mirror of
https://github.com/reactos/reactos.git
synced 2025-01-04 21:38:43 +00:00
- Sync crypt32 and cryptui with Wine head
svn path=/trunk/; revision=39760
This commit is contained in:
parent
b6bab62a3b
commit
81ccdcd42b
6 changed files with 802 additions and 79 deletions
|
@ -28,6 +28,7 @@
|
||||||
#include "crypt32_private.h"
|
#include "crypt32_private.h"
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(crypt);
|
WINE_DEFAULT_DEBUG_CHANNEL(crypt);
|
||||||
|
WINE_DECLARE_DEBUG_CHANNEL(chain);
|
||||||
|
|
||||||
#define DEFAULT_CYCLE_MODULUS 7
|
#define DEFAULT_CYCLE_MODULUS 7
|
||||||
|
|
||||||
|
@ -355,7 +356,7 @@ static void CRYPT_CheckRootCert(HCERTCHAINENGINE hRoot,
|
||||||
CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, (void *)root,
|
CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, (void *)root,
|
||||||
CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, (void *)root, 0, NULL))
|
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 |=
|
rootElement->TrustStatus.dwErrorStatus |=
|
||||||
CERT_TRUST_IS_NOT_SIGNATURE_VALID;
|
CERT_TRUST_IS_NOT_SIGNATURE_VALID;
|
||||||
}
|
}
|
||||||
|
@ -411,8 +412,12 @@ static BOOL CRYPT_DecodeBasicConstraints(PCCERT_CONTEXT cert,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Checks element's basic constraints to see if it can act as a CA, with
|
/* 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
|
* remainingCAs CAs left in this chain. A root certificate is assumed to be
|
||||||
* element's constraints, if:
|
* 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
|
* 1. chainConstraints doesn't have a path length constraint, or
|
||||||
* 2. element's path length constraint is smaller than chainConstraints's
|
* 2. element's path length constraint is smaller than chainConstraints's
|
||||||
* Sets *pathLengthConstraintViolated to TRUE if a path length violation
|
* Sets *pathLengthConstraintViolated to TRUE if a path length violation
|
||||||
|
@ -422,17 +427,17 @@ static BOOL CRYPT_DecodeBasicConstraints(PCCERT_CONTEXT cert,
|
||||||
*/
|
*/
|
||||||
static BOOL CRYPT_CheckBasicConstraintsForCA(PCCERT_CONTEXT cert,
|
static BOOL CRYPT_CheckBasicConstraintsForCA(PCCERT_CONTEXT cert,
|
||||||
CERT_BASIC_CONSTRAINTS2_INFO *chainConstraints, DWORD remainingCAs,
|
CERT_BASIC_CONSTRAINTS2_INFO *chainConstraints, DWORD remainingCAs,
|
||||||
BOOL *pathLengthConstraintViolated)
|
BOOL isRoot, BOOL *pathLengthConstraintViolated)
|
||||||
{
|
{
|
||||||
BOOL validBasicConstraints;
|
BOOL validBasicConstraints;
|
||||||
CERT_BASIC_CONSTRAINTS2_INFO constraints;
|
CERT_BASIC_CONSTRAINTS2_INFO constraints;
|
||||||
|
|
||||||
if ((validBasicConstraints = CRYPT_DecodeBasicConstraints(cert,
|
if ((validBasicConstraints = CRYPT_DecodeBasicConstraints(cert,
|
||||||
&constraints, TRUE)))
|
&constraints, isRoot)))
|
||||||
{
|
{
|
||||||
if (!constraints.fCA)
|
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;
|
validBasicConstraints = FALSE;
|
||||||
}
|
}
|
||||||
else if (constraints.fPathLenConstraint)
|
else if (constraints.fPathLenConstraint)
|
||||||
|
@ -444,7 +449,7 @@ static BOOL CRYPT_CheckBasicConstraintsForCA(PCCERT_CONTEXT cert,
|
||||||
constraints.dwPathLenConstraint <
|
constraints.dwPathLenConstraint <
|
||||||
chainConstraints->dwPathLenConstraint)
|
chainConstraints->dwPathLenConstraint)
|
||||||
{
|
{
|
||||||
TRACE("setting path length constraint to %d\n",
|
TRACE_(chain)("setting path length constraint to %d\n",
|
||||||
chainConstraints->dwPathLenConstraint);
|
chainConstraints->dwPathLenConstraint);
|
||||||
chainConstraints->fPathLenConstraint = TRUE;
|
chainConstraints->fPathLenConstraint = TRUE;
|
||||||
chainConstraints->dwPathLenConstraint =
|
chainConstraints->dwPathLenConstraint =
|
||||||
|
@ -455,8 +460,8 @@ static BOOL CRYPT_CheckBasicConstraintsForCA(PCCERT_CONTEXT cert,
|
||||||
if (chainConstraints->fPathLenConstraint &&
|
if (chainConstraints->fPathLenConstraint &&
|
||||||
remainingCAs > chainConstraints->dwPathLenConstraint)
|
remainingCAs > chainConstraints->dwPathLenConstraint)
|
||||||
{
|
{
|
||||||
TRACE("remaining CAs %d exceed max path length %d\n", remainingCAs,
|
TRACE_(chain)("remaining CAs %d exceed max path length %d\n",
|
||||||
chainConstraints->dwPathLenConstraint);
|
remainingCAs, chainConstraints->dwPathLenConstraint);
|
||||||
validBasicConstraints = FALSE;
|
validBasicConstraints = FALSE;
|
||||||
*pathLengthConstraintViolated = TRUE;
|
*pathLengthConstraintViolated = TRUE;
|
||||||
}
|
}
|
||||||
|
@ -709,6 +714,100 @@ static void CRYPT_CheckChainNameConstraints(PCERT_SIMPLE_CHAIN chain)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
static void CRYPT_CheckSimpleChain(PCertificateChainEngine engine,
|
||||||
PCERT_SIMPLE_CHAIN chain, LPFILETIME time)
|
PCERT_SIMPLE_CHAIN chain, LPFILETIME time)
|
||||||
{
|
{
|
||||||
|
@ -717,14 +816,25 @@ static void CRYPT_CheckSimpleChain(PCertificateChainEngine engine,
|
||||||
BOOL pathLengthConstraintViolated = FALSE;
|
BOOL pathLengthConstraintViolated = FALSE;
|
||||||
CERT_BASIC_CONSTRAINTS2_INFO constraints = { TRUE, FALSE, 0 };
|
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--)
|
for (i = chain->cElement - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
|
if (TRACE_ON(chain))
|
||||||
|
dump_element(chain->rgpElement[i]->pCertContext);
|
||||||
if (CertVerifyTimeValidity(time,
|
if (CertVerifyTimeValidity(time,
|
||||||
chain->rgpElement[i]->pCertContext->pCertInfo) != 0)
|
chain->rgpElement[i]->pCertContext->pCertInfo) != 0)
|
||||||
chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
|
chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
|
||||||
CERT_TRUST_IS_NOT_TIME_VALID;
|
CERT_TRUST_IS_NOT_TIME_VALID;
|
||||||
if (i != 0)
|
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 */
|
/* Check the signature of the cert this issued */
|
||||||
if (!CryptVerifyCertificateSignatureEx(0, X509_ASN_ENCODING,
|
if (!CryptVerifyCertificateSignatureEx(0, X509_ASN_ENCODING,
|
||||||
CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT,
|
CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT,
|
||||||
|
@ -741,7 +851,7 @@ static void CRYPT_CheckSimpleChain(PCertificateChainEngine engine,
|
||||||
CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
|
CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
|
||||||
else if (!CRYPT_CheckBasicConstraintsForCA(
|
else if (!CRYPT_CheckBasicConstraintsForCA(
|
||||||
chain->rgpElement[i]->pCertContext, &constraints, i - 1,
|
chain->rgpElement[i]->pCertContext, &constraints, i - 1,
|
||||||
&pathLengthConstraintViolated))
|
isRoot, &pathLengthConstraintViolated))
|
||||||
chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
|
chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
|
||||||
CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
|
CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
|
||||||
else if (constraints.fPathLenConstraint &&
|
else if (constraints.fPathLenConstraint &&
|
||||||
|
@ -884,8 +994,7 @@ static PCCERT_CONTEXT CRYPT_GetIssuer(HCERTSTORE store, PCCERT_CONTEXT subject,
|
||||||
issuer = CertFindCertificateInStore(store,
|
issuer = CertFindCertificateInStore(store,
|
||||||
subject->dwCertEncodingType, 0, CERT_FIND_SUBJECT_NAME,
|
subject->dwCertEncodingType, 0, CERT_FIND_SUBJECT_NAME,
|
||||||
&subject->pCertInfo->Issuer, prevIssuer);
|
&subject->pCertInfo->Issuer, prevIssuer);
|
||||||
if (issuer)
|
*infoStatus = CERT_TRUST_HAS_NAME_MATCH_ISSUER;
|
||||||
*infoStatus = CERT_TRUST_HAS_NAME_MATCH_ISSUER;
|
|
||||||
}
|
}
|
||||||
return issuer;
|
return issuer;
|
||||||
}
|
}
|
||||||
|
@ -902,12 +1011,13 @@ static BOOL CRYPT_BuildSimpleChain(PCertificateChainEngine engine,
|
||||||
while (ret && !CRYPT_IsSimpleChainCyclic(chain) &&
|
while (ret && !CRYPT_IsSimpleChainCyclic(chain) &&
|
||||||
!CRYPT_IsCertificateSelfSigned(cert))
|
!CRYPT_IsCertificateSelfSigned(cert))
|
||||||
{
|
{
|
||||||
DWORD infoStatus;
|
PCCERT_CONTEXT issuer = CRYPT_GetIssuer(world, cert, NULL,
|
||||||
PCCERT_CONTEXT issuer = CRYPT_GetIssuer(world, cert, NULL, &infoStatus);
|
&chain->rgpElement[chain->cElement - 1]->TrustStatus.dwInfoStatus);
|
||||||
|
|
||||||
if (issuer)
|
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
|
/* CRYPT_AddCertToSimpleChain add-ref's the issuer, so free it to
|
||||||
* close the enumeration that found it
|
* close the enumeration that found it
|
||||||
*/
|
*/
|
||||||
|
@ -916,7 +1026,7 @@ static BOOL CRYPT_BuildSimpleChain(PCertificateChainEngine engine,
|
||||||
}
|
}
|
||||||
else
|
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;
|
chain->TrustStatus.dwErrorStatus |= CERT_TRUST_IS_PARTIAL_CHAIN;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,6 +172,7 @@ STRINGTABLE DISCARDABLE
|
||||||
IDS_LOCALIZEDNAME_MY "개인"
|
IDS_LOCALIZEDNAME_MY "개인"
|
||||||
IDS_LOCALIZEDNAME_CA "중개 검증 기관"
|
IDS_LOCALIZEDNAME_CA "중개 검증 기관"
|
||||||
IDS_LOCALIZEDNAME_ADDRESSBOOK "다른 사람"
|
IDS_LOCALIZEDNAME_ADDRESSBOOK "다른 사람"
|
||||||
|
IDS_LOCALIZEDNAME_TRUSTEDPUBLISHER "신뢰할 수 있는 발행자"
|
||||||
}
|
}
|
||||||
|
|
||||||
STRINGTABLE DISCARDABLE
|
STRINGTABLE DISCARDABLE
|
||||||
|
|
|
@ -102,8 +102,8 @@ STRINGTABLE DISCARDABLE
|
||||||
IDS_FRIENDLY_NAME_COLUMN "Friendly Name"
|
IDS_FRIENDLY_NAME_COLUMN "Friendly Name"
|
||||||
IDS_ALLOWED_PURPOSE_ALL "<All>"
|
IDS_ALLOWED_PURPOSE_ALL "<All>"
|
||||||
IDS_ALLOWED_PURPOSE_NONE "<None>"
|
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_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 mesages with these certificate, or sign messages with them.\nAre you sure you want to remove these certificates?"
|
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_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_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?"
|
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 @@ STRINGTABLE DISCARDABLE
|
||||||
IDS_NO "No"
|
IDS_NO "No"
|
||||||
IDS_EXPORT_SUCCEEDED "The export was successful."
|
IDS_EXPORT_SUCCEEDED "The export was successful."
|
||||||
IDS_EXPORT_FAILED "The export failed."
|
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
|
IDD_GENERAL DIALOG DISCARDABLE 0, 0, 255, 236
|
||||||
|
@ -381,6 +388,29 @@ BEGIN
|
||||||
-1, 115,103,195,8
|
-1, 115,103,195,8
|
||||||
END
|
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
|
IDD_EXPORT_FORMAT DIALOG DISCARDABLE 0,0,317,143
|
||||||
CAPTION "Certificate Export Wizard"
|
CAPTION "Certificate Export Wizard"
|
||||||
FONT 8, "MS Shell Dlg"
|
FONT 8, "MS Shell Dlg"
|
||||||
|
|
|
@ -143,6 +143,34 @@ STRINGTABLE DISCARDABLE
|
||||||
IDS_PURPOSE_CA_EXCHANGE "사적 키 보관소"
|
IDS_PURPOSE_CA_EXCHANGE "사적 키 보관소"
|
||||||
IDS_PURPOSE_KEY_RECOVERY_AGENT "키 복구 에이전트"
|
IDS_PURPOSE_KEY_RECOVERY_AGENT "키 복구 에이전트"
|
||||||
IDS_PURPOSE_DS_EMAIL_REPLICATION "디렉토리 서비스 전자우편 복제"
|
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
|
IDD_GENERAL DIALOG DISCARDABLE 0, 0, 255, 236
|
||||||
|
@ -330,3 +358,90 @@ BEGIN
|
||||||
PUSHBUTTON "확인", IDOK, 132,155,51,14, BS_DEFPUSHBUTTON
|
PUSHBUTTON "확인", IDOK, 132,155,51,14, BS_DEFPUSHBUTTON
|
||||||
PUSHBUTTON "취소", IDCANCEL, 190,155,51,14
|
PUSHBUTTON "취소", IDCANCEL, 190,155,51,14
|
||||||
END
|
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
|
||||||
|
|
|
@ -160,6 +160,13 @@
|
||||||
#define IDS_NO 1217
|
#define IDS_NO 1217
|
||||||
#define IDS_EXPORT_SUCCEEDED 1218
|
#define IDS_EXPORT_SUCCEEDED 1218
|
||||||
#define IDS_EXPORT_FAILED 1219
|
#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_GENERAL 100
|
||||||
#define IDD_DETAIL 101
|
#define IDD_DETAIL 101
|
||||||
|
@ -175,9 +182,11 @@
|
||||||
#define IDD_CERT_MGR 111
|
#define IDD_CERT_MGR 111
|
||||||
#define IDD_CERT_MGR_ADVANCED 112
|
#define IDD_CERT_MGR_ADVANCED 112
|
||||||
#define IDD_EXPORT_WELCOME 113
|
#define IDD_EXPORT_WELCOME 113
|
||||||
#define IDD_EXPORT_FORMAT 114
|
#define IDD_EXPORT_PRIVATE_KEY 114
|
||||||
#define IDD_EXPORT_FILE 115
|
#define IDD_EXPORT_PASSWORD 115
|
||||||
#define IDD_EXPORT_FINISH 116
|
#define IDD_EXPORT_FORMAT 116
|
||||||
|
#define IDD_EXPORT_FILE 117
|
||||||
|
#define IDD_EXPORT_FINISH 118
|
||||||
|
|
||||||
#define IDB_SMALL_ICONS 200
|
#define IDB_SMALL_ICONS 200
|
||||||
#define IDB_CERT 201
|
#define IDB_CERT 201
|
||||||
|
@ -253,5 +262,10 @@
|
||||||
#define IDC_EXPORT_FILENAME 2909
|
#define IDC_EXPORT_FILENAME 2909
|
||||||
#define IDC_EXPORT_BROWSE_FILE 2910
|
#define IDC_EXPORT_BROWSE_FILE 2910
|
||||||
#define IDC_EXPORT_SETTINGS 2911
|
#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_ */
|
#endif /* ndef __CRYPTUIRES_H_ */
|
||||||
|
|
|
@ -1076,25 +1076,24 @@ static LRESULT CALLBACK cert_mgr_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
|
||||||
HWND tab = GetDlgItem(hwnd, IDC_MGR_STORES);
|
HWND tab = GetDlgItem(hwnd, IDC_MGR_STORES);
|
||||||
|
|
||||||
data = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CertMgrData));
|
data = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CertMgrData));
|
||||||
if (data)
|
if (!data)
|
||||||
|
return 0;
|
||||||
|
data->imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK, 2, 0);
|
||||||
|
if (data->imageList)
|
||||||
{
|
{
|
||||||
data->imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK,
|
HBITMAP bmp;
|
||||||
2, 0);
|
COLORREF backColor = RGB(255, 0, 255);
|
||||||
if (data->imageList)
|
|
||||||
{
|
|
||||||
HBITMAP bmp;
|
|
||||||
COLORREF backColor = RGB(255, 0, 255);
|
|
||||||
|
|
||||||
bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_SMALL_ICONS));
|
bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_SMALL_ICONS));
|
||||||
ImageList_AddMasked(data->imageList, bmp, backColor);
|
ImageList_AddMasked(data->imageList, bmp, backColor);
|
||||||
DeleteObject(bmp);
|
DeleteObject(bmp);
|
||||||
ImageList_SetBkColor(data->imageList, CLR_NONE);
|
ImageList_SetBkColor(data->imageList, CLR_NONE);
|
||||||
SendMessageW(GetDlgItem(hwnd, IDC_MGR_CERTS), LVM_SETIMAGELIST,
|
SendMessageW(GetDlgItem(hwnd, IDC_MGR_CERTS), LVM_SETIMAGELIST,
|
||||||
LVSIL_SMALL, (LPARAM)data->imageList);
|
LVSIL_SMALL, (LPARAM)data->imageList);
|
||||||
}
|
|
||||||
SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
|
|
||||||
data->title = pCryptUICertMgr->pwszTitle;
|
|
||||||
}
|
}
|
||||||
|
SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
|
||||||
|
data->title = pCryptUICertMgr->pwszTitle;
|
||||||
|
|
||||||
initialize_purpose_selection(hwnd);
|
initialize_purpose_selection(hwnd);
|
||||||
add_cert_columns(hwnd);
|
add_cert_columns(hwnd);
|
||||||
if (pCryptUICertMgr->pwszTitle)
|
if (pCryptUICertMgr->pwszTitle)
|
||||||
|
@ -5516,8 +5515,11 @@ struct ExportWizData
|
||||||
HFONT titleFont;
|
HFONT titleFont;
|
||||||
DWORD dwFlags;
|
DWORD dwFlags;
|
||||||
LPCWSTR pwszWizardTitle;
|
LPCWSTR pwszWizardTitle;
|
||||||
PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo;
|
CRYPTUI_WIZ_EXPORT_INFO exportInfo;
|
||||||
CRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO contextInfo;
|
CRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO contextInfo;
|
||||||
|
BOOL freePassword;
|
||||||
|
PCRYPT_KEY_PROV_INFO keyProvInfo;
|
||||||
|
BOOL deleteKeys;
|
||||||
LPWSTR fileName;
|
LPWSTR fileName;
|
||||||
HANDLE file;
|
HANDLE file;
|
||||||
BOOL success;
|
BOOL success;
|
||||||
|
@ -5567,6 +5569,141 @@ static LRESULT CALLBACK export_welcome_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
|
||||||
return ret;
|
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)
|
static BOOL export_info_has_private_key(PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo)
|
||||||
{
|
{
|
||||||
BOOL ret = FALSE;
|
BOOL ret = FALSE;
|
||||||
|
@ -5585,6 +5722,41 @@ static BOOL export_info_has_private_key(PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo)
|
||||||
return ret;
|
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,
|
static LRESULT CALLBACK export_format_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
|
||||||
LPARAM lp)
|
LPARAM lp)
|
||||||
{
|
{
|
||||||
|
@ -5596,32 +5768,10 @@ static LRESULT CALLBACK export_format_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
|
||||||
case WM_INITDIALOG:
|
case WM_INITDIALOG:
|
||||||
{
|
{
|
||||||
PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
|
PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
|
||||||
int defaultFormatID;
|
|
||||||
BOOL hasPrivateKey;
|
|
||||||
|
|
||||||
data = (struct ExportWizData *)page->lParam;
|
data = (struct ExportWizData *)page->lParam;
|
||||||
SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
|
SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
|
||||||
hasPrivateKey = export_info_has_private_key(data->pExportInfo);
|
export_format_enable_controls(hwnd, data);
|
||||||
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);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case WM_NOTIFY:
|
case WM_NOTIFY:
|
||||||
|
@ -5633,10 +5783,14 @@ static LRESULT CALLBACK export_format_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
|
||||||
case PSN_SETACTIVE:
|
case PSN_SETACTIVE:
|
||||||
PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
|
PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
|
||||||
PSWIZB_BACK | PSWIZB_NEXT);
|
PSWIZB_BACK | PSWIZB_NEXT);
|
||||||
|
data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
|
||||||
|
export_format_enable_controls(hwnd, data);
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
break;
|
break;
|
||||||
case PSN_WIZNEXT:
|
case PSN_WIZNEXT:
|
||||||
{
|
{
|
||||||
|
BOOL skipPasswordPage = TRUE;
|
||||||
|
|
||||||
data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
|
data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
|
||||||
if (IsDlgButtonChecked(hwnd, IDC_EXPORT_FORMAT_DER))
|
if (IsDlgButtonChecked(hwnd, IDC_EXPORT_FORMAT_DER))
|
||||||
data->contextInfo.dwExportFormat =
|
data->contextInfo.dwExportFormat =
|
||||||
|
@ -5661,8 +5815,12 @@ static LRESULT CALLBACK export_format_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
|
||||||
if (IsDlgButtonChecked(hwnd, IDC_EXPORT_PFX_STRONG_ENCRYPTION))
|
if (IsDlgButtonChecked(hwnd, IDC_EXPORT_PFX_STRONG_ENCRYPTION))
|
||||||
data->contextInfo.fStrongEncryption = TRUE;
|
data->contextInfo.fStrongEncryption = TRUE;
|
||||||
if (IsDlgButtonChecked(hwnd, IDC_EXPORT_PFX_DELETE_PRIVATE_KEY))
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5705,6 +5863,111 @@ static LRESULT CALLBACK export_format_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
|
||||||
return ret;
|
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,
|
static LPWSTR export_append_extension(struct ExportWizData *data,
|
||||||
LPWSTR fileName)
|
LPWSTR fileName)
|
||||||
{
|
{
|
||||||
|
@ -5727,7 +5990,7 @@ static LPWSTR export_append_extension(struct ExportWizData *data,
|
||||||
extension = pfx;
|
extension = pfx;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
switch (data->pExportInfo->dwSubjectChoice)
|
switch (data->exportInfo.dwSubjectChoice)
|
||||||
{
|
{
|
||||||
case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
|
case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
|
||||||
extension = crl;
|
extension = crl;
|
||||||
|
@ -5926,9 +6189,9 @@ static LRESULT CALLBACK export_file_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
|
||||||
|
|
||||||
data = (struct ExportWizData *)page->lParam;
|
data = (struct ExportWizData *)page->lParam;
|
||||||
SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
|
SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
|
||||||
if (data->pExportInfo->pwszExportFileName)
|
if (data->exportInfo.pwszExportFileName)
|
||||||
SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_FILENAME), WM_SETTEXT, 0,
|
SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_FILENAME), WM_SETTEXT, 0,
|
||||||
(LPARAM)data->pExportInfo->pwszExportFileName);
|
(LPARAM)data->exportInfo.pwszExportFileName);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case WM_NOTIFY:
|
case WM_NOTIFY:
|
||||||
|
@ -5937,6 +6200,15 @@ static LRESULT CALLBACK export_file_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
|
||||||
|
|
||||||
switch (hdr->code)
|
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:
|
case PSN_WIZNEXT:
|
||||||
{
|
{
|
||||||
HWND fileNameEdit = GetDlgItem(hwnd, IDC_EXPORT_FILENAME);
|
HWND fileNameEdit = GetDlgItem(hwnd, IDC_EXPORT_FILENAME);
|
||||||
|
@ -6006,7 +6278,7 @@ static LRESULT CALLBACK export_file_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
|
||||||
ofn.hwndOwner = hwnd;
|
ofn.hwndOwner = hwnd;
|
||||||
ofn.lpstrFilter = make_export_file_filter(
|
ofn.lpstrFilter = make_export_file_filter(
|
||||||
data->contextInfo.dwExportFormat,
|
data->contextInfo.dwExportFormat,
|
||||||
data->pExportInfo->dwSubjectChoice);
|
data->exportInfo.dwSubjectChoice);
|
||||||
ofn.lpstrFile = fileBuf;
|
ofn.lpstrFile = fileBuf;
|
||||||
ofn.nMaxFile = sizeof(fileBuf) / sizeof(fileBuf[0]);
|
ofn.nMaxFile = sizeof(fileBuf) / sizeof(fileBuf[0]);
|
||||||
fileBuf[0] = 0;
|
fileBuf[0] = 0;
|
||||||
|
@ -6043,7 +6315,7 @@ static void show_export_details(HWND lv, struct ExportWizData *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
item.pszText = text;
|
item.pszText = text;
|
||||||
switch (data->pExportInfo->dwSubjectChoice)
|
switch (data->exportInfo.dwSubjectChoice)
|
||||||
{
|
{
|
||||||
case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
|
case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
|
||||||
case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT:
|
case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT:
|
||||||
|
@ -6084,7 +6356,7 @@ static void show_export_details(HWND lv, struct ExportWizData *data)
|
||||||
SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
|
SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
|
||||||
|
|
||||||
item.iSubItem = 1;
|
item.iSubItem = 1;
|
||||||
switch (data->pExportInfo->dwSubjectChoice)
|
switch (data->exportInfo.dwSubjectChoice)
|
||||||
{
|
{
|
||||||
case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
|
case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
|
||||||
contentID = IDS_EXPORT_FILTER_CRL;
|
contentID = IDS_EXPORT_FILTER_CRL;
|
||||||
|
@ -6227,8 +6499,140 @@ static BOOL save_serialized_store(HANDLE file, HCERTSTORE store)
|
||||||
CERT_STORE_SAVE_AS_STORE, CERT_STORE_SAVE_TO_FILE, file, 0);
|
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,
|
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;
|
BOOL ret;
|
||||||
|
|
||||||
|
@ -6272,8 +6676,8 @@ static BOOL do_export(HANDLE file, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo,
|
||||||
pContextInfo->fExportChain);
|
pContextInfo->fExportChain);
|
||||||
break;
|
break;
|
||||||
case CRYPTUI_WIZ_EXPORT_FORMAT_PFX:
|
case CRYPTUI_WIZ_EXPORT_FORMAT_PFX:
|
||||||
FIXME("unimplemented for PFX\n");
|
ret = save_pfx(file, pExportInfo, pContextInfo, keyProvInfo,
|
||||||
ret = FALSE;
|
deleteKeys);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
SetLastError(E_FAIL);
|
SetLastError(E_FAIL);
|
||||||
|
@ -6336,8 +6740,8 @@ static LRESULT CALLBACK export_finish_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
|
||||||
DWORD mbFlags;
|
DWORD mbFlags;
|
||||||
|
|
||||||
data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
|
data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
|
||||||
if ((data->success = do_export(data->file, data->pExportInfo,
|
if ((data->success = do_export(data->file, &data->exportInfo,
|
||||||
&data->contextInfo)))
|
&data->contextInfo, data->keyProvInfo, data->deleteKeys)))
|
||||||
{
|
{
|
||||||
messageID = IDS_EXPORT_SUCCEEDED;
|
messageID = IDS_EXPORT_SUCCEEDED;
|
||||||
mbFlags = MB_OK;
|
mbFlags = MB_OK;
|
||||||
|
@ -6371,24 +6775,33 @@ static BOOL show_export_ui(DWORD dwFlags, HWND hwndParent,
|
||||||
LPCWSTR pwszWizardTitle, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo, void *pvoid)
|
LPCWSTR pwszWizardTitle, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo, void *pvoid)
|
||||||
{
|
{
|
||||||
PROPSHEETHEADERW hdr;
|
PROPSHEETHEADERW hdr;
|
||||||
PROPSHEETPAGEW pages[4];
|
PROPSHEETPAGEW pages[6];
|
||||||
struct ExportWizData data;
|
struct ExportWizData data;
|
||||||
int nPages = 0;
|
int nPages = 0;
|
||||||
BOOL showFormatPage = TRUE;
|
BOOL hasPrivateKey, showFormatPage = TRUE;
|
||||||
|
INT_PTR l;
|
||||||
|
|
||||||
data.dwFlags = dwFlags;
|
data.dwFlags = dwFlags;
|
||||||
data.pwszWizardTitle = pwszWizardTitle;
|
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.dwSize = sizeof(data.contextInfo);
|
||||||
data.contextInfo.dwExportFormat = CRYPTUI_WIZ_EXPORT_FORMAT_DER;
|
data.contextInfo.dwExportFormat = CRYPTUI_WIZ_EXPORT_FORMAT_DER;
|
||||||
data.contextInfo.fExportChain = FALSE;
|
data.contextInfo.fExportChain = FALSE;
|
||||||
data.contextInfo.fStrongEncryption = FALSE;
|
data.contextInfo.fStrongEncryption = FALSE;
|
||||||
data.contextInfo.fExportPrivateKeys = FALSE;
|
data.contextInfo.fExportPrivateKeys = FALSE;
|
||||||
|
data.contextInfo.pwszPassword = NULL;
|
||||||
|
data.freePassword = FALSE;
|
||||||
if (pExportInfo->dwSubjectChoice == CRYPTUI_WIZ_EXPORT_CERT_CONTEXT &&
|
if (pExportInfo->dwSubjectChoice == CRYPTUI_WIZ_EXPORT_CERT_CONTEXT &&
|
||||||
pvoid)
|
pvoid)
|
||||||
memcpy(&data.contextInfo, pvoid,
|
memcpy(&data.contextInfo, pvoid,
|
||||||
min(((PCCRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO)pvoid)->dwSize,
|
min(((PCCRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO)pvoid)->dwSize,
|
||||||
sizeof(data.contextInfo)));
|
sizeof(data.contextInfo)));
|
||||||
|
data.keyProvInfo = NULL;
|
||||||
|
data.deleteKeys = FALSE;
|
||||||
data.fileName = NULL;
|
data.fileName = NULL;
|
||||||
data.file = INVALID_HANDLE_VALUE;
|
data.file = INVALID_HANDLE_VALUE;
|
||||||
data.success = FALSE;
|
data.success = FALSE;
|
||||||
|
@ -6403,6 +6816,7 @@ static BOOL show_export_ui(DWORD dwFlags, HWND hwndParent,
|
||||||
pages[nPages].lParam = (LPARAM)&data;
|
pages[nPages].lParam = (LPARAM)&data;
|
||||||
nPages++;
|
nPages++;
|
||||||
|
|
||||||
|
hasPrivateKey = export_info_has_private_key(pExportInfo);
|
||||||
switch (pExportInfo->dwSubjectChoice)
|
switch (pExportInfo->dwSubjectChoice)
|
||||||
{
|
{
|
||||||
case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
|
case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
|
||||||
|
@ -6420,6 +6834,21 @@ static BOOL show_export_ui(DWORD dwFlags, HWND hwndParent,
|
||||||
data.contextInfo.dwExportFormat = CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7;
|
data.contextInfo.dwExportFormat = CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7;
|
||||||
break;
|
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)
|
if (showFormatPage)
|
||||||
{
|
{
|
||||||
pages[nPages].dwSize = sizeof(pages[0]);
|
pages[nPages].dwSize = sizeof(pages[0]);
|
||||||
|
@ -6434,6 +6863,20 @@ static BOOL show_export_ui(DWORD dwFlags, HWND hwndParent,
|
||||||
pages[nPages].lParam = (LPARAM)&data;
|
pages[nPages].lParam = (LPARAM)&data;
|
||||||
nPages++;
|
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++;
|
||||||
|
}
|
||||||
|
|
||||||
pages[nPages].dwSize = sizeof(pages[0]);
|
pages[nPages].dwSize = sizeof(pages[0]);
|
||||||
pages[nPages].hInstance = hInstance;
|
pages[nPages].hInstance = hInstance;
|
||||||
|
@ -6468,11 +6911,21 @@ static BOOL show_export_ui(DWORD dwFlags, HWND hwndParent,
|
||||||
hdr.nPages = nPages;
|
hdr.nPages = nPages;
|
||||||
hdr.u4.pszbmWatermark = MAKEINTRESOURCEW(IDB_CERT_WATERMARK);
|
hdr.u4.pszbmWatermark = MAKEINTRESOURCEW(IDB_CERT_WATERMARK);
|
||||||
hdr.u5.pszbmHeader = MAKEINTRESOURCEW(IDB_CERT_HEADER);
|
hdr.u5.pszbmHeader = MAKEINTRESOURCEW(IDB_CERT_HEADER);
|
||||||
PropertySheetW(&hdr);
|
l = PropertySheetW(&hdr);
|
||||||
DeleteObject(data.titleFont);
|
DeleteObject(data.titleFont);
|
||||||
|
if (data.freePassword)
|
||||||
|
HeapFree(GetProcessHeap(), 0,
|
||||||
|
(LPWSTR)data.contextInfo.pwszPassword);
|
||||||
|
HeapFree(GetProcessHeap(), 0, data.keyProvInfo);
|
||||||
CloseHandle(data.file);
|
CloseHandle(data.file);
|
||||||
HeapFree(GetProcessHeap(), 0, data.fileName);
|
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,
|
BOOL WINAPI CryptUIWizExport(DWORD dwFlags, HWND hwndParent,
|
||||||
|
@ -6494,7 +6947,7 @@ BOOL WINAPI CryptUIWizExport(DWORD dwFlags, HWND hwndParent,
|
||||||
|
|
||||||
if (file != INVALID_HANDLE_VALUE)
|
if (file != INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
ret = do_export(file, pExportInfo, pvoid);
|
ret = do_export(file, pExportInfo, pvoid, NULL, FALSE);
|
||||||
CloseHandle(file);
|
CloseHandle(file);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
Loading…
Reference in a new issue