[ros-diffs] [dchapyshev] 39760: - Sync crypt32 and cryptui with Wine head

dchapyshev at svn.reactos.org dchapyshev at svn.reactos.org
Thu Feb 26 11:22:00 CET 2009


Author: dchapyshev
Date: Thu Feb 26 13:21:59 2009
New Revision: 39760

URL: http://svn.reactos.org/svn/reactos?rev=39760&view=rev
Log:
- Sync crypt32 and cryptui with Wine head

Modified:
    trunk/reactos/dll/win32/crypt32/chain.c
    trunk/reactos/dll/win32/crypt32/crypt32_Ko.rc
    trunk/reactos/dll/win32/cryptui/cryptui_En.rc
    trunk/reactos/dll/win32/cryptui/cryptui_Ko.rc
    trunk/reactos/dll/win32/cryptui/cryptuires.h
    trunk/reactos/dll/win32/cryptui/main.c

Modified: trunk/reactos/dll/win32/crypt32/chain.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/crypt32/chain.c?rev=39760&r1=39759&r2=39760&view=diff
==============================================================================
--- trunk/reactos/dll/win32/crypt32/chain.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/crypt32/chain.c [iso-8859-1] Thu Feb 26 13:21:59 2009
@@ -28,6 +28,7 @@
 #include "crypt32_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
+WINE_DECLARE_DEBUG_CHANNEL(chain);
 
 #define DEFAULT_CYCLE_MODULUS 7
 
@@ -355,7 +356,7 @@
      CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, (void *)root,
      CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, (void *)root, 0, NULL))
     {
-        TRACE("Last certificate's signature is invalid\n");
+        TRACE_(chain)("Last certificate's signature is invalid\n");
         rootElement->TrustStatus.dwErrorStatus |=
          CERT_TRUST_IS_NOT_SIGNATURE_VALID;
     }
@@ -411,8 +412,12 @@
 }
 
 /* Checks element's basic constraints to see if it can act as a CA, with
- * remainingCAs CAs left in this chain.  Updates chainConstraints with the
- * element's constraints, if:
+ * remainingCAs CAs left in this chain.  A root certificate is assumed to be
+ * allowed to be a CA whether or not the basic constraints extension is present,
+ * whereas an intermediate CA cert is not.  This matches the expected usage in
+ * RFC 3280:  a conforming intermediate CA MUST contain the basic constraints
+ * extension.  It also appears to match Microsoft's implementation.
+ * Updates chainConstraints with the element's constraints, if:
  * 1. chainConstraints doesn't have a path length constraint, or
  * 2. element's path length constraint is smaller than chainConstraints's
  * Sets *pathLengthConstraintViolated to TRUE if a path length violation
@@ -422,17 +427,17 @@
  */
 static BOOL CRYPT_CheckBasicConstraintsForCA(PCCERT_CONTEXT cert,
  CERT_BASIC_CONSTRAINTS2_INFO *chainConstraints, DWORD remainingCAs,
- BOOL *pathLengthConstraintViolated)
+ BOOL isRoot, BOOL *pathLengthConstraintViolated)
 {
     BOOL validBasicConstraints;
     CERT_BASIC_CONSTRAINTS2_INFO constraints;
 
     if ((validBasicConstraints = CRYPT_DecodeBasicConstraints(cert,
-     &constraints, TRUE)))
+     &constraints, isRoot)))
     {
         if (!constraints.fCA)
         {
-            TRACE("chain element %d can't be a CA\n", remainingCAs + 1);
+            TRACE_(chain)("chain element %d can't be a CA\n", remainingCAs + 1);
             validBasicConstraints = FALSE;
         }
         else if (constraints.fPathLenConstraint)
@@ -444,7 +449,7 @@
              constraints.dwPathLenConstraint <
              chainConstraints->dwPathLenConstraint)
             {
-                TRACE("setting path length constraint to %d\n",
+                TRACE_(chain)("setting path length constraint to %d\n",
                  chainConstraints->dwPathLenConstraint);
                 chainConstraints->fPathLenConstraint = TRUE;
                 chainConstraints->dwPathLenConstraint =
@@ -455,8 +460,8 @@
     if (chainConstraints->fPathLenConstraint &&
      remainingCAs > chainConstraints->dwPathLenConstraint)
     {
-        TRACE("remaining CAs %d exceed max path length %d\n", remainingCAs,
-         chainConstraints->dwPathLenConstraint);
+        TRACE_(chain)("remaining CAs %d exceed max path length %d\n",
+         remainingCAs, chainConstraints->dwPathLenConstraint);
         validBasicConstraints = FALSE;
         *pathLengthConstraintViolated = TRUE;
     }
@@ -709,6 +714,100 @@
     }
 }
 
+static void dump_basic_constraints(PCERT_EXTENSION ext)
+{
+    CERT_BASIC_CONSTRAINTS_INFO *info;
+    DWORD size = 0;
+
+    if (CryptDecodeObjectEx(X509_ASN_ENCODING, szOID_BASIC_CONSTRAINTS,
+     ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG,
+     NULL, &info, &size))
+    {
+        TRACE_(chain)("SubjectType: %02x\n", info->SubjectType.pbData[0]);
+        TRACE_(chain)("%s path length constraint\n",
+         info->fPathLenConstraint ? "has" : "doesn't have");
+        TRACE_(chain)("path length=%d\n", info->dwPathLenConstraint);
+        LocalFree(info);
+    }
+}
+
+static void dump_basic_constraints2(PCERT_EXTENSION ext)
+{
+    CERT_BASIC_CONSTRAINTS2_INFO constraints;
+    DWORD size = sizeof(CERT_BASIC_CONSTRAINTS2_INFO);
+
+    if (CryptDecodeObjectEx(X509_ASN_ENCODING,
+     szOID_BASIC_CONSTRAINTS2, ext->Value.pbData, ext->Value.cbData,
+     0, NULL, &constraints, &size))
+    {
+        TRACE_(chain)("basic constraints:\n");
+        TRACE_(chain)("can%s be a CA\n", constraints.fCA ? "" : "not");
+        TRACE_(chain)("%s path length constraint\n",
+         constraints.fPathLenConstraint ? "has" : "doesn't have");
+        TRACE_(chain)("path length=%d\n", constraints.dwPathLenConstraint);
+    }
+}
+
+static void dump_extension(PCERT_EXTENSION ext)
+{
+    TRACE_(chain)("%s (%scritical)\n", debugstr_a(ext->pszObjId),
+     ext->fCritical ? "" : "not ");
+    if (!strcmp(ext->pszObjId, szOID_BASIC_CONSTRAINTS))
+        dump_basic_constraints(ext);
+    else if (!strcmp(ext->pszObjId, szOID_BASIC_CONSTRAINTS2))
+        dump_basic_constraints2(ext);
+}
+
+static LPCWSTR filetime_to_str(const FILETIME *time)
+{
+    static WCHAR date[80];
+    WCHAR dateFmt[80]; /* sufficient for all versions of LOCALE_SSHORTDATE */
+    SYSTEMTIME sysTime;
+
+    if (!time) return NULL;
+
+    GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SSHORTDATE, dateFmt,
+     sizeof(dateFmt) / sizeof(dateFmt[0]));
+    FileTimeToSystemTime(time, &sysTime);
+    GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, date,
+     sizeof(date) / sizeof(date[0]));
+    return date;
+}
+
+static void dump_element(PCCERT_CONTEXT cert)
+{
+    LPWSTR name = NULL;
+    DWORD len, i;
+
+    TRACE_(chain)("%p\n", cert);
+    len = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
+     CERT_NAME_ISSUER_FLAG, NULL, NULL, 0);
+    name = CryptMemAlloc(len * sizeof(WCHAR));
+    if (name)
+    {
+        CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
+         CERT_NAME_ISSUER_FLAG, NULL, name, len);
+        TRACE_(chain)("issued by %s\n", debugstr_w(name));
+        CryptMemFree(name);
+    }
+    len = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL,
+     NULL, 0);
+    name = CryptMemAlloc(len * sizeof(WCHAR));
+    if (name)
+    {
+        CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL,
+         name, len);
+        TRACE_(chain)("issued to %s\n", debugstr_w(name));
+        CryptMemFree(name);
+    }
+    TRACE_(chain)("valid from %s to %s\n",
+     debugstr_w(filetime_to_str(&cert->pCertInfo->NotBefore)),
+     debugstr_w(filetime_to_str(&cert->pCertInfo->NotAfter)));
+    TRACE_(chain)("%d extensions\n", cert->pCertInfo->cExtension);
+    for (i = 0; i < cert->pCertInfo->cExtension; i++)
+        dump_extension(&cert->pCertInfo->rgExtension[i]);
+}
+
 static void CRYPT_CheckSimpleChain(PCertificateChainEngine engine,
  PCERT_SIMPLE_CHAIN chain, LPFILETIME time)
 {
@@ -717,14 +816,25 @@
     BOOL pathLengthConstraintViolated = FALSE;
     CERT_BASIC_CONSTRAINTS2_INFO constraints = { TRUE, FALSE, 0 };
 
+    TRACE_(chain)("checking chain with %d elements for time %s\n",
+     chain->cElement, debugstr_w(filetime_to_str(time)));
     for (i = chain->cElement - 1; i >= 0; i--)
     {
+        if (TRACE_ON(chain))
+            dump_element(chain->rgpElement[i]->pCertContext);
         if (CertVerifyTimeValidity(time,
          chain->rgpElement[i]->pCertContext->pCertInfo) != 0)
             chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
              CERT_TRUST_IS_NOT_TIME_VALID;
         if (i != 0)
         {
+            BOOL isRoot;
+
+            if (i == chain->cElement - 1)
+                isRoot = CRYPT_IsCertificateSelfSigned(
+                 chain->rgpElement[i]->pCertContext);
+            else
+                isRoot = FALSE;
             /* Check the signature of the cert this issued */
             if (!CryptVerifyCertificateSignatureEx(0, X509_ASN_ENCODING,
              CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT,
@@ -741,7 +851,7 @@
                  CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
             else if (!CRYPT_CheckBasicConstraintsForCA(
              chain->rgpElement[i]->pCertContext, &constraints, i - 1,
-             &pathLengthConstraintViolated))
+             isRoot, &pathLengthConstraintViolated))
                 chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
                  CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
             else if (constraints.fPathLenConstraint &&
@@ -884,8 +994,7 @@
         issuer = CertFindCertificateInStore(store,
          subject->dwCertEncodingType, 0, CERT_FIND_SUBJECT_NAME,
          &subject->pCertInfo->Issuer, prevIssuer);
-        if (issuer)
-            *infoStatus = CERT_TRUST_HAS_NAME_MATCH_ISSUER;
+        *infoStatus = CERT_TRUST_HAS_NAME_MATCH_ISSUER;
     }
     return issuer;
 }
@@ -902,12 +1011,13 @@
     while (ret && !CRYPT_IsSimpleChainCyclic(chain) &&
      !CRYPT_IsCertificateSelfSigned(cert))
     {
-        DWORD infoStatus;
-        PCCERT_CONTEXT issuer = CRYPT_GetIssuer(world, cert, NULL, &infoStatus);
+        PCCERT_CONTEXT issuer = CRYPT_GetIssuer(world, cert, NULL,
+         &chain->rgpElement[chain->cElement - 1]->TrustStatus.dwInfoStatus);
 
         if (issuer)
         {
-            ret = CRYPT_AddCertToSimpleChain(engine, chain, issuer, infoStatus);
+            ret = CRYPT_AddCertToSimpleChain(engine, chain, issuer,
+             chain->rgpElement[chain->cElement - 1]->TrustStatus.dwInfoStatus);
             /* CRYPT_AddCertToSimpleChain add-ref's the issuer, so free it to
              * close the enumeration that found it
              */
@@ -916,7 +1026,7 @@
         }
         else
         {
-            TRACE("Couldn't find issuer, halting chain creation\n");
+            TRACE_(chain)("Couldn't find issuer, halting chain creation\n");
             chain->TrustStatus.dwErrorStatus |= CERT_TRUST_IS_PARTIAL_CHAIN;
             break;
         }

Modified: trunk/reactos/dll/win32/crypt32/crypt32_Ko.rc
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/crypt32/crypt32_Ko.rc?rev=39760&r1=39759&r2=39760&view=diff
==============================================================================
--- trunk/reactos/dll/win32/crypt32/crypt32_Ko.rc [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/crypt32/crypt32_Ko.rc [iso-8859-1] Thu Feb 26 13:21:59 2009
@@ -172,6 +172,7 @@
     IDS_LOCALIZEDNAME_MY "°³ÀÎ"
     IDS_LOCALIZEDNAME_CA "Áß°³ °ËÁõ ±â°ü"
     IDS_LOCALIZEDNAME_ADDRESSBOOK "´Ù¸¥ »ç¶÷"
+    IDS_LOCALIZEDNAME_TRUSTEDPUBLISHER "½Å·ÚÇÒ ¼ö ÀÖ´Â ¹ßÇàÀÚ"
 }
 
 STRINGTABLE DISCARDABLE

Modified: trunk/reactos/dll/win32/cryptui/cryptui_En.rc
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/cryptui/cryptui_En.rc?rev=39760&r1=39759&r2=39760&view=diff
==============================================================================
--- trunk/reactos/dll/win32/cryptui/cryptui_En.rc [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/cryptui/cryptui_En.rc [iso-8859-1] Thu Feb 26 13:21:59 2009
@@ -102,8 +102,8 @@
     IDS_FRIENDLY_NAME_COLUMN "Friendly Name"
     IDS_ALLOWED_PURPOSE_ALL "<All>"
     IDS_ALLOWED_PURPOSE_NONE "<None>"
-    IDS_WARN_REMOVE_MY "You will no longer be able to decrypt mesages with this certificate, or sign messages with it.\nAre you sure you want to remove this certificate?"
-    IDS_WARN_REMOVE_PLURAL_MY "You will no longer be able to decrypt mesages with these certificate, or sign messages with them.\nAre you sure you want to remove these certificates?"
+    IDS_WARN_REMOVE_MY "You will no longer be able to decrypt messages with this certificate, or sign messages with it.\nAre you sure you want to remove this certificate?"
+    IDS_WARN_REMOVE_PLURAL_MY "You will no longer be able to decrypt messages with these certificates, or sign messages with them.\nAre you sure you want to remove these certificates?"
     IDS_WARN_REMOVE_ADDRESSBOOK "You will no longer be able to encrypt messages with this certificate, or verify messages signed with it.\nAre you sure you want to remove this certificate?"
     IDS_WARN_REMOVE_PLURAL_ADDRESSBOOK "You will no longer be able to encrypt messages with these certificates, or verify messages signed with it.\nAre you sure you want to remove these certificates?"
     IDS_WARN_REMOVE_CA "Certificates issued by this certification authority will no longer be trusted.\nAre you sure you want to remove this certificate?"
@@ -161,6 +161,13 @@
     IDS_NO "No"
     IDS_EXPORT_SUCCEEDED "The export was successful."
     IDS_EXPORT_FAILED "The export failed."
+    IDS_EXPORT_PRIVATE_KEY_TITLE "Export Private Key"
+    IDS_EXPORT_PRIVATE_KEY_SUBTITLE "The certificate contains a private key which may be exported along with the certificate."
+    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
@@ -379,6 +386,29 @@
     -1, 115,56,195,40
   LTEXT "To continue, click Next.",
     -1, 115,103,195,8
+END
+
+IDD_EXPORT_PRIVATE_KEY DIALOG DISCARDABLE 0,0,317,143
+CAPTION "Certificate Export Wizard"
+FONT 8, "MS Shell Dlg"
+BEGIN
+  LTEXT "If you choose to export the private key, you will be prompted for a password to protect the private key on a later page.", -1, 21,1,195,23
+  LTEXT "Do you wish to export the private key?", -1, 21,24,195,15
+  AUTORADIOBUTTON "&Yes, export the private key",
+    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
+CAPTION "Certificate Export Wizard"
+FONT 8, "MS Shell Dlg"
+BEGIN
+  LTEXT "&Password:", -1, 21,1,195,10
+  EDITTEXT IDC_EXPORT_PASSWORD, 21,11,208,14, ES_AUTOHSCROLL|WS_TABSTOP
+  LTEXT "&Confirm password:", -1, 21,35,195,10
+  EDITTEXT IDC_EXPORT_PASSWORD_CONFIRM, 21,45,208,14, ES_AUTOHSCROLL|WS_TABSTOP
 END
 
 IDD_EXPORT_FORMAT DIALOG DISCARDABLE 0,0,317,143

Modified: trunk/reactos/dll/win32/cryptui/cryptui_Ko.rc
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/cryptui/cryptui_Ko.rc?rev=39760&r1=39759&r2=39760&view=diff
==============================================================================
--- trunk/reactos/dll/win32/cryptui/cryptui_Ko.rc [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/cryptui/cryptui_Ko.rc [iso-8859-1] Thu Feb 26 13:21:59 2009
@@ -143,6 +143,34 @@
     IDS_PURPOSE_CA_EXCHANGE "»çÀû Å° º¸°ü¼Ò"
     IDS_PURPOSE_KEY_RECOVERY_AGENT "Å° º¹±¸ ¿¡ÀÌÀüÆ®"
     IDS_PURPOSE_DS_EMAIL_REPLICATION "µð·ºÅ丮 ¼­ºñ½º ÀüÀÚ¿ìÆí º¹Á¦"
+    IDS_EXPORT_WIZARD "ÀÎÁõ¼­ ³»º¸³»±â ¸¶¹ý»ç"
+    IDS_EXPORT_FORMAT_TITLE "³»º¸³¾ Çü½Ä"
+    IDS_EXPORT_FORMAT_SUBTITLE "³»¿ëÀ» ÀúÀåÇÒ Çü½Ä ¼±ÅÃ."
+    IDS_EXPORT_FILE_TITLE "³»º¸³¾ ÆÄÀÏÀ̸§"
+    IDS_EXPORT_FILE_SUBTITLE "³»¿ëÀ» ÀúÀåÇÒ ÆÄÀÏ À̸§ ÁöÁ¤."
+    IDS_EXPORT_FILE_EXISTS "ÁöÁ¤µÈ ÆÄÀÏÀº ÀÌ¹Ì Á¸ÀçÇÕ´Ï´Ù.µ¤¾î ¾²½Ã°Ú½À´Ï±î?"
+    IDS_EXPORT_FILTER_CERT "DER-¾ÏȣȭµÈ ¹ÙÀ̳ʸ® X.509 (*.cer)"
+    IDS_EXPORT_FILTER_BASE64_CERT "Base64-¾ÏȣȭµÈ X.509 (*.cer)"
+    IDS_EXPORT_FILTER_CRL "ÀÎÁõ¼­ Æó±â ¸ñ·Ï (*.crl)"
+    IDS_EXPORT_FILTER_CTL "ÀÎÁõ¼­ ½Å·Ú ¸ñ·Ï (*.stl)"
+    IDS_EXPORT_FILTER_CMS "CMS/PKCS #7 ¸Þ¼¼Áö (*.p7b)"
+    IDS_EXPORT_FILTER_PFX "°³ÀÎ Á¤º¸ ±³È¯ (*.pfx)"
+    IDS_EXPORT_FILTER_SERIALIZED_CERT_STORE "³ª¿­µÈ ÀÎÁõ¼­ ÀúÀå¼Ò (*.sst)"
+    IDS_EXPORT_FORMAT "ÆÄÀÏ Çü½Ä"
+    IDS_EXPORT_INCLUDE_CHAIN "ÀÎÁõ °æ·Î¿¡ ÀÖ´Â ¸ðµç ÀÎÁõ¼­ Æ÷ÇÔ"
+    IDS_EXPORT_KEYS "³»º¸³¾ Å°"
+    IDS_YES "¿¹"
+    IDS_NO "¾Æ´Ï¿À"
+    IDS_EXPORT_SUCCEEDED "³»º¸³»±â ¼º°ø."
+    IDS_EXPORT_FAILED "³»º¸³»±â ½ÇÆÐ."
+    IDS_EXPORT_PRIVATE_KEY_TITLE "³»º¸³¾ °³ÀÎ Å°"
+    IDS_EXPORT_PRIVATE_KEY_SUBTITLE "ÀÌ ÀÎÁõ¼­´Â  ÀÎÁõ¼­¸¦ ³»º¸³¾ ¶§ °°ÀÌ ³ª°¥ °³ÀÎÅ°¸¦ Æ÷ÇÔÇÏ°í ÀÖ½À´Ï´Ù."
+    IDS_EXPORT_PASSWORD_TITLE "¾ÏÈ£ ÀÔ·Â"
+    IDS_EXPORT_PASSWORD_SUBTITLE "ÀÌ °³ÀÎÅ°´Â ¾Æ¸¶µµ ¾ÏÈ£·Î º¸È£µÇ¾îÀÖ´Â °Í °°½À´Ï´Ù."
+    IDS_EXPORT_PASSWORD_MISMATCH "ÀÌ ¾ÏÈ£´Â ¸ÂÁö ¾Ê½À´Ï´Ù."
+    IDS_EXPORT_PRIVATE_KEY_UNAVAILABLE "ÁÖÀÇ: ÀÌ ÀÎÁõ¼­¸¦ À§ÇÑ °³ÀÎ Å°¸¦ ¿­ ¼ö ¾ø½À´Ï´Ù."
+    IDS_EXPORT_PRIVATE_KEY_NON_EXPORTABLE "ÁÖÀÇ: ÀÌ ÀÎÁõ¼­¸¦ À§ÇÑ °³ÀÎ Å°¸¦ ³»º¸³¾ ¼ö ¾ø½À´Ï´Ù."
+
 }
 
 IDD_GENERAL DIALOG DISCARDABLE 0, 0, 255, 236
@@ -330,3 +358,90 @@
   PUSHBUTTON "È®ÀÎ", IDOK, 132,155,51,14, BS_DEFPUSHBUTTON
   PUSHBUTTON "Ãë¼Ò", IDCANCEL, 190,155,51,14
 END
+
+
+IDD_EXPORT_WELCOME DIALOG DISCARDABLE 0,0,317,143
+CAPTION "ÀÎÁõ¼­ ³»º¸³»±â ¸¶¹ý»ç"
+FONT 8, "MS Shell Dlg"
+BEGIN
+  LTEXT "ÀÎÁõ¼­ ³»º¸³»±â ¸¶¹ý»ç¿¡ ¿À½Å °ÍÀ» ȯ¿µÇÕ´Ï´Ù", IDC_EXPORT_TITLE,
+    115,1,195,40
+  LTEXT "ÀÌ ¸¶¹ý»ç´Â ÀÎÁõ¼­,ÀÎÁõ¼­ Æó±â ¸ñ·Ï,ÀÎÁõ¼­ ½Å·Ú ¸ñ·ÏÀ» ÀÎÁõ¼­ ÀúÀå¼Ò·ÎºÎÅÍ ÆÄÀÏ·Î ³»º¸³»´Â °ÍÀ» µµ¿ÍÁÙ°Ì´Ï´Ù.",
+    -1, 115,33,195,16
+  LTEXT " ÀÎÁõ¼­´Â ´ç½ÅÀ̳ª ´ç½ÅÀÌ Åë½Å¿¡ »ç¿ëÇÏ´Â ÄÄÇ»Å͸¦ ½Å¿øº¸ÁõÇÏ´Â µ¥ »ç¿ëµË´Ï´Ù.  ¶ÇÇÑ  ¸Þ¼¼Áö¿¡ »çÀÎÇÏ°í ÀÎÁõÇÏ´Â µ¥µµ »ç¿ëµË´Ï´Ù. ÀÎÁõ¼­ º¸°ü¼Ò´Â ÀÎÁõ¼­, ÀÎÁõ¼­ Æı⠸ñ·Ï, ÀÎÁõ¼­ ½Å·Ú ¸ñ·ÏÀÇ ÀúÀå¼ÒÀÔ´Ï´Ù..",
+    -1, 115,56,195,40
+  LTEXT "°è¼Ó ÇϽǷÁ¸é, <´ÙÀ½>À» Ŭ¸¯ÇϽʽÿÀ.",
+    -1, 115,103,195,8
+END
+
+IDD_EXPORT_PRIVATE_KEY DIALOG DISCARDABLE 0,0,317,143
+CAPTION "ÀÎÁõ¼­ ³»º¸³»±â ¸¶¹ý»ç"
+FONT 8, "MS Shell Dlg"
+BEGIN
+	LTEXT "´ç½ÅÀÌ  °³ÀÎ Å°¸¦ ³»º¸³»±â¸¦ ¼±ÅÃÇϸé, ´ç½ÅÀº ´ÙÀ½ ÆäÀÌÁö¿¡¼­ °³ÀÎ Å°¸¦ º¸È£ÇÒ ¾ÏÈ£¸¦ ÀÔ·ÂÇÏ°Ô µÉ °ÍÀÔ´Ï´Ù.", -1, 21,1,195,23
+	LTEXT "°³ÀÎ Å°¸¦ ³»º¸³»±â¸¦ ¿øÇմϱî?", -1, 21,24,195,15
+	AUTORADIOBUTTON "¿¹(&Y), °³ÀÎ Å° ³»º¸³»±â",
+	IDC_EXPORT_PRIVATE_KEY_YES, 31,36,200,12, BS_AUTORADIOBUTTON|WS_TABSTOP
+	AUTORADIOBUTTON "¾Æ´Ï¿À(&O), °³ÀÎ Å° ¾È ³»º¸³»±â",
+	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
+CAPTION "ÀÎÁõ¼­ ³»º¸³»±â ¸¶¹ý»ç"
+FONT 8, "MS Shell Dlg"
+BEGIN
+LTEXT "¾ÏÈ£(&P):", -1, 21,1,195,10
+EDITTEXT IDC_EXPORT_PASSWORD, 21,11,208,14, ES_AUTOHSCROLL|WS_TABSTOP
+LTEXT "¾ÏÈ£ È®ÀÎ(&C):", -1, 21,35,195,10
+EDITTEXT IDC_EXPORT_PASSWORD_CONFIRM, 21,45,208,14, ES_AUTOHSCROLL|WS_TABSTOP
+END
+
+IDD_EXPORT_FORMAT DIALOG DISCARDABLE 0,0,317,143
+CAPTION "ÀÎÁõ¼­ ³»º¸³»±â ¸¶¹ý»ç"
+FONT 8, "MS Shell Dlg"
+BEGIN
+  LTEXT "»ç¿ëÇÒ ÆÄÀÏ Çü½Ä ¼±ÅÃ:", -1, 21,1,195,10
+  AUTORADIOBUTTON "&DER-¾ÏȣȭµÈ X.509 (.cer)",
+    IDC_EXPORT_FORMAT_DER, 31,18,200,12, BS_AUTORADIOBUTTON|WS_TABSTOP
+  AUTORADIOBUTTON "Ba&se64-¾ÏȣȭµÈ X.509 (.cer):",
+    IDC_EXPORT_FORMAT_BASE64, 31,30,200,12, BS_AUTORADIOBUTTON
+  AUTORADIOBUTTON "¾ÏÈ£ ¸Þ½ÃÁö ¹®¹ý Ç¥ÁØ/PKCS #7 ¸Þ½ÃÁö(&C) (.p7b)",
+    IDC_EXPORT_FORMAT_CMS, 31,42,200,12, BS_AUTORADIOBUTTON
+  CHECKBOX "°¡´ÉÇÑ ÀÎÁõ¼­ °æ·Î¿¡ ÀÖ´Â ¸ðµç ÀÎÁõ¼­ Æ÷ÇÔ(&I)",
+    IDC_EXPORT_CMS_INCLUDE_CHAIN, 44,57,200,8, BS_AUTOCHECKBOX|WS_TABSTOP|WS_DISABLED
+  AUTORADIOBUTTON "°³ÀÎ Á¤º¸ ±³È¯(&P)/PKCS #12 (.pfx)",
+    IDC_EXPORT_FORMAT_PFX, 31,72,200,12, BS_AUTORADIOBUTTON|WS_DISABLED
+  CHECKBOX "°¡´ÉÇÑ ÀÎÁõ¼­ °æ·Î¿¡ ÀÖ´Â ¸ðµç ÀÎÁõ¼­ Æ÷ÇÔ(&U)",
+    IDC_EXPORT_PFX_INCLUDE_CHAIN, 44,87,200,8, BS_AUTOCHECKBOX|WS_TABSTOP|WS_DISABLED
+  CHECKBOX "°­ÇÑ ¾Ïȣȭ °¡´É(&E)",
+    IDC_EXPORT_PFX_STRONG_ENCRYPTION, 44,102,200,8,
+    BS_AUTOCHECKBOX|WS_TABSTOP|WS_DISABLED
+  CHECKBOX "³»º¸³»±â°¡ ¼º°øÇÏ¸é °³ÀÎ Å° Áö¿ì±â(&K)",
+    IDC_EXPORT_PFX_DELETE_PRIVATE_KEY, 44,117,200,8,
+    BS_AUTOCHECKBOX|WS_TABSTOP|WS_DISABLED
+END
+
+IDD_EXPORT_FILE DIALOG DISCARDABLE 0,0,317,143
+CAPTION "ÀÎÁõ¼­ ³»º¸³»±â ¸¶¹ý»ç"
+FONT 8, "MS Shell Dlg"
+BEGIN
+  LTEXT "ÆÄÀÏ À̸§(&F):", -1, 21,1,195,10
+  EDITTEXT IDC_EXPORT_FILENAME, 21,11,208,14, ES_AUTOHSCROLL|WS_TABSTOP
+  PUSHBUTTON "ã±â(&R)...", IDC_EXPORT_BROWSE_FILE, 236,11,60,14
+END
+
+IDD_EXPORT_FINISH DIALOG DISCARDABLE 0,0,317,143
+CAPTION "ÀÎÁõ¼­ ³»º¸³»±â ¸¶¹ý»ç"
+FONT 8, "MS Shell Dlg"
+BEGIN
+  LTEXT "ÀÎÁõ¼­ ³»º¸³»±â ¸¶¹ý¼­ ¿Ï·áÇÏ´Â Áß", IDC_EXPORT_TITLE,
+    115,1,195,40
+  LTEXT "´ç½ÅÀº ÀÎÁõ¼­ ³»º¸³»±â ¸¶¹ý¸¦ ¿Ï·áÇÏ´Â µ¥ ¼º°øÇÏ¿´½À´Ï´Ù.",
+    -1, 115,33,195,24
+  LTEXT "´ç½ÅÀº ´ÙÀ½ ¼³Á¤À» ÁöÁ¤Çß½À´Ï´Ù:",
+    -1, 115,57,195,12
+  CONTROL "", IDC_EXPORT_SETTINGS, "SysListView32",
+    LVS_REPORT|LVS_NOCOLUMNHEADER|LVS_SINGLESEL|WS_CHILD|WS_VISIBLE|WS_TABSTOP|WS_BORDER,
+    115,67,174,100
+END

Modified: trunk/reactos/dll/win32/cryptui/cryptuires.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/cryptui/cryptuires.h?rev=39760&r1=39759&r2=39760&view=diff
==============================================================================
--- trunk/reactos/dll/win32/cryptui/cryptuires.h [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/cryptui/cryptuires.h [iso-8859-1] Thu Feb 26 13:21:59 2009
@@ -160,6 +160,13 @@
 #define IDS_NO 1217
 #define IDS_EXPORT_SUCCEEDED 1218
 #define IDS_EXPORT_FAILED 1219
+#define IDS_EXPORT_PRIVATE_KEY_TITLE 1220
+#define IDS_EXPORT_PRIVATE_KEY_SUBTITLE 1221
+#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
@@ -175,9 +182,11 @@
 #define IDD_CERT_MGR 111
 #define IDD_CERT_MGR_ADVANCED 112
 #define IDD_EXPORT_WELCOME 113
-#define IDD_EXPORT_FORMAT 114
-#define IDD_EXPORT_FILE 115
-#define IDD_EXPORT_FINISH 116
+#define IDD_EXPORT_PRIVATE_KEY 114
+#define IDD_EXPORT_PASSWORD 115
+#define IDD_EXPORT_FORMAT 116
+#define IDD_EXPORT_FILE 117
+#define IDD_EXPORT_FINISH 118
 
 #define IDB_SMALL_ICONS 200
 #define IDB_CERT 201
@@ -253,5 +262,10 @@
 #define IDC_EXPORT_FILENAME 2909
 #define IDC_EXPORT_BROWSE_FILE 2910
 #define IDC_EXPORT_SETTINGS 2911
+#define IDC_EXPORT_PRIVATE_KEY_YES 2912
+#define IDC_EXPORT_PRIVATE_KEY_NO 2913
+#define IDC_EXPORT_PRIVATE_KEY_UNAVAILABLE 2914
+#define IDC_EXPORT_PASSWORD 2915
+#define IDC_EXPORT_PASSWORD_CONFIRM 2916
 
 #endif /* ndef __CRYPTUIRES_H_ */

Modified: trunk/reactos/dll/win32/cryptui/main.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/cryptui/main.c?rev=39760&r1=39759&r2=39760&view=diff
==============================================================================
--- trunk/reactos/dll/win32/cryptui/main.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/cryptui/main.c [iso-8859-1] Thu Feb 26 13:21:59 2009
@@ -1076,25 +1076,24 @@
         HWND tab = GetDlgItem(hwnd, IDC_MGR_STORES);
 
         data = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CertMgrData));
-        if (data)
-        {
-            data->imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK,
-             2, 0);
-            if (data->imageList)
-            {
-                HBITMAP bmp;
-                COLORREF backColor = RGB(255, 0, 255);
-
-                bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_SMALL_ICONS));
-                ImageList_AddMasked(data->imageList, bmp, backColor);
-                DeleteObject(bmp);
-                ImageList_SetBkColor(data->imageList, CLR_NONE);
-                SendMessageW(GetDlgItem(hwnd, IDC_MGR_CERTS), LVM_SETIMAGELIST,
-                 LVSIL_SMALL, (LPARAM)data->imageList);
-            }
-            SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
-            data->title = pCryptUICertMgr->pwszTitle;
-        }
+        if (!data)
+            return 0;
+        data->imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK, 2, 0);
+        if (data->imageList)
+        {
+            HBITMAP bmp;
+            COLORREF backColor = RGB(255, 0, 255);
+
+            bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_SMALL_ICONS));
+            ImageList_AddMasked(data->imageList, bmp, backColor);
+            DeleteObject(bmp);
+            ImageList_SetBkColor(data->imageList, CLR_NONE);
+            SendMessageW(GetDlgItem(hwnd, IDC_MGR_CERTS), LVM_SETIMAGELIST,
+                         LVSIL_SMALL, (LPARAM)data->imageList);
+        }
+        SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
+        data->title = pCryptUICertMgr->pwszTitle;
+
         initialize_purpose_selection(hwnd);
         add_cert_columns(hwnd);
         if (pCryptUICertMgr->pwszTitle)
@@ -5516,8 +5515,11 @@
     HFONT titleFont;
     DWORD dwFlags;
     LPCWSTR pwszWizardTitle;
-    PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo;
+    CRYPTUI_WIZ_EXPORT_INFO exportInfo;
     CRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO contextInfo;
+    BOOL freePassword;
+    PCRYPT_KEY_PROV_INFO keyProvInfo;
+    BOOL deleteKeys;
     LPWSTR fileName;
     HANDLE file;
     BOOL success;
@@ -5567,6 +5569,141 @@
     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)
+{
+    LRESULT ret = 0;
+    struct ExportWizData *data;
+
+    switch (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;
+    }
+    case WM_NOTIFY:
+    {
+        NMHDR *hdr = (NMHDR *)lp;
+
+        switch (hdr->code)
+        {
+        case PSN_SETACTIVE:
+            PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
+             PSWIZB_BACK | PSWIZB_NEXT);
+            ret = TRUE;
+            break;
+        case PSN_WIZNEXT:
+            data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
+            if (IsDlgButtonChecked(hwnd, IDC_EXPORT_PRIVATE_KEY_NO))
+            {
+                data->contextInfo.dwExportFormat =
+                 CRYPTUI_WIZ_EXPORT_FORMAT_DER;
+                data->contextInfo.fExportPrivateKeys = FALSE;
+            }
+            else
+            {
+                data->contextInfo.dwExportFormat =
+                 CRYPTUI_WIZ_EXPORT_FORMAT_PFX;
+                data->contextInfo.fExportPrivateKeys = TRUE;
+            }
+            break;
+        }
+        break;
+    }
+    }
+    return ret;
+}
+
 static BOOL export_info_has_private_key(PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo)
 {
     BOOL ret = FALSE;
@@ -5585,6 +5722,41 @@
     return ret;
 }
 
+static void export_format_enable_controls(HWND hwnd, struct ExportWizData *data)
+{
+    int defaultFormatID;
+
+    switch (data->contextInfo.dwExportFormat)
+    {
+    case CRYPTUI_WIZ_EXPORT_FORMAT_BASE64:
+        defaultFormatID = IDC_EXPORT_FORMAT_BASE64;
+        break;
+    case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7:
+        defaultFormatID = IDC_EXPORT_FORMAT_CMS;
+        break;
+    case CRYPTUI_WIZ_EXPORT_FORMAT_PFX:
+        defaultFormatID = IDC_EXPORT_FORMAT_PFX;
+        break;
+    default:
+        defaultFormatID = IDC_EXPORT_FORMAT_DER;
+    }
+    SendMessageW(GetDlgItem(hwnd, defaultFormatID), BM_CLICK, 0, 0);
+    if (defaultFormatID == IDC_EXPORT_FORMAT_PFX)
+    {
+        EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_DER), FALSE);
+        EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_BASE64), FALSE);
+        EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_CMS), FALSE);
+        EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_PFX), TRUE);
+    }
+    else
+    {
+        EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_DER), TRUE);
+        EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_BASE64), TRUE);
+        EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_CMS), TRUE);
+        EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_PFX), FALSE);
+    }
+}
+
 static LRESULT CALLBACK export_format_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
  LPARAM lp)
 {
@@ -5596,32 +5768,10 @@
     case WM_INITDIALOG:
     {
         PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
-        int defaultFormatID;
-        BOOL hasPrivateKey;
 
         data = (struct ExportWizData *)page->lParam;
         SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
-        hasPrivateKey = export_info_has_private_key(data->pExportInfo);
-        if (hasPrivateKey)
-            EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_PFX), TRUE);
-        switch (data->contextInfo.dwExportFormat)
-        {
-        case CRYPTUI_WIZ_EXPORT_FORMAT_BASE64:
-            defaultFormatID = IDC_EXPORT_FORMAT_BASE64;
-            break;
-        case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7:
-            defaultFormatID = IDC_EXPORT_FORMAT_CMS;
-            break;
-        case CRYPTUI_WIZ_EXPORT_FORMAT_PFX:
-            if (hasPrivateKey)
-                defaultFormatID = IDC_EXPORT_FORMAT_PFX;
-            else
-                defaultFormatID = IDC_EXPORT_FORMAT_DER;
-            break;
-        default:
-            defaultFormatID = IDC_EXPORT_FORMAT_DER;
-        }
-        SendMessageW(GetDlgItem(hwnd, defaultFormatID), BM_CLICK, 0, 0);
+        export_format_enable_controls(hwnd, data);
         break;
     }
     case WM_NOTIFY:
@@ -5633,10 +5783,14 @@
         case PSN_SETACTIVE:
             PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
              PSWIZB_BACK | PSWIZB_NEXT);
+            data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
+            export_format_enable_controls(hwnd, data);
             ret = TRUE;
             break;
         case PSN_WIZNEXT:
         {
+            BOOL skipPasswordPage = TRUE;
+
             data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
             if (IsDlgButtonChecked(hwnd, IDC_EXPORT_FORMAT_DER))
                 data->contextInfo.dwExportFormat =
@@ -5661,8 +5815,12 @@
                 if (IsDlgButtonChecked(hwnd, IDC_EXPORT_PFX_STRONG_ENCRYPTION))
                     data->contextInfo.fStrongEncryption = TRUE;
                 if (IsDlgButtonChecked(hwnd, IDC_EXPORT_PFX_DELETE_PRIVATE_KEY))
-                    data->contextInfo.fExportPrivateKeys = TRUE;
+                    data->deleteKeys = TRUE;
+                skipPasswordPage = FALSE;
             }
+            SetWindowLongPtrW(hwnd, DWLP_MSGRESULT,
+             skipPasswordPage ? IDD_EXPORT_FILE : 0);
+            ret = 1;
             break;
         }
         }
@@ -5705,6 +5863,111 @@
     return ret;
 }
 
+static void export_password_mismatch(HWND hwnd, struct ExportWizData *data)
+{
+    WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
+    LPCWSTR pTitle;
+
+    if (data->pwszWizardTitle)
+        pTitle = data->pwszWizardTitle;
+    else
+    {
+        LoadStringW(hInstance, IDS_EXPORT_WIZARD, title,
+         sizeof(title) / sizeof(title[0]));
+        pTitle = title;
+    }
+    LoadStringW(hInstance, IDS_EXPORT_PASSWORD_MISMATCH, error,
+     sizeof(error) / sizeof(error[0]));
+    MessageBoxW(hwnd, error, pTitle, MB_ICONERROR | MB_OK);
+    SetFocus(GetDlgItem(hwnd, IDC_EXPORT_PASSWORD));
+}
+
+static LRESULT CALLBACK export_password_dlg_proc(HWND hwnd, UINT msg,
+ WPARAM wp, LPARAM lp)
+{
+    LRESULT ret = 0;
+    struct ExportWizData *data;
+
+    switch (msg)
+    {
+    case WM_INITDIALOG:
+    {
+        PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
+
+        data = (struct ExportWizData *)page->lParam;
+        SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
+        break;
+    }
+    case WM_NOTIFY:
+    {
+        NMHDR *hdr = (NMHDR *)lp;
+
+        switch (hdr->code)
+        {
+        case PSN_SETACTIVE:
+            PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
+             PSWIZB_BACK | PSWIZB_NEXT);
+            ret = TRUE;
+            break;
+        case PSN_WIZNEXT:
+        {
+            HWND passwordEdit = GetDlgItem(hwnd, IDC_EXPORT_PASSWORD);
+            HWND passwordConfirmEdit = GetDlgItem(hwnd,
+             IDC_EXPORT_PASSWORD_CONFIRM);
+            DWORD passwordLen = SendMessageW(passwordEdit, WM_GETTEXTLENGTH,
+             0, 0);
+            DWORD passwordConfirmLen = SendMessageW(passwordConfirmEdit,
+             WM_GETTEXTLENGTH, 0, 0);
+
+            data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
+            if (!passwordLen && !passwordConfirmLen)
+                data->contextInfo.pwszPassword = NULL;
+            else if (passwordLen != passwordConfirmLen)
+            {
+                export_password_mismatch(hwnd, data);
+                SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
+                ret = 1;
+            }
+            else
+            {
+                LPWSTR password = HeapAlloc(GetProcessHeap(), 0,
+                 (passwordLen + 1) * sizeof(WCHAR));
+                LPWSTR passwordConfirm = HeapAlloc(GetProcessHeap(), 0,
+                 (passwordConfirmLen + 1) * sizeof(WCHAR));
+                BOOL freePassword = TRUE;
+
+                if (password && passwordConfirm)
+                {
+                    SendMessageW(passwordEdit, WM_GETTEXT, passwordLen + 1,
+                     (LPARAM)password);
+                    SendMessageW(passwordConfirmEdit, WM_GETTEXT,
+                     passwordConfirmLen + 1, (LPARAM)passwordConfirm);
+                    if (strcmpW(password, passwordConfirm))
+                    {
+                        export_password_mismatch(hwnd, data);
+                        SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
+                        ret = 1;
+                    }
+                    else
+                    {
+                        data->contextInfo.pwszPassword = password;
+                        freePassword = FALSE;
+                        data->freePassword = TRUE;
+                    }
+                }
+                if (freePassword)
+                    HeapFree(GetProcessHeap(), 0, password);
+                HeapFree(GetProcessHeap(), 0, passwordConfirm);
+            }
+            break;
+        }
+        }
+        break;
+    }
+    }
+    return ret;
+}
+
 static LPWSTR export_append_extension(struct ExportWizData *data,
  LPWSTR fileName)
 {
@@ -5727,7 +5990,7 @@
         extension = pfx;
         break;
     default:
-        switch (data->pExportInfo->dwSubjectChoice)
+        switch (data->exportInfo.dwSubjectChoice)
         {
         case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
             extension = crl;
@@ -5926,9 +6189,9 @@
 
         data = (struct ExportWizData *)page->lParam;
         SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
-        if (data->pExportInfo->pwszExportFileName)
+        if (data->exportInfo.pwszExportFileName)
             SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_FILENAME), WM_SETTEXT, 0,
-             (LPARAM)data->pExportInfo->pwszExportFileName);
+             (LPARAM)data->exportInfo.pwszExportFileName);
         break;
     }
     case WM_NOTIFY:
@@ -5937,6 +6200,15 @@
 
         switch (hdr->code)
         {
+        case PSN_WIZBACK:
+            data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
+            if (data->contextInfo.dwExportFormat !=
+             CRYPTUI_WIZ_EXPORT_FORMAT_PFX)
+            {
+                SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, IDD_EXPORT_FORMAT);
+                ret = 1;
+            }
+            break;
         case PSN_WIZNEXT:
         {
             HWND fileNameEdit = GetDlgItem(hwnd, IDC_EXPORT_FILENAME);
@@ -6006,7 +6278,7 @@
             ofn.hwndOwner = hwnd;
             ofn.lpstrFilter = make_export_file_filter(
              data->contextInfo.dwExportFormat,
-             data->pExportInfo->dwSubjectChoice);
+             data->exportInfo.dwSubjectChoice);
             ofn.lpstrFile = fileBuf;
             ofn.nMaxFile = sizeof(fileBuf) / sizeof(fileBuf[0]);
             fileBuf[0] = 0;
@@ -6043,7 +6315,7 @@
     }
 
     item.pszText = text;
-    switch (data->pExportInfo->dwSubjectChoice)
+    switch (data->exportInfo.dwSubjectChoice)
     {
     case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
     case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT:
@@ -6084,7 +6356,7 @@
     SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
 
     item.iSubItem = 1;
-    switch (data->pExportInfo->dwSubjectChoice)
+    switch (data->exportInfo.dwSubjectChoice)
     {
     case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
         contentID = IDS_EXPORT_FILTER_CRL;
@@ -6227,8 +6499,140 @@
      CERT_STORE_SAVE_AS_STORE, CERT_STORE_SAVE_TO_FILE, file, 0);
 }
 
+static BOOL save_pfx(HANDLE file, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo,
+ PCCRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO pContextInfo,
+ PCRYPT_KEY_PROV_INFO keyProvInfo, BOOL deleteKeys)
+{
+    HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING,
+     0, CERT_STORE_CREATE_NEW_FLAG, NULL);
+    BOOL ret = FALSE;
+
+    if (store)
+    {
+        CRYPT_DATA_BLOB pfxBlob = { 0, NULL };
+        PCCERT_CONTEXT cert = NULL;
+        BOOL freeKeyProvInfo = FALSE;
+
+        if (pContextInfo->fExportChain)
+        {
+            HCERTCHAINENGINE engine = NULL;
+
+            if (pExportInfo->cStores)
+            {
+                CERT_CHAIN_ENGINE_CONFIG config;
+
+                memset(&config, 0, sizeof(config));
+                config.cbSize = sizeof(config);
+                config.cAdditionalStore = pExportInfo->cStores;
+                config.rghAdditionalStore = pExportInfo->rghStores;
+                ret = CertCreateCertificateChainEngine(&config, &engine);
+            }
+            else
+                ret = TRUE;
+            if (ret)
+            {
+                CERT_CHAIN_PARA chainPara;
+                PCCERT_CHAIN_CONTEXT chain;
+
+                memset(&chainPara, 0, sizeof(chainPara));
+                chainPara.cbSize = sizeof(chainPara);
+                ret = CertGetCertificateChain(engine,
+                 pExportInfo->u.pCertContext, NULL, NULL, &chainPara, 0, NULL,
+                 &chain);
+                if (ret)
+                {
+                    DWORD i, j;
+
+                    for (i = 0; ret && i < chain->cChain; i++)
+                        for (j = 0; ret && j < chain->rgpChain[i]->cElement;
+                         j++)
+                        {
+                            if (i == 0 && j == 0)
+                                ret = CertAddCertificateContextToStore(store,
+                                 chain->rgpChain[i]->rgpElement[j]->pCertContext,
+                                 CERT_STORE_ADD_ALWAYS, &cert);
+                            else
+                                ret = CertAddCertificateContextToStore(store,
+                                 chain->rgpChain[i]->rgpElement[j]->pCertContext,
+                                 CERT_STORE_ADD_ALWAYS, NULL);
+                        }
+                    CertFreeCertificateChain(chain);
+                }
+            }
+            if (engine)
+                CertFreeCertificateChainEngine(engine);
+        }
+        else
+            ret = CertAddCertificateContextToStore(store,
+             pExportInfo->u.pCertContext, CERT_STORE_ADD_ALWAYS, &cert);
+        /* Copy private key info to newly created cert, so it'll get exported
+         * along with the cert.
+         */
+        if (ret && pContextInfo->fExportPrivateKeys)
+        {
+            if (keyProvInfo)
+                ret = CertSetCertificateContextProperty(cert,
+                 CERT_KEY_PROV_INFO_PROP_ID, 0, keyProvInfo);
+            else
+            {
+                if (!(keyProvInfo = export_get_private_key_info(cert)))
+                    ret = FALSE;
+                else
+                {
+                    ret = CertSetCertificateContextProperty(cert,
+                     CERT_KEY_PROV_INFO_PROP_ID, 0, keyProvInfo);
+                    freeKeyProvInfo = TRUE;
+                }
+            }
+        }
+        if (ret)
+        {
+            DWORD exportFlags =
+             REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY | EXPORT_PRIVATE_KEYS;
+
+            ret = PFXExportCertStore(store, &pfxBlob,
+             pContextInfo->pwszPassword, exportFlags);
+            if (ret)
+            {
+                pfxBlob.pbData = HeapAlloc(GetProcessHeap(), 0, pfxBlob.cbData);
+                if (pfxBlob.pbData)
+                {
+                    ret = PFXExportCertStore(store, &pfxBlob,
+                     pContextInfo->pwszPassword, exportFlags);
+                    if (ret)
+                    {
+                        DWORD bytesWritten;
+
+                        ret = WriteFile(file, pfxBlob.pbData, pfxBlob.cbData,
+                         &bytesWritten, NULL);
+                    }
+                }
+                else
+                {
+                    SetLastError(ERROR_OUTOFMEMORY);
+                    ret = FALSE;
+                }
+            }
+        }
+        if (ret && deleteKeys)
+        {
+            HCRYPTPROV prov;
+
+            CryptAcquireContextW(&prov, keyProvInfo->pwszContainerName,
+             keyProvInfo->pwszProvName, keyProvInfo->dwProvType,
+             CRYPT_DELETEKEYSET);
+        }
+        if (freeKeyProvInfo)
+            HeapFree(GetProcessHeap(), 0, keyProvInfo);
+        CertFreeCertificateContext(cert);
+        CertCloseStore(store, 0);
+    }
+    return ret;
+}
+
 static BOOL do_export(HANDLE file, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo,
- PCCRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO pContextInfo)
+ PCCRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO pContextInfo,
+ PCRYPT_KEY_PROV_INFO keyProvInfo, BOOL deleteKeys)
 {
     BOOL ret;
 
@@ -6272,8 +6676,8 @@
              pContextInfo->fExportChain);
             break;
         case CRYPTUI_WIZ_EXPORT_FORMAT_PFX:
-            FIXME("unimplemented for PFX\n");
-            ret = FALSE;
+            ret = save_pfx(file, pExportInfo, pContextInfo, keyProvInfo,
+             deleteKeys);
             break;
         default:
             SetLastError(E_FAIL);
@@ -6336,8 +6740,8 @@
             DWORD mbFlags;
 
             data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
-            if ((data->success = do_export(data->file, data->pExportInfo,
-             &data->contextInfo)))
+            if ((data->success = do_export(data->file, &data->exportInfo,
+             &data->contextInfo, data->keyProvInfo, data->deleteKeys)))
             {
                 messageID = IDS_EXPORT_SUCCEEDED;
                 mbFlags = MB_OK;
@@ -6371,24 +6775,33 @@
  LPCWSTR pwszWizardTitle, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo, void *pvoid)
 {
     PROPSHEETHEADERW hdr;
-    PROPSHEETPAGEW pages[4];
+    PROPSHEETPAGEW pages[6];
     struct ExportWizData data;
     int nPages = 0;
-    BOOL showFormatPage = TRUE;
+    BOOL hasPrivateKey, showFormatPage = TRUE;
+    INT_PTR l;
 
     data.dwFlags = dwFlags;
     data.pwszWizardTitle = pwszWizardTitle;
-    data.pExportInfo = pExportInfo;
+    memset(&data.exportInfo, 0, sizeof(data.exportInfo));
+    memcpy(&data.exportInfo, pExportInfo,
+     min(sizeof(data.exportInfo), pExportInfo->dwSize));
+    if (pExportInfo->dwSize > sizeof(data.exportInfo))
+        data.exportInfo.dwSize = sizeof(data.exportInfo);
     data.contextInfo.dwSize = sizeof(data.contextInfo);
     data.contextInfo.dwExportFormat = CRYPTUI_WIZ_EXPORT_FORMAT_DER;
     data.contextInfo.fExportChain = FALSE;
     data.contextInfo.fStrongEncryption = FALSE;
     data.contextInfo.fExportPrivateKeys = FALSE;
+    data.contextInfo.pwszPassword = NULL;
+    data.freePassword = FALSE;
     if (pExportInfo->dwSubjectChoice == CRYPTUI_WIZ_EXPORT_CERT_CONTEXT &&
      pvoid)
         memcpy(&data.contextInfo, pvoid,
          min(((PCCRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO)pvoid)->dwSize,
          sizeof(data.contextInfo)));
+    data.keyProvInfo = NULL;
+    data.deleteKeys = FALSE;
     data.fileName = NULL;
     data.file = INVALID_HANDLE_VALUE;
     data.success = FALSE;
@@ -6403,6 +6816,7 @@
     pages[nPages].lParam = (LPARAM)&data;
     nPages++;
 
+    hasPrivateKey = export_info_has_private_key(pExportInfo);
     switch (pExportInfo->dwSubjectChoice)
     {
     case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
@@ -6419,6 +6833,21 @@
         showFormatPage = FALSE;
         data.contextInfo.dwExportFormat = CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7;
         break;
+    }
+
+    if (hasPrivateKey && showFormatPage)
+    {
+        pages[nPages].dwSize = sizeof(pages[0]);
+        pages[nPages].hInstance = hInstance;
+        pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_PRIVATE_KEY);
+        pages[nPages].pfnDlgProc = export_private_key_dlg_proc;
+        pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
+        pages[nPages].pszHeaderTitle =
+         MAKEINTRESOURCEW(IDS_EXPORT_PRIVATE_KEY_TITLE);
+        pages[nPages].pszHeaderSubTitle =
+         MAKEINTRESOURCEW(IDS_EXPORT_PRIVATE_KEY_SUBTITLE);
+        pages[nPages].lParam = (LPARAM)&data;
+        nPages++;
     }
     if (showFormatPage)
     {
@@ -6431,6 +6860,20 @@
          MAKEINTRESOURCEW(IDS_EXPORT_FORMAT_TITLE);
         pages[nPages].pszHeaderSubTitle =
          MAKEINTRESOURCEW(IDS_EXPORT_FORMAT_SUBTITLE);
+        pages[nPages].lParam = (LPARAM)&data;
+        nPages++;
+    }
+    if (hasPrivateKey && showFormatPage)
+    {
+        pages[nPages].dwSize = sizeof(pages[0]);
+        pages[nPages].hInstance = hInstance;
+        pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_PASSWORD);
+        pages[nPages].pfnDlgProc = export_password_dlg_proc;
+        pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
+        pages[nPages].pszHeaderTitle =
+         MAKEINTRESOURCEW(IDS_EXPORT_PASSWORD_TITLE);
+        pages[nPages].pszHeaderSubTitle =
+         MAKEINTRESOURCEW(IDS_EXPORT_PASSWORD_SUBTITLE);
         pages[nPages].lParam = (LPARAM)&data;
         nPages++;
     }
@@ -6468,11 +6911,21 @@
     hdr.nPages = nPages;
     hdr.u4.pszbmWatermark = MAKEINTRESOURCEW(IDB_CERT_WATERMARK);
     hdr.u5.pszbmHeader = MAKEINTRESOURCEW(IDB_CERT_HEADER);
-    PropertySheetW(&hdr);
+    l = PropertySheetW(&hdr);
     DeleteObject(data.titleFont);
+    if (data.freePassword)
+        HeapFree(GetProcessHeap(), 0,
+         (LPWSTR)data.contextInfo.pwszPassword);
+    HeapFree(GetProcessHeap(), 0, data.keyProvInfo);
     CloseHandle(data.file);
     HeapFree(GetProcessHeap(), 0, data.fileName);
-    return data.success;
+    if (l == 0)
+    {
+        SetLastError(ERROR_CANCELLED);
+        return FALSE;
+    }
+    else
+        return data.success;
 }
 
 BOOL WINAPI CryptUIWizExport(DWORD dwFlags, HWND hwndParent,
@@ -6494,7 +6947,7 @@
 
         if (file != INVALID_HANDLE_VALUE)
         {
-            ret = do_export(file, pExportInfo, pvoid);
+            ret = do_export(file, pExportInfo, pvoid, NULL, FALSE);
             CloseHandle(file);
         }
         else



More information about the Ros-diffs mailing list