Juan Lang : cryptui: Ensure a certificate' s private key is exportable before allowing it to be selected for export.

Alexandre Julliard julliard at winehq.org
Mon Feb 9 10:29:21 CST 2009


Module: wine
Branch: master
Commit: af87814ac6552a2358e9df4a439bea765b4305be
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=af87814ac6552a2358e9df4a439bea765b4305be

Author: Juan Lang <juan.lang at gmail.com>
Date:   Fri Feb  6 12:05:30 2009 -0800

cryptui: Ensure a certificate's private key is exportable before allowing it to be selected for export.

---

 dlls/cryptui/cryptui_En.rc |    3 ++
 dlls/cryptui/cryptuires.h  |    7 +++-
 dlls/cryptui/main.c        |   87 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 95 insertions(+), 2 deletions(-)

diff --git a/dlls/cryptui/cryptui_En.rc b/dlls/cryptui/cryptui_En.rc
index 8cabea4..c6d6559 100644
--- a/dlls/cryptui/cryptui_En.rc
+++ b/dlls/cryptui/cryptui_En.rc
@@ -166,6 +166,8 @@ STRINGTABLE DISCARDABLE
     IDS_EXPORT_PASSWORD_TITLE "Enter Password"
     IDS_EXPORT_PASSWORD_SUBTITLE "You may password-protect a private key."
     IDS_EXPORT_PASSWORD_MISMATCH "The passwords do not match."
+    IDS_EXPORT_PRIVATE_KEY_UNAVAILABLE "Note: The private key for this certificate could not be opened."
+    IDS_EXPORT_PRIVATE_KEY_NON_EXPORTABLE "Note: The private  key for this certificate is not exportable."
 }
 
 IDD_GENERAL DIALOG DISCARDABLE 0, 0, 255, 236
@@ -396,6 +398,7 @@ BEGIN
     IDC_EXPORT_PRIVATE_KEY_YES, 31,36,200,12, BS_AUTORADIOBUTTON|WS_TABSTOP
   AUTORADIOBUTTON "N&o, do not export the private key",
     IDC_EXPORT_PRIVATE_KEY_NO, 31,48,200,12, BS_AUTORADIOBUTTON
+  LTEXT "", IDC_EXPORT_PRIVATE_KEY_UNAVAILABLE, 21,60,200,24
 END
 
 IDD_EXPORT_PASSWORD DIALOG DISCARDABLE 0,0,317,143
diff --git a/dlls/cryptui/cryptuires.h b/dlls/cryptui/cryptuires.h
index e16bb21..b46ea4e 100644
--- a/dlls/cryptui/cryptuires.h
+++ b/dlls/cryptui/cryptuires.h
@@ -165,6 +165,8 @@
 #define IDS_EXPORT_PASSWORD_TITLE 1222
 #define IDS_EXPORT_PASSWORD_SUBTITLE 1223
 #define IDS_EXPORT_PASSWORD_MISMATCH 1224
+#define IDS_EXPORT_PRIVATE_KEY_UNAVAILABLE 1225
+#define IDS_EXPORT_PRIVATE_KEY_NON_EXPORTABLE 1226
 
 #define IDD_GENERAL 100
 #define IDD_DETAIL 101
@@ -262,7 +264,8 @@
 #define IDC_EXPORT_SETTINGS 2911
 #define IDC_EXPORT_PRIVATE_KEY_YES 2912
 #define IDC_EXPORT_PRIVATE_KEY_NO 2913
-#define IDC_EXPORT_PASSWORD 2914
-#define IDC_EXPORT_PASSWORD_CONFIRM 2915
+#define IDC_EXPORT_PRIVATE_KEY_UNAVAILABLE 2914
+#define IDC_EXPORT_PASSWORD 2915
+#define IDC_EXPORT_PASSWORD_CONFIRM 2916
 
 #endif /* ndef __CRYPTUIRES_H_ */
diff --git a/dlls/cryptui/main.c b/dlls/cryptui/main.c
index 677bee4..620f53f 100644
--- a/dlls/cryptui/main.c
+++ b/dlls/cryptui/main.c
@@ -5518,6 +5518,7 @@ struct ExportWizData
     CRYPTUI_WIZ_EXPORT_INFO exportInfo;
     CRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO contextInfo;
     BOOL freePassword;
+    PCRYPT_KEY_PROV_INFO keyProvInfo;
     LPWSTR fileName;
     HANDLE file;
     BOOL success;
@@ -5567,6 +5568,63 @@ static LRESULT CALLBACK export_welcome_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
     return ret;
 }
 
+static PCRYPT_KEY_PROV_INFO export_get_private_key_info(PCCERT_CONTEXT cert)
+{
+    PCRYPT_KEY_PROV_INFO info = NULL;
+    DWORD size;
+
+    if (CertGetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID,
+     NULL, &size))
+    {
+        info = HeapAlloc(GetProcessHeap(), 0, size);
+        if (info)
+        {
+            if (!CertGetCertificateContextProperty(cert,
+             CERT_KEY_PROV_INFO_PROP_ID, info, &size))
+            {
+                HeapFree(GetProcessHeap(), 0, info);
+                info = NULL;
+            }
+        }
+    }
+    return info;
+}
+
+static BOOL export_acquire_private_key(PCRYPT_KEY_PROV_INFO info,
+ HCRYPTPROV *phProv)
+{
+    BOOL ret;
+
+    ret = CryptAcquireContextW(phProv, info->pwszContainerName,
+     info->pwszProvName, info->dwProvType, 0);
+    if (ret)
+    {
+        DWORD i;
+
+        for (i = 0; i < info->cProvParam; i++)
+            CryptSetProvParam(*phProv, info->rgProvParam[i].dwParam,
+             info->rgProvParam[i].pbData, info->rgProvParam[i].dwFlags);
+    }
+    return ret;
+}
+
+static BOOL export_is_key_exportable(HCRYPTPROV hProv, DWORD keySpec)
+{
+    BOOL ret;
+    HCRYPTKEY key;
+
+    if ((ret = CryptGetUserKey(hProv, keySpec, &key)))
+    {
+        DWORD permissions, size = sizeof(permissions);
+
+        if ((ret = CryptGetKeyParam(key, KP_PERMISSIONS, (BYTE *)&permissions,
+         &size, 0)) && !(permissions & CRYPT_EXPORT))
+            ret = FALSE;
+        CryptDestroyKey(key);
+    }
+    return ret;
+}
+
 static LRESULT CALLBACK export_private_key_dlg_proc(HWND hwnd, UINT msg,
  WPARAM wp, LPARAM lp)
 {
@@ -5578,9 +5636,36 @@ static LRESULT CALLBACK export_private_key_dlg_proc(HWND hwnd, UINT msg,
     case WM_INITDIALOG:
     {
         PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
+        PCRYPT_KEY_PROV_INFO info;
+        HCRYPTPROV hProv = 0;
+        int errorID = 0;
 
         data = (struct ExportWizData *)page->lParam;
         SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
+        /* Get enough information about a key to see whether it's exportable.
+         */
+        if (!(info = export_get_private_key_info(
+         data->exportInfo.u.pCertContext)))
+            errorID = IDS_EXPORT_PRIVATE_KEY_UNAVAILABLE;
+        else if (!export_acquire_private_key(info, &hProv))
+            errorID = IDS_EXPORT_PRIVATE_KEY_UNAVAILABLE;
+        else if (!export_is_key_exportable(hProv, info->dwKeySpec))
+            errorID = IDS_EXPORT_PRIVATE_KEY_NON_EXPORTABLE;
+
+        if (errorID)
+        {
+            WCHAR error[MAX_STRING_LEN];
+
+            LoadStringW(hInstance, errorID, error,
+             sizeof(error) / sizeof(error[0]));
+            SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_PRIVATE_KEY_UNAVAILABLE),
+             WM_SETTEXT, 0, (LPARAM)error);
+            EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_PRIVATE_KEY_YES), FALSE);
+        }
+        else
+            data->keyProvInfo = info;
+        if (hProv)
+            CryptReleaseContext(hProv, 0);
         SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_PRIVATE_KEY_NO), BM_CLICK,
          0, 0);
         break;
@@ -6671,6 +6756,7 @@ static BOOL show_export_ui(DWORD dwFlags, HWND hwndParent,
         memcpy(&data.contextInfo, pvoid,
          min(((PCCRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO)pvoid)->dwSize,
          sizeof(data.contextInfo)));
+    data.keyProvInfo = NULL;
     data.fileName = NULL;
     data.file = INVALID_HANDLE_VALUE;
     data.success = FALSE;
@@ -6785,6 +6871,7 @@ static BOOL show_export_ui(DWORD dwFlags, HWND hwndParent,
     if (data.freePassword)
         HeapFree(GetProcessHeap(), 0,
          (LPWSTR)data.contextInfo.pwszPassword);
+    HeapFree(GetProcessHeap(), 0, data.keyProvInfo);
     CloseHandle(data.file);
     HeapFree(GetProcessHeap(), 0, data.fileName);
     if (l == 0)




More information about the wine-cvs mailing list