mirror of
https://github.com/reactos/reactos.git
synced 2025-01-02 20:43:18 +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"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(crypt);
|
||||
WINE_DECLARE_DEBUG_CHANNEL(chain);
|
||||
|
||||
#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_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 @@ static BOOL CRYPT_DecodeBasicConstraints(PCCERT_CONTEXT cert,
|
|||
}
|
||||
|
||||
/* 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_DecodeBasicConstraints(PCCERT_CONTEXT cert,
|
|||
*/
|
||||
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 @@ static BOOL CRYPT_CheckBasicConstraintsForCA(PCCERT_CONTEXT cert,
|
|||
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 @@ static BOOL CRYPT_CheckBasicConstraintsForCA(PCCERT_CONTEXT cert,
|
|||
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 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,
|
||||
PCERT_SIMPLE_CHAIN chain, LPFILETIME time)
|
||||
{
|
||||
|
@ -717,14 +816,25 @@ static void CRYPT_CheckSimpleChain(PCertificateChainEngine engine,
|
|||
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 @@ static void CRYPT_CheckSimpleChain(PCertificateChainEngine engine,
|
|||
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 @@ static PCCERT_CONTEXT CRYPT_GetIssuer(HCERTSTORE store, PCCERT_CONTEXT subject,
|
|||
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 @@ static BOOL CRYPT_BuildSimpleChain(PCertificateChainEngine engine,
|
|||
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 @@ static BOOL CRYPT_BuildSimpleChain(PCertificateChainEngine engine,
|
|||
}
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -172,6 +172,7 @@ STRINGTABLE DISCARDABLE
|
|||
IDS_LOCALIZEDNAME_MY "개인"
|
||||
IDS_LOCALIZEDNAME_CA "중개 검증 기관"
|
||||
IDS_LOCALIZEDNAME_ADDRESSBOOK "다른 사람"
|
||||
IDS_LOCALIZEDNAME_TRUSTEDPUBLISHER "신뢰할 수 있는 발행자"
|
||||
}
|
||||
|
||||
STRINGTABLE DISCARDABLE
|
||||
|
|
|
@ -102,8 +102,8 @@ STRINGTABLE DISCARDABLE
|
|||
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 @@ STRINGTABLE DISCARDABLE
|
|||
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
|
||||
|
@ -381,6 +388,29 @@ BEGIN
|
|||
-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
|
||||
CAPTION "Certificate Export Wizard"
|
||||
FONT 8, "MS Shell Dlg"
|
||||
|
|
|
@ -143,6 +143,34 @@ STRINGTABLE DISCARDABLE
|
|||
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 @@ BEGIN
|
|||
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
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -1076,25 +1076,24 @@ static LRESULT CALLBACK cert_mgr_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
|
|||
HWND tab = GetDlgItem(hwnd, IDC_MGR_STORES);
|
||||
|
||||
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,
|
||||
2, 0);
|
||||
if (data->imageList)
|
||||
{
|
||||
HBITMAP bmp;
|
||||
COLORREF backColor = RGB(255, 0, 255);
|
||||
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;
|
||||
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 @@ struct ExportWizData
|
|||
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 @@ static LRESULT CALLBACK export_welcome_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static PCRYPT_KEY_PROV_INFO export_get_private_key_info(PCCERT_CONTEXT cert)
|
||||
{
|
||||
PCRYPT_KEY_PROV_INFO info = NULL;
|
||||
DWORD size;
|
||||
|
||||
if (CertGetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID,
|
||||
NULL, &size))
|
||||
{
|
||||
info = HeapAlloc(GetProcessHeap(), 0, size);
|
||||
if (info)
|
||||
{
|
||||
if (!CertGetCertificateContextProperty(cert,
|
||||
CERT_KEY_PROV_INFO_PROP_ID, info, &size))
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, info);
|
||||
info = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
static BOOL export_acquire_private_key(PCRYPT_KEY_PROV_INFO info,
|
||||
HCRYPTPROV *phProv)
|
||||
{
|
||||
BOOL ret;
|
||||
|
||||
ret = CryptAcquireContextW(phProv, info->pwszContainerName,
|
||||
info->pwszProvName, info->dwProvType, 0);
|
||||
if (ret)
|
||||
{
|
||||
DWORD i;
|
||||
|
||||
for (i = 0; i < info->cProvParam; i++)
|
||||
CryptSetProvParam(*phProv, info->rgProvParam[i].dwParam,
|
||||
info->rgProvParam[i].pbData, info->rgProvParam[i].dwFlags);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL export_is_key_exportable(HCRYPTPROV hProv, DWORD keySpec)
|
||||
{
|
||||
BOOL ret;
|
||||
HCRYPTKEY key;
|
||||
|
||||
if ((ret = CryptGetUserKey(hProv, keySpec, &key)))
|
||||
{
|
||||
DWORD permissions, size = sizeof(permissions);
|
||||
|
||||
if ((ret = CryptGetKeyParam(key, KP_PERMISSIONS, (BYTE *)&permissions,
|
||||
&size, 0)) && !(permissions & CRYPT_EXPORT))
|
||||
ret = FALSE;
|
||||
CryptDestroyKey(key);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK export_private_key_dlg_proc(HWND hwnd, UINT msg,
|
||||
WPARAM wp, LPARAM lp)
|
||||
{
|
||||
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 @@ static BOOL export_info_has_private_key(PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo)
|
|||
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 @@ static LRESULT CALLBACK export_format_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
|
|||
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 @@ static LRESULT CALLBACK export_format_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
|
|||
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 @@ static LRESULT CALLBACK export_format_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
|
|||
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 @@ static LRESULT CALLBACK export_format_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
|
|||
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 @@ static LPWSTR export_append_extension(struct ExportWizData *data,
|
|||
extension = pfx;
|
||||
break;
|
||||
default:
|
||||
switch (data->pExportInfo->dwSubjectChoice)
|
||||
switch (data->exportInfo.dwSubjectChoice)
|
||||
{
|
||||
case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
|
||||
extension = crl;
|
||||
|
@ -5926,9 +6189,9 @@ static LRESULT CALLBACK export_file_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
|
|||
|
||||
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 @@ static LRESULT CALLBACK export_file_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
|
|||
|
||||
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 @@ static LRESULT CALLBACK export_file_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
|
|||
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 @@ static void show_export_details(HWND lv, struct ExportWizData *data)
|
|||
}
|
||||
|
||||
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 @@ static void show_export_details(HWND lv, struct ExportWizData *data)
|
|||
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 @@ static BOOL save_serialized_store(HANDLE file, HCERTSTORE store)
|
|||
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 @@ static BOOL do_export(HANDLE file, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo,
|
|||
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 @@ static LRESULT CALLBACK export_finish_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
|
|||
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 @@ static BOOL show_export_ui(DWORD dwFlags, HWND hwndParent,
|
|||
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 @@ static BOOL show_export_ui(DWORD dwFlags, HWND hwndParent,
|
|||
pages[nPages].lParam = (LPARAM)&data;
|
||||
nPages++;
|
||||
|
||||
hasPrivateKey = export_info_has_private_key(pExportInfo);
|
||||
switch (pExportInfo->dwSubjectChoice)
|
||||
{
|
||||
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;
|
||||
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)
|
||||
{
|
||||
pages[nPages].dwSize = sizeof(pages[0]);
|
||||
|
@ -6434,6 +6863,20 @@ static BOOL show_export_ui(DWORD dwFlags, HWND hwndParent,
|
|||
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++;
|
||||
}
|
||||
|
||||
pages[nPages].dwSize = sizeof(pages[0]);
|
||||
pages[nPages].hInstance = hInstance;
|
||||
|
@ -6468,11 +6911,21 @@ static BOOL show_export_ui(DWORD dwFlags, HWND hwndParent,
|
|||
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 @@ BOOL WINAPI CryptUIWizExport(DWORD dwFlags, HWND hwndParent,
|
|||
|
||||
if (file != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
ret = do_export(file, pExportInfo, pvoid);
|
||||
ret = do_export(file, pExportInfo, pvoid, NULL, FALSE);
|
||||
CloseHandle(file);
|
||||
}
|
||||
else
|
||||
|
|
Loading…
Reference in a new issue