Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

7290 lines
159 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1995 - 1999
//
// File: store.cpp
//
//--------------------------------------------------------------------------
#include <pch.cpp>
#pragma hdrstop
#include <winldap.h>
#include <setupapi.h>
#include "ocmanage.h"
#include "initcert.h"
#include "cscsp.h"
#include "csber.h"
#include "csldap.h"
#define __dwFILE__ __dwFILE_CERTUTIL_STORE_CPP__
#define RSAPRIV_MAGIC 0x32415352 // "RSA2"
DWORD
cuGetSystemStoreFlags()
{
return(g_fEnterpriseRegistry?
CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE :
(g_fUserRegistry?
CERT_SYSTEM_STORE_CURRENT_USER :
CERT_SYSTEM_STORE_LOCAL_MACHINE));
}
// Parse a CertIndex -- any one of the following:
//
// Return the following in *piCert, *piCRL and *piCTL. MAXDWORD if not
// specified
// Each value must be less than 64k.
// iCert decimal number
// iCert.iCRL decimal number, period, decimal number
// iCert.iCRL.iCTL decimal number, period, decimal number, period, number
// .iCRL period, decimal number
// ..iCTL period, period, decimal number
//
// Return the string in *ppwszCertName, if no Cert, CRL and CTL indexes.
HRESULT
ParseCertCRLIndex(
IN WCHAR const *pwszCertIndex,
OUT WCHAR **ppwszCertName,
OUT DWORD *piCert,
OUT DWORD *piCRL,
OUT DWORD *piCTL)
{
HRESULT hr;
WCHAR *pwszCopy = NULL;
*ppwszCertName = NULL;
*piCert = MAXDWORD;
*piCRL = MAXDWORD;
*piCTL = MAXDWORD;
if (NULL != pwszCertIndex && 0 != lstrcmp(L"*", pwszCertIndex))
{
BOOL fNumericIndex = TRUE;
WCHAR *pwszCert;
WCHAR *pwszCRL;
WCHAR *pwszCTL;
if (L' ' == *pwszCertIndex)
{
fNumericIndex = FALSE;
pwszCertIndex++;
}
hr = myDupString(pwszCertIndex, &pwszCopy);
_JumpIfError(hr, error, "myDupString");
pwszCert = pwszCopy;
if (!iswdigit(*pwszCert) && L'.' != *pwszCert)
{
fNumericIndex = FALSE;
}
pwszCRL = NULL;
pwszCTL = NULL;
if (fNumericIndex)
{
pwszCRL = wcschr(pwszCert, L'.');
if (NULL != pwszCRL)
{
*pwszCRL++ = L'\0';
pwszCTL = wcschr(pwszCRL, L'.');
if (NULL != pwszCTL)
{
*pwszCTL++ = L'\0';
if (L'\0' != *pwszCTL)
{
hr = myGetLong(pwszCTL, (LONG *) piCTL);
if (S_OK != hr || 64*1024 <= *piCTL)
{
fNumericIndex = FALSE;
}
}
}
if (fNumericIndex && L'\0' != *pwszCRL)
{
hr = myGetLong(pwszCRL, (LONG *) piCRL);
if (S_OK != hr || 64*1024 <= *piCRL)
{
fNumericIndex = FALSE;
}
}
}
}
if (fNumericIndex && L'\0' != *pwszCert)
{
hr = myGetLong(pwszCert, (LONG *) piCert);
if (S_OK != hr || 64*1024 <= *piCert)
{
fNumericIndex = FALSE;
}
}
if (!fNumericIndex)
{
hr = myRevertSanitizeName(pwszCertIndex, ppwszCertName);
_JumpIfError(hr, error, "myRevertSanitizeName");
*piCert = MAXDWORD;
*piCRL = MAXDWORD;
*piCTL = MAXDWORD;
}
}
if (1 < g_fVerbose)
{
wprintf(
L"pwszCertIndex=%ws, %ws, %d.%d.%d\n",
pwszCertIndex,
*ppwszCertName,
*piCert,
*piCRL,
*piCTL);
}
hr = S_OK;
error:
if (NULL != pwszCopy)
{
LocalFree(pwszCopy);
}
return(hr);
}
HRESULT
DeleteKeys(
IN CERT_CONTEXT const *pcc,
IN BOOL fUser)
{
HRESULT hr;
CRYPT_KEY_PROV_INFO *pkpi = NULL;
hr = myCertGetKeyProviderInfo(pcc, &pkpi);
_PrintIfError(hr, "myCertGetKeyProviderInfo");
if (S_OK == hr)
{
HCRYPTPROV hProv;
if (!myCertSrvCryptAcquireContext(
&hProv,
pkpi->pwszContainerName,
pkpi->pwszProvName,
pkpi->dwProvType,
pkpi->dwFlags | CRYPT_DELETEKEYSET,
!fUser))
{
hr = myHLastError();
_PrintIfError(hr, "myCertSrvCryptAcquireContext");
}
else
{
DBGPRINT((
DBG_SS_CERTLIBI,
"DeleteKeys(%ws, %ws)\n",
!fUser? L"Machine" : L"User",
pkpi->pwszContainerName));
}
}
hr = S_OK;
//error:
if (NULL != pkpi)
{
LocalFree(pkpi);
}
return(hr);
}
// Delete keys copied into new CSP, and close store
HRESULT
cuDeleteStoreAndKeys(
OPTIONAL IN HCERTSTORE hStore,
IN BOOL fUser)
{
HRESULT hr;
CERT_CONTEXT const *pcc;
// Enumerate certs and delete keys
pcc = NULL;
while (TRUE)
{
pcc = CertEnumCertificatesInStore(hStore, pcc);
if (NULL == pcc)
{
break;
}
hr = DeleteKeys(pcc, fUser);
_PrintIfError(hr, "DeleteKeys");
}
CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
hr = S_OK;
//error:
return(hr);
}
HRESULT
CopyOneCertAndKeys(
IN CERT_CONTEXT const *pcc,
IN BOOL fUser,
IN WCHAR const *pwszNewCSP,
IN OUT HCERTSTORE hStore)
{
HRESULT hr;
CRYPT_KEY_PROV_INFO *pkpi = NULL;
WCHAR *pwszKeyContainerName = NULL;
CERT_CONTEXT const *pccNew = NULL;
pccNew = CertCreateCertificateContext(
X509_ASN_ENCODING,
pcc->pbCertEncoded,
pcc->cbCertEncoded);
if (NULL == pccNew)
{
hr = myHLastError();
_JumpError(hr, error, "CertCreateCertificateContext");
}
hr = myCertGetKeyProviderInfo(pcc, &pkpi);
_PrintIfError(hr, "myCertGetKeyProviderInfo");
if (S_OK == hr)
{
hr = cuGenerateKeyContainerName(pcc, &pwszKeyContainerName);
_JumpIfError(hr, error, "cuGenerateKeyContainerName");
hr = myCopyKeys(
pkpi,
pkpi->pwszContainerName, // pwszOldContainer
pwszKeyContainerName, // pwszNewContainer
pwszNewCSP, // pwszNewCSP
fUser, // fOldUserKey
fUser, // fNewUserKey
FALSE, // fNewProtect
g_fForce);
_JumpIfError(hr, error, "myCopyKeys");
pkpi->pwszContainerName = pwszKeyContainerName;
pkpi->pwszProvName = const_cast<WCHAR *>(pwszNewCSP);
if (!CertSetCertificateContextProperty(
pccNew,
CERT_KEY_PROV_INFO_PROP_ID,
0,
pkpi))
{
hr = myHLastError();
_JumpError(hr, error, "CertSetCertificateContextProperty");
}
}
if (!CertAddCertificateContextToStore(
hStore,
pccNew,
CERT_STORE_ADD_ALWAYS,
NULL))
{
hr = myHLastError();
_JumpError(hr, error, "CertAddCertificateContextToStore");
}
hr = S_OK;
error:
if (NULL != pccNew)
{
CertFreeCertificateContext(pccNew);
}
if (NULL != pkpi)
{
LocalFree(pkpi);
}
if (NULL != pwszKeyContainerName)
{
LocalFree(pwszKeyContainerName);
}
return(hr);
}
HRESULT
cuCopyStoreToNewCSP(
IN HCERTSTORE hStoreIn,
IN BOOL fUser,
IN WCHAR const *pwszNewCSP,
OUT HCERTSTORE *phStoreOut)
{
HRESULT hr;
HCERTSTORE hStoreOut = NULL;
CERT_CONTEXT const *pcc;
*phStoreOut = NULL;
hStoreOut = CertOpenStore(
CERT_STORE_PROV_MEMORY,
X509_ASN_ENCODING,
NULL,
CERT_STORE_NO_CRYPT_RELEASE_FLAG |
CERT_STORE_ENUM_ARCHIVED_FLAG,
NULL);
if (NULL == hStoreOut)
{
hr = myHLastError();
_JumpError(hr, error, "CertOpenStore");
}
// Enumerate certs:
// copy certs to new store and keys to new CSP
pcc = NULL;
while (TRUE)
{
pcc = CertEnumCertificatesInStore(hStoreIn, pcc);
if (NULL == pcc)
{
break;
}
hr = CopyOneCertAndKeys(pcc, fUser, pwszNewCSP, hStoreOut);
_JumpIfError(hr, error, "CopyOneCertAndKeys");
}
*phStoreOut = hStoreOut;
hStoreOut = NULL;
hr = S_OK;
error:
if (NULL != hStoreOut)
{
cuDeleteStoreAndKeys(hStoreOut, fUser);
}
return(hr);
}
HRESULT
SavePFXStoreToFile(
IN HCERTSTORE hStoreSave,
IN WCHAR const *pwszfnOut,
OPTIONAL IN WCHAR const *pwszNewCSP,
OPTIONAL IN WCHAR const *pwszSalt,
OPTIONAL IN WCHAR const *pwszV3CACertId,
IN BOOL fSaveAsPFX,
IN DWORD dwEPFAlg,
IN WCHAR const *pwszPassword,
IN OUT WCHAR **ppwszPassword)
{
HRESULT hr;
CRYPT_DATA_BLOB pfx;
WCHAR wszPassword[MAX_PATH];
HCERTSTORE hStoreT = NULL;
BOOL fUser = !g_fEnterpriseRegistry && g_fUserRegistry;
pfx.pbData = NULL;
if (NULL == *ppwszPassword)
{
hr = cuGetPassword(
IDS_FORMAT_ENTER_PASSWORD_OUTPUT_FILE,
pwszfnOut,
pwszPassword,
TRUE, // fVerify
wszPassword,
ARRAYSIZE(wszPassword),
&pwszPassword);
_JumpIfError(hr, error, "cuGetPassword");
hr = myDupString(pwszPassword, ppwszPassword);
_JumpIfError(hr, error, "myDupString");
}
pwszPassword = *ppwszPassword;
if (fSaveAsPFX)
{
if (NULL != pwszNewCSP)
{
// Copy keys to new CSP, create new store with updated KeyProvInfo
//wprintf(L"New CSP: %ws\n", pwszNewCSP);
hr = cuCopyStoreToNewCSP(hStoreSave, fUser, pwszNewCSP, &hStoreT);
_JumpIfError(hr, error, "cuCopyStoreToNewCSP");
hStoreSave = hStoreT;
}
// GemPlus returns NTE_BAD_TYPE instead of NTE_BAD_KEY, blowing up
// REPORT_NOT_ABLE* filtering. If they ever get this right, we can
// pass "[...] : EXPORT_PRIVATE_KEYS"
hr = myPFXExportCertStore(
hStoreSave,
&pfx,
pwszPassword,
!g_fWeakPFX,
EXPORT_PRIVATE_KEYS | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY);
_JumpIfError(hr, error, "myPFXExportCertStore");
hr = EncodeToFileW(
pwszfnOut,
pfx.pbData,
pfx.cbData,
CRYPT_STRING_BINARY | g_EncodeFlags);
_JumpIfError(hr, error, "EncodeToFileW");
}
else
{
hr = EPFSaveCertStoreToFile(
hStoreSave,
pwszPassword,
pwszfnOut,
pwszV3CACertId,
dwEPFAlg,
pwszSalt);
_JumpIfError(hr, error, "EPFSaveCertStoreToFile");
}
error:
SecureZeroMemory(wszPassword, sizeof(wszPassword)); // password data
if (NULL != hStoreT)
{
cuDeleteStoreAndKeys(hStoreT, fUser);
}
if (NULL != pfx.pbData)
{
LocalFree(pfx.pbData);
}
return(hr);
}
HRESULT
SavePFXToFile(
IN CERT_CONTEXT const *pCert,
IN WCHAR const *pwszfnOut,
IN BOOL fFirst,
IN WCHAR const *pwszPassword,
IN OUT WCHAR **ppwszPassword)
{
HRESULT hr;
HCERTSTORE hTempMemoryStore = NULL;
hTempMemoryStore = CertOpenStore(
CERT_STORE_PROV_MEMORY,
X509_ASN_ENCODING,
NULL,
CERT_STORE_NO_CRYPT_RELEASE_FLAG |
CERT_STORE_ENUM_ARCHIVED_FLAG,
NULL);
if (NULL == hTempMemoryStore)
{
hr = myHLastError();
_JumpError(hr, error, "CertOpenStore");
}
// Begin Chain Building
hr = myAddChainToMemoryStore(hTempMemoryStore, pCert, g_dwmsTimeout);
_JumpIfError(hr, error, "myAddChainToMemoryStore");
// End Chain Building
hr = SavePFXStoreToFile(
hTempMemoryStore,
pwszfnOut,
NULL, // pwszNewCSP
NULL, // pwszSalt
NULL, // pwszV3CACertId
TRUE, // fSaveAsPFX
0, // dwEPFAlg
pwszPassword,
ppwszPassword);
_JumpIfError(hr, error, "SavePFXStoreToFile");
error:
if (NULL != hTempMemoryStore)
{
CertCloseStore(hTempMemoryStore, CERT_CLOSE_STORE_CHECK_FLAG);
}
return(hr);
}
HRESULT
SavePVKToFile(
IN CERT_CONTEXT const *pCert,
IN WCHAR const *pwszfnOut,
IN BOOL fFirst)
{
return(S_OK);
}
HRESULT
cuDumpCTLProperties(
IN CTL_CONTEXT const *pCTL)
{
HRESULT hr;
DWORD dwPropId;
BYTE *pb = NULL;
DWORD cb;
dwPropId = 0;
while (TRUE)
{
if (NULL != pb)
{
LocalFree(pb);
pb = NULL;
}
dwPropId = CertEnumCTLContextProperties(pCTL, dwPropId);
if (0 == dwPropId)
{
break;
}
while (TRUE)
{
if (!CertGetCTLContextProperty(pCTL, dwPropId, pb, &cb))
{
hr = myHLastError();
_JumpError(hr, error, "CertGetCTLContextProperty");
}
if (NULL != pb)
{
break; // memory alloc'd, property fetched
}
pb = (BYTE *) LocalAlloc(LMEM_FIXED, cb);
if (NULL == pb)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
}
hr = cuDumpFormattedProperty(dwPropId, NULL, pb, cb);
_PrintIfError(hr, "cuDumpFormattedProperty");
}
hr = S_OK;
error:
if (NULL != pb)
{
LocalFree(pb);
}
return(hr);
}
HRESULT
cuDumpCRLProperties(
IN CRL_CONTEXT const *pCRL)
{
HRESULT hr;
DWORD dwPropId;
BYTE *pb = NULL;
DWORD cb;
dwPropId = 0;
while (TRUE)
{
if (NULL != pb)
{
LocalFree(pb);
pb = NULL;
}
dwPropId = CertEnumCRLContextProperties(pCRL, dwPropId);
if (0 == dwPropId)
{
break;
}
while (TRUE)
{
if (!CertGetCRLContextProperty(pCRL, dwPropId, pb, &cb))
{
hr = myHLastError();
_JumpError(hr, error, "CertGetCRLContextProperty");
}
if (NULL != pb)
{
break; // memory alloc'd, property fetched
}
pb = (BYTE *) LocalAlloc(LMEM_FIXED, cb);
if (NULL == pb)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
}
hr = cuDumpFormattedProperty(dwPropId, NULL, pb, cb);
_PrintIfError(hr, "cuDumpFormattedProperty");
}
hr = S_OK;
error:
if (NULL != pb)
{
LocalFree(pb);
}
return(hr);
}
HRESULT
cuDumpCertProperties(
IN CERT_CONTEXT const *pCert)
{
HRESULT hr;
DWORD dwPropId;
BYTE *pb = NULL;
DWORD cb;
dwPropId = 0;
while (TRUE)
{
dwPropId = CertEnumCertificateContextProperties(pCert, dwPropId);
if (0 == dwPropId)
{
break;
}
if (NULL != pb)
{
LocalFree(pb);
pb = NULL;
}
while (TRUE)
{
if (!CertGetCertificateContextProperty(pCert, dwPropId, pb, &cb))
{
hr = myHLastError();
_JumpError(hr, error, "CertGetCertificateContextProperty");
}
if (NULL != pb)
{
break; // memory alloc'd, property fetched
}
pb = (BYTE *) LocalAlloc(LMEM_FIXED, cb);
if (NULL == pb)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
}
hr = cuDumpFormattedProperty(dwPropId, NULL, pb, cb);
_PrintIfError(hr, "cuDumpFormattedProperty");
}
hr = S_OK;
error:
if (NULL != pb)
{
LocalFree(pb);
}
return(hr);
}
HRESULT
SetCertificateKeyProvInfo(
IN CERT_CONTEXT const *pCert,
IN CRYPT_KEY_PROV_INFO const *pkpi,
IN CERT_PUBLIC_KEY_INFO const *pPubKeyInfo)
{
HRESULT hr;
if (!myCertComparePublicKeyInfo(
X509_ASN_ENCODING,
CERT_V1 == pCert->pCertInfo->dwVersion,
pPubKeyInfo,
&pCert->pCertInfo->SubjectPublicKeyInfo))
{
// by design, (my)CertComparePublicKeyInfo doesn't set last error!
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError2(hr, error, "myCertComparePublicKeyInfo", hr);
}
if (!CertSetCertificateContextProperty(
pCert,
CERT_KEY_PROV_INFO_PROP_ID,
0,
pkpi))
{
hr = myHLastError();
_JumpError(hr, error, "CertSetCertificateContextProperty");
}
hr = S_OK;
error:
return(hr);
}
HRESULT
cuFindCertificateKeyProvInfo(
IN CERT_CONTEXT const *pCert)
{
HRESULT hr;
HCRYPTPROV hProv = NULL;
KEY_LIST *pKeyList = NULL;
CERT_PUBLIC_KEY_INFO *pPubKeyInfoSig = NULL;
CERT_PUBLIC_KEY_INFO *pPubKeyInfoXchg = NULL;
if (NULL != g_pwszCSP)
{
DWORD dwKeySpec;
DWORD dwProvType;
KEY_LIST *pKeyT;
hr = csiGetProviderTypeFromProviderName(g_pwszCSP, &dwProvType);
_JumpIfErrorStr(hr, error, "csiGetProviderTypeFromProviderName", g_pwszCSP);
if (!CryptAcquireCertificatePrivateKey(
pCert,
CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
NULL, // pvReserved
&hProv,
&dwKeySpec,
NULL)) // pfCallerFreeProv
{
hr = myHLastError();
_PrintError(hr, "CryptFindCertificateKeyProvInfo");
}
else
{
hr = CRYPT_E_EXISTS;
_PrintError2(hr, "Key Exists!", hr);
if (!g_fForce)
{
goto error;
}
}
hr = csiGetKeyList(
dwProvType, // dwProvType
g_pwszCSP, // pwszProvName
!g_fUserRegistry, // fMachineKeyset
!g_fCryptSilent, // inverted fSilent: default is Silent!
&pKeyList);
_JumpIfErrorStr(hr, error, "csiGetKeyList", g_pwszCSP);
for (pKeyT = pKeyList; NULL != pKeyT; pKeyT = pKeyT->next)
{
DWORD dwProvTypeT;
dwProvTypeT = dwProvType;
hr = cuLoadKeys(
g_pwszCSP,
&dwProvTypeT,
pKeyT->pwszName,
!g_fUserRegistry, // fMachineKeyset
TRUE,
NULL,
&pPubKeyInfoSig,
&pPubKeyInfoXchg);
if (S_OK != hr)
{
cuPrintError(IDS_ERR_FORMAT_LOADKEYS, hr);
}
else
{
CRYPT_KEY_PROV_INFO kpi;
ZeroMemory(&kpi, sizeof(kpi));
kpi.pwszContainerName = pKeyT->pwszName;
kpi.pwszProvName = g_pwszCSP;
kpi.dwProvType = dwProvTypeT;
kpi.dwFlags = g_fUserRegistry? 0 : CRYPT_MACHINE_KEYSET;
if (NULL != pPubKeyInfoSig)
{
kpi.dwKeySpec = AT_SIGNATURE;
hr = SetCertificateKeyProvInfo(
pCert,
&kpi,
pPubKeyInfoSig);
if (S_OK == hr)
{
break;
}
_PrintError2(hr, "SetCertificateKeyProvInfo", hr);
}
if (NULL != pPubKeyInfoXchg)
{
kpi.dwKeySpec = AT_KEYEXCHANGE;
hr = SetCertificateKeyProvInfo(
pCert,
&kpi,
pPubKeyInfoXchg);
if (S_OK == hr)
{
break;
}
_PrintError2(hr, "SetCertificateKeyProvInfo", hr);
}
}
if (NULL != pPubKeyInfoSig)
{
LocalFree(pPubKeyInfoSig);
pPubKeyInfoSig = NULL;
}
if (NULL != pPubKeyInfoXchg)
{
LocalFree(pPubKeyInfoXchg);
pPubKeyInfoXchg = NULL;
}
}
if (NULL == pKeyT)
{
hr = CRYPT_E_NOT_FOUND;
_JumpError(hr, error, "cuFindCertificateKeyProvInfo");
}
}
else
{
if (!CryptFindCertificateKeyProvInfo(
pCert,
0, // dwFlags
NULL)) // pvReserved
{
hr = myHLastError();
_JumpError(hr, error, "CryptFindCertificateKeyProvInfo");
}
}
hr = S_OK;
error:
if (NULL != pPubKeyInfoSig)
{
LocalFree(pPubKeyInfoSig);
}
if (NULL != pPubKeyInfoXchg)
{
LocalFree(pPubKeyInfoXchg);
}
if (NULL != pKeyList)
{
csiFreeKeyList(pKeyList);
}
if (NULL != hProv)
{
CryptReleaseContext(hProv, 0);
}
return(hr);
}
HRESULT
EnumCertsInStore(
IN HCERTSTORE hStore,
IN DWORD Mode,
IN DWORD iCertSave,
OPTIONAL IN WCHAR const *pwszCertName,
IN DWORD cbHash,
OPTIONAL IN BYTE *pbHash,
OPTIONAL IN WCHAR const *pwszfnOut,
OPTIONAL IN WCHAR const *pwszPasswordArg,
IN OUT WCHAR **ppwszPassword,
OUT DWORD *pcCert)
{
HRESULT hr;
HRESULT hr2;
DWORD iCert;
CERT_CONTEXT const *pCert = NULL;
BSTR strSerialNumber = NULL;
*pcCert = 0;
hr2 = S_OK;
if (NULL != pwszCertName)
{
hr = myMakeSerialBstr(pwszCertName, &strSerialNumber);
_PrintIfError2(hr, "myMakeSerialBstr", hr);
}
for (iCert = 0; ; iCert++)
{
DWORD VerifyState;
BOOL fSigningKey;
BOOL fMatchingKey;
pCert = CertEnumCertificatesInStore(hStore, pCert);
if (NULL == pCert)
{
break;
}
if (MAXDWORD == iCertSave || iCert == iCertSave)
{
DWORD cb;
if (NULL != pwszCertName)
{
BOOL fMatch;
hr = myCertMatch(
pCert,
pwszCertName,
FALSE, // fAllowMissingCN
pbHash,
cbHash,
strSerialNumber,
&fMatch);
_PrintIfError(hr, "myCertMatch");
if (S_OK == hr2)
{
hr2 = hr;
}
if (S_OK != hr || !fMatch)
{
continue;
}
}
if (0 != *pcCert)
{
wprintf(wszNewLine);
}
wprintf(
myLoadResourceString(IDS_FORMAT_DUMP_CERT_INDEX), // "================ Certificate %d ================"
iCert);
wprintf(wszNewLine);
if (CertGetCertificateContextProperty(
pCert,
CERT_ARCHIVED_PROP_ID,
NULL,
&cb))
{
wprintf(myLoadResourceString(IDS_ARCHIVED)); // "Archived!"
wprintf(wszNewLine);
}
if ((iCert == iCertSave || NULL != pwszCertName) &&
NULL != pwszfnOut &&
(DVNS_SAVECERT & Mode))
{
hr = EncodeToFileW(
pwszfnOut,
pCert->pbCertEncoded,
pCert->cbCertEncoded,
CRYPT_STRING_BINARY | g_EncodeFlags);
_PrintIfError(hr, "EncodeToFileW");
if (S_OK == hr2)
{
hr2 = hr;
}
}
hr = cuDumpAsnBinary(
pCert->pbCertEncoded,
pCert->cbCertEncoded,
MAXDWORD);
_PrintIfError(hr, "cuDumpAsnBinary");
if (S_OK == hr2)
{
hr2 = hr;
}
if (DVNS_REPAIRKPI & Mode)
{
hr = cuFindCertificateKeyProvInfo(pCert);
_PrintIfError(hr, "cuFindCertificateKeyProvInfo");
if (S_OK == hr2)
{
hr2 = hr;
}
}
if ((DVNS_DUMPPROPERTIES & Mode) && !g_fQuiet)
{
hr = cuDumpCertProperties(pCert);
_PrintIfError(hr, "cuDumpCertProperties");
if (S_OK == hr2)
{
hr2 = hr;
}
}
if (DVNS_DUMPKEYS & Mode)
{
if (0 == (DVNS_DUMPPROPERTIES & Mode) || g_fQuiet)
{
hr = cuDumpCertKeyProviderInfo(
g_wszPad2,
pCert,
NULL,
NULL);
_PrintIfError(hr, "cuDumpCertKeyProviderInfo");
if (S_OK == hr2)
{
hr2 = hr;
}
}
hr = cuDumpPrivateKey(pCert, &fSigningKey, &fMatchingKey);
if (!IsHrSkipPrivateKey(hr))
{
if (S_OK != hr)
{
wprintf(myLoadResourceString(
fSigningKey?
IDS_SIGNATURE_BAD : // "Signature test FAILED"
IDS_ENCRYPTION_BAD)); // "Encryption test FAILED"
wprintf(wszNewLine);
_PrintError(hr, "cuDumpPrivateKey");
fMatchingKey = FALSE;
}
if (fMatchingKey)
{
wprintf(myLoadResourceString(
fSigningKey?
IDS_SIGNATURE_OK : // "Signature test passed"
IDS_ENCRYPTION_OK)); // "Encryption test passed"
wprintf(wszNewLine);
}
}
}
if (DVNS_VERIFYCERT & Mode)
{
hr = cuVerifyCertContext(
pCert,
(DVNS_CASTORE & Mode)? hStore : NULL,
0, // cApplicationPolicies
NULL, // apszApplicationPolicies
0, // cIssuancePolicies
NULL, // apszIssuancePolicies
FALSE, // fNTAuth
&VerifyState);
if (S_OK != hr)
{
cuPrintError(IDS_ERR_FORMAT_BAD_CERT, hr);
_PrintError(hr, "cuVerifyCertContext");
if (S_OK == hr2)
{
hr2 = hr; // Save first error
}
}
else if (0 == (VS_ERRORMASK & VerifyState))
{
wprintf(myLoadResourceString(IDS_CERT_VERIFIES)); // "Certificate is valid"
}
wprintf(wszNewLine);
}
if (DVNS_SAVEPFX & Mode)
{
hr = SavePFXToFile(
pCert,
pwszfnOut,
0 == *pcCert,
pwszPasswordArg,
ppwszPassword);
_PrintIfError(hr, "SavePFXToFile");
if (S_OK == hr2)
{
hr2 = hr;
}
}
if (DVNS_SAVEPVK & Mode)
{
hr = SavePVKToFile(pCert, pwszfnOut, 0 == *pcCert);
_PrintIfError(hr, "SavePVKToFile");
if (S_OK == hr2)
{
hr2 = hr;
}
}
(*pcCert)++;
}
}
hr = hr2;
_JumpIfError(hr, error, "EnumCertsInStore");
error:
if (NULL != pCert)
{
CertFreeCertificateContext(pCert);
}
if (NULL != strSerialNumber)
{
SysFreeString(strSerialNumber);
}
return(hr);
}
HRESULT
EnumCRLsInStore(
IN HCERTSTORE hStore,
IN DWORD Mode,
IN DWORD iCRLSave,
OPTIONAL IN WCHAR const *pwszCertName,
IN DWORD cbHash,
OPTIONAL IN BYTE *pbHash,
OPTIONAL IN WCHAR const *pwszfnOut,
OUT DWORD *pcCRL)
{
HRESULT hr;
HRESULT hr2;
DWORD iCRL;
CRL_CONTEXT const *pCRL = NULL;
*pcCRL = 0;
hr2 = S_OK;
for (iCRL = 0; ; iCRL++)
{
pCRL = CertEnumCRLsInStore(hStore, pCRL);
if (NULL == pCRL)
{
break;
}
if (MAXDWORD == iCRLSave || iCRL == iCRLSave)
{
if (NULL != pwszCertName)
{
BOOL fMatch;
hr = myCRLMatch(
pCRL,
pwszCertName,
FALSE, // fAllowMissingCN
pbHash,
cbHash,
&fMatch);
_PrintIfError(hr, "myCRLMatch");
if (S_OK == hr2)
{
hr2 = hr;
}
if (S_OK != hr || !fMatch)
{
continue;
}
}
if (0 != *pcCRL)
{
wprintf(wszNewLine);
}
wprintf(
myLoadResourceString(IDS_FORMAT_DUMP_CRL_INDEX), // "================ CRL %d ================"
iCRL);
wprintf(wszNewLine);
if ((iCRL == iCRLSave || NULL != pwszCertName) &&
NULL != pwszfnOut &&
(DVNS_SAVECRL & Mode))
{
hr = EncodeToFileW(
pwszfnOut,
pCRL->pbCrlEncoded,
pCRL->cbCrlEncoded,
CRYPT_STRING_BINARY | g_EncodeFlags);
_PrintIfError(hr, "EncodeToFileW");
if (S_OK == hr2)
{
hr2 = hr;
}
}
hr = cuDumpAsnBinary(
pCRL->pbCrlEncoded,
pCRL->cbCrlEncoded,
MAXDWORD);
_PrintIfError(hr, "cuDumpAsnBinary");
if (S_OK == hr2)
{
hr2 = hr;
}
if ((DVNS_DUMPPROPERTIES & Mode) && !g_fQuiet)
{
hr = cuDumpCRLProperties(pCRL);
_PrintIfError(hr, "cuDumpCRLProperties");
if (S_OK == hr2)
{
hr2 = hr;
}
}
(*pcCRL)++;
}
}
hr = hr2;
_JumpIfError(hr, error, "EnumCRLsInStore");
error:
if (NULL != pCRL)
{
CertFreeCRLContext(pCRL);
}
return(hr);
}
HRESULT
EnumCTLsInStore(
IN HCERTSTORE hStore,
IN DWORD Mode,
IN DWORD iCTLSave,
OPTIONAL IN WCHAR const *pwszCertName,
IN DWORD cbHash,
OPTIONAL IN BYTE *pbHash,
OPTIONAL IN WCHAR const *pwszfnOut,
OUT DWORD *pcCTL)
{
HRESULT hr;
HRESULT hr2;
DWORD iCTL;
CTL_CONTEXT const *pCTL = NULL;
*pcCTL = 0;
hr2 = S_OK;
for (iCTL = 0; ; iCTL++)
{
pCTL = CertEnumCTLsInStore(hStore, pCTL);
if (NULL == pCTL)
{
break;
}
if (MAXDWORD == iCTLSave || iCTL == iCTLSave)
{
DWORD cb;
if (NULL != pwszCertName)
{
BOOL fMatch;
hr = myCTLMatch(pCTL, pbHash, cbHash, &fMatch);
_PrintIfError(hr, "myCTLMatch");
if (S_OK == hr2)
{
hr2 = hr;
}
if (S_OK != hr || !fMatch)
{
continue;
}
}
if (0 != *pcCTL)
{
wprintf(wszNewLine);
}
wprintf(
myLoadResourceString(IDS_FORMAT_DUMP_CTL_INDEX), // "================ CTL %d ================"
iCTL);
wprintf(wszNewLine);
if (CertGetCTLContextProperty(
pCTL,
CERT_ARCHIVED_PROP_ID,
NULL,
&cb))
{
wprintf(myLoadResourceString(IDS_ARCHIVED)); // "Archived!"
wprintf(wszNewLine);
}
if ((iCTL == iCTLSave || NULL != pwszCertName) &&
NULL != pwszfnOut &&
(DVNS_SAVECTL & Mode))
{
hr = EncodeToFileW(
pwszfnOut,
pCTL->pbCtlEncoded,
pCTL->cbCtlEncoded,
CRYPT_STRING_BINARY | g_EncodeFlags);
_PrintIfError(hr, "EncodeToFileW");
if (S_OK == hr2)
{
hr2 = hr;
}
}
hr = cuDumpAsnBinary(
pCTL->pbCtlEncoded,
pCTL->cbCtlEncoded,
MAXDWORD);
_PrintIfError(hr, "cuDumpAsnBinary");
if (S_OK == hr2)
{
hr2 = hr;
}
if ((DVNS_DUMPPROPERTIES & Mode) && !g_fQuiet)
{
hr = cuDumpCTLProperties(pCTL);
_PrintIfError(hr, "cuDumpCTLProperties");
if (S_OK == hr2)
{
hr2 = hr;
}
}
#if 0
if (DVNS_VERIFYCERT & Mode)
{
hr = cuVerifyCertContext(
pCTL,
(DVNS_CASTORE & Mode)? hStore : NULL,
NULL, // apszPolicies
0, // cPolicies
FALSE, // fNTAuth
&VerifyState);
if (S_OK != hr)
{
cuPrintError(IDS_ERR_FORMAT_BAD_CTL, hr);
_PrintError(hr, "cuVerifyCertContext");
if (S_OK == hr2)
{
hr2 = hr; // Save first error
}
}
else
{
wprintf(myLoadResourceString(IDS_CTL_VERIFIES)); // "CTL is valid"
}
wprintf(wszNewLine);
}
#endif
(*pcCTL)++;
}
}
hr = hr2;
_JumpIfError(hr, error, "EnumCTLsInStore");
error:
if (NULL != pCTL)
{
CertFreeCTLContext(pCTL);
}
return(hr);
}
HRESULT
cuDumpAndVerifyStore(
IN HCERTSTORE hStore,
IN DWORD Mode,
OPTIONAL IN WCHAR const *pwszCertName,
IN DWORD iCertSave,
IN DWORD iCRLSave,
IN DWORD iCTLSave,
OPTIONAL IN WCHAR const *pwszfnOut,
OPTIONAL IN WCHAR const *pwszPasswordArg)
{
HRESULT hr;
HRESULT hr2;
BYTE *pbHash = NULL;
DWORD cbHash;
BOOL fVerboseOld = g_fVerbose;
BOOL fQuietOld = g_fQuiet;
WCHAR *pwszPassword = NULL;
DWORD cCert = 0;
DWORD cCRL = 0;
DWORD cCTL = 0;
if (g_fVerbose)
{
g_fVerbose--;
}
else
{
g_fQuiet = TRUE;
}
hr2 = S_OK;
if (NULL != pwszCertName)
{
hr = WszToMultiByteInteger(TRUE, pwszCertName, &cbHash, &pbHash);
_PrintIfError2(hr, "WszToMultiByteInteger", hr);
}
if (NULL != pwszCertName ||
MAXDWORD != iCertSave ||
(MAXDWORD == iCRLSave && MAXDWORD == iCTLSave))
{
hr = EnumCertsInStore(
hStore,
Mode,
iCertSave,
pwszCertName,
cbHash,
pbHash,
pwszfnOut,
pwszPasswordArg,
&pwszPassword,
&cCert);
_PrintIfError(hr, "EnumCertsInStore");
if (S_OK == hr2)
{
hr2 = hr;
}
}
if (NULL != pwszCertName ||
MAXDWORD != iCRLSave ||
(MAXDWORD == iCertSave && MAXDWORD == iCTLSave))
{
hr = EnumCRLsInStore(
hStore,
Mode,
iCRLSave,
pwszCertName,
cbHash,
pbHash,
pwszfnOut,
&cCRL);
_PrintIfError(hr, "EnumCRLsInStore");
if (S_OK == hr2)
{
hr2 = hr;
}
}
if (NULL != pwszCertName ||
MAXDWORD != iCTLSave ||
(MAXDWORD == iCertSave && MAXDWORD == iCRLSave))
{
hr = EnumCTLsInStore(
hStore,
Mode,
iCTLSave,
pwszCertName,
cbHash,
pbHash,
pwszfnOut,
&cCTL);
_PrintIfError(hr, "EnumCTLsInStore");
if (S_OK == hr2)
{
hr2 = hr;
}
}
hr = hr2;
if (S_OK == hr && NULL != pwszCertName && 0 == (cCert + cCRL + cCTL))
{
hr = NTE_NOT_FOUND;
_JumpError(hr, error, "cuDumpAndVerifyStore");
}
error:
g_fVerbose = fVerboseOld;
g_fQuiet = fQuietOld;
if (NULL != pbHash)
{
LocalFree(pbHash);
}
if (NULL != pwszPassword)
{
myZeroDataString(pwszPassword); // password data
LocalFree(pwszPassword);
}
return(hr);
}
// Reorder LDAP URL paramaters as per RFC 2255:
// Attribute list: ?attribute,...
// Scope: ?sub or ?one or ?base
// Search filter: ?objectClass=*,...
HRESULT
PatchLdapURL(
IN WCHAR const *pwszURLIn,
OUT WCHAR **ppwszURLOut)
{
HRESULT hr;
DWORD cParm;
DWORD iParm;
WCHAR *pwsz;
WCHAR *pwszT = NULL;
WCHAR *pwszURLOut = NULL;
WCHAR **apwsz = NULL;
*ppwszURLOut = NULL;
hr = myDupString(pwszURLIn, &pwszT);
_JumpIfError(hr, error, "myDupString");
pwsz = pwszT;
for (cParm = 0; ; cParm++)
{
pwsz = wcschr(pwsz, L'?');
if (NULL == pwsz)
{
break;
}
pwsz++;
}
if (1 < cParm)
{
apwsz = (WCHAR **) LocalAlloc(LMEM_FIXED, sizeof(apwsz[0]) * cParm);
if (NULL == apwsz)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
pwsz = pwszT;
for (iParm = 0; iParm < cParm; iParm++)
{
pwsz = wcschr(pwsz, L'?');
CSASSERT(NULL != pwsz);
*pwsz++ = L'\0';
apwsz[iParm] = pwsz;
}
CSASSERT(cParm == iParm);
CSASSERT(NULL == wcschr(pwsz, L'?'));
hr = myDupString(pwszURLIn, &pwszURLOut);
_JumpIfError(hr, error, "myDupString");
pwsz = wcschr(pwszURLOut, L'?');
if (NULL != pwsz)
{
DWORD i;
*pwsz = L'\0';
for (i = 0; i < 3; i++)
{
for (iParm = 0; iParm < cParm; iParm++)
{
BOOL fScope;
BOOL fFilter;
BOOL fCopy;
fScope =
0 == mylstrcmpiS(apwsz[iParm], &wszDSSUBSEARCH[1]) ||
0 == mylstrcmpiS(apwsz[iParm], &wszDSBASESEARCH[1]) ||
0 == mylstrcmpiS(apwsz[iParm], &wszDSONESEARCH[1]);
fFilter = NULL != wcschr(apwsz[iParm], L'=');
switch (i)
{
case 0: fCopy = !fScope && !fFilter; break;
case 1: fCopy = fScope; break;
default: fCopy = fFilter; break;
}
if (fCopy)
{
wcscat(pwszURLOut, L"?");
wcscat(pwszURLOut, apwsz[iParm]);
}
}
}
CSASSERT(wcslen(pwszURLOut) == wcslen(pwszURLIn));
// If the URL was reordered, return the patched URL.
if (0 != lstrcmp(pwszURLIn, pwszURLOut))
{
*ppwszURLOut = pwszURLOut;
pwszURLOut = NULL;
}
}
}
hr = NULL == *ppwszURLOut? S_FALSE : S_OK;
error:
if (NULL != apwsz)
{
LocalFree(apwsz);
}
if (NULL != pwszT)
{
LocalFree(pwszT);
}
if (NULL != pwszURLOut)
{
LocalFree(pwszURLOut);
}
return(hr);
}
#define wszLDAPCOLONSLASH L"ldap:/"
#define wszFMTLDAPPREFIX L"ldap://%ws/"
HRESULT
cuOpenCertStore(
IN WCHAR const *pwszStoreName,
IN OUT DWORD *pMode,
OPTIONAL OUT WCHAR **ppwszStoreNameOut,
OUT HCERTSTORE *phStore)
{
HRESULT hr;
WCHAR awcLdap[ARRAYSIZE(wszLDAPCOLONSLASH)];
LPCSTR pszStoreProvider = CERT_STORE_PROV_SYSTEM_REGISTRY_W;
WCHAR *pwszStoreAlloc = NULL;
WCHAR *pwszStoreAlloc2 = NULL;
WCHAR *pwszStoreNameOut = NULL;
if (NULL != ppwszStoreNameOut)
{
*ppwszStoreNameOut = NULL;
}
if (NULL == pwszStoreName ||
0 == wcscmp(L"*", pwszStoreName) ||
0 == LSTRCMPIS(pwszStoreName, wszCA_CERTSTORE))
{
pwszStoreName = wszCA_CERTSTORE;
*pMode |= DVNS_CASTORE;
}
wcsncpy(awcLdap, pwszStoreName, ARRAYSIZE(awcLdap) - 1);
awcLdap[ARRAYSIZE(awcLdap) - 1] = L'\0';
if (0 == LSTRCMPIS(awcLdap, wszLDAPCOLONSLASH))
{
pszStoreProvider = CERT_STORE_PROV_LDAP_W;
*pMode |= DVNS_DSSTORE;
}
else
{
CSASSERT(3 < ARRAYSIZE(awcLdap));
awcLdap[3] = L'\0';
if (0 == LSTRCMPIS(awcLdap, L"CN="))
{
DWORD cwc = WSZARRAYSIZE(wszFMTLDAPPREFIX) + wcslen(pwszStoreName);
if (NULL != g_pwszDC)
{
cwc += wcslen (g_pwszDC);
}
pwszStoreAlloc = (WCHAR *) LocalAlloc(
LMEM_FIXED,
(cwc + 1) * sizeof(WCHAR));
if (NULL == pwszStoreAlloc)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
swprintf(
pwszStoreAlloc,
wszFMTLDAPPREFIX,
NULL != g_pwszDC? g_pwszDC : g_wszEmpty);
wcscat(pwszStoreAlloc, pwszStoreName);
pwszStoreName = pwszStoreAlloc;
pszStoreProvider = CERT_STORE_PROV_LDAP_W;
*pMode |= DVNS_DSSTORE;
}
}
if (DVNS_DSSTORE & *pMode)
{
hr = PatchLdapURL(pwszStoreName, &pwszStoreAlloc2);
if (S_FALSE != hr)
{
_JumpIfError(hr, error, "PatchLdapURL");
pwszStoreName = pwszStoreAlloc2;
}
}
if (NULL != ppwszStoreNameOut)
{
hr = myDupString(pwszStoreName, &pwszStoreNameOut);
_JumpIfError(hr, error, "myDupString");
}
if ((DVNS_DSSTORE & *pMode) &&
0 == ((DVNS_REPAIRKPI | DVNS_WRITESTORE) & *pMode))
{
wprintf(L"%ws\n", pwszStoreName);
*phStore = myUrlCertOpenStore(
CRYPT_WIRE_ONLY_RETRIEVAL |
CRYPT_RETRIEVE_MULTIPLE_OBJECTS,
pwszStoreName);
if (NULL == *phStore)
{
hr = myHLastError();
_PrintErrorStr(hr, "myUrlCertOpenStore", pwszStoreName);
if (CRYPT_E_NOT_FOUND != hr)
{
_JumpError(hr, error, "myUrlCertOpenStore");
}
}
}
if (NULL == *phStore)
{
*phStore = CertOpenStore(
pszStoreProvider,
X509_ASN_ENCODING,
NULL, // hProv
CERT_STORE_NO_CRYPT_RELEASE_FLAG |
CERT_STORE_ENUM_ARCHIVED_FLAG |
(((DVNS_REPAIRKPI | DVNS_WRITESTORE) & *pMode)?
0 : CERT_STORE_READONLY_FLAG) |
(g_fForce? 0 : CERT_STORE_OPEN_EXISTING_FLAG) |
cuGetSystemStoreFlags(),
pwszStoreName);
if (NULL == *phStore)
{
hr = myHLastError();
_JumpErrorStr(hr, error, "CertOpenStore", pwszStoreName);
}
}
if (NULL != ppwszStoreNameOut)
{
*ppwszStoreNameOut = pwszStoreNameOut;
pwszStoreNameOut = NULL;
}
hr = S_OK;
error:
if (NULL != pwszStoreAlloc)
{
LocalFree(pwszStoreAlloc);
}
if (NULL != pwszStoreAlloc2)
{
LocalFree(pwszStoreAlloc2);
}
if (NULL != pwszStoreNameOut)
{
LocalFree(pwszStoreNameOut);
}
return(hr);
}
HRESULT
DumpAndVerifyNamedStore(
IN WCHAR const *pwszStoreName,
IN DWORD Mode,
OPTIONAL IN WCHAR const *pwszCertName,
IN DWORD iCertSave,
IN DWORD iCRLSave,
IN DWORD iCTLSave,
OPTIONAL IN WCHAR const *pwszfnOut,
OPTIONAL IN WCHAR const *pwszPassword)
{
HRESULT hr;
HCERTSTORE hStore = NULL;
hr = cuOpenCertStore(pwszStoreName, &Mode, NULL, &hStore);
_JumpIfError(hr, error, "cuOpenCertStore");
hr = cuDumpAndVerifyStore(
hStore,
Mode,
pwszCertName,
iCertSave,
iCRLSave,
iCTLSave,
pwszfnOut,
pwszPassword);
_JumpIfError(hr, error, "cuDumpAndVerifyStore");
error:
if (NULL != hStore)
{
CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
}
return(hr);
}
HRESULT
myDupStringN(
IN WCHAR const *pwszIn,
IN DWORD cwc,
OUT WCHAR **ppwszOut)
{
HRESULT hr;
CSASSERT(wcslen(pwszIn) >= cwc);
*ppwszOut = (WCHAR *) LocalAlloc(LMEM_FIXED, (cwc + 1) * sizeof(WCHAR));
if (NULL == *ppwszOut)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
CopyMemory(*ppwszOut, pwszIn, cwc * sizeof(WCHAR));
(*ppwszOut)[cwc] = L'\0';
hr = S_OK;
error:
return(hr);
}
#define URLI_DC 0
#define URLI_DN 1
#define URLI_ATTRIBUTE 2
#define URLI_SCOPE 3
#define URLI_CLASS 4
#define URLI_MAX 5
HRESULT
ParseLdapUrl(
IN WCHAR const *pwszIn,
OUT WCHAR *ppwszOut[URLI_MAX])
{
HRESULT hr;
WCHAR *pwszAlloc = NULL;
WCHAR awcLdap[ARRAYSIZE(wszLDAPCOLONSLASH)];
DWORD cSlash;
WCHAR const *pwsz;
DWORD i;
ZeroMemory(ppwszOut, URLI_MAX * sizeof(*ppwszOut));
wcsncpy(awcLdap, pwszIn, ARRAYSIZE(awcLdap) - 1);
awcLdap[ARRAYSIZE(awcLdap) - 1] = L'\0';
if (0 != LSTRCMPIS(awcLdap, wszLDAPCOLONSLASH))
{
hr = E_INVALIDARG;
_JumpError(hr, error, "ldap:URL");
}
hr = myInternetUncanonicalizeURL(pwszIn, &pwszAlloc);
_JumpIfError(hr, error, "myInternetUncanonicalizeURL");
pwszIn = pwszAlloc;
pwszIn += WSZARRAYSIZE(wszLDAPCOLONSLASH);
cSlash = 1;
while (L'/' == *pwszIn)
{
pwszIn++;
cSlash++;
}
if (2 == cSlash)
{
pwsz = pwszIn;
while (L'\0' != *pwszIn && L'/' != *pwszIn)
{
pwszIn++;
}
hr = myDupStringN(
pwsz,
SAFE_SUBTRACT_POINTERS(pwszIn, pwsz),
&ppwszOut[0]);
_JumpIfError(hr, error, "myDupStringN");
if (L'\0' != *pwszIn)
{
pwszIn++;
}
}
for (i = 1; i < URLI_MAX; i++)
{
pwsz = pwszIn;
while (L'\0' != *pwszIn && L'?' != *pwszIn)
{
pwszIn++;
}
hr = myDupStringN(
pwsz,
SAFE_SUBTRACT_POINTERS(pwszIn, pwsz),
&ppwszOut[i]);
_JumpIfError(hr, error, "myDupStringN");
if (L'\0' == *pwszIn)
{
break;
}
pwszIn++;
}
hr = S_OK;
error:
for (i = 0; i < ARRAYSIZE(ppwszOut); i++)
{
wprintf(L"DeleteLastLdapValue[%u](%ws)\n", i, ppwszOut[i]);
}
if (S_OK != hr)
{
for (i = 0; i < URLI_MAX; i++)
{
if (NULL != ppwszOut[i])
{
LocalFree(ppwszOut[i]);
ppwszOut[i] = NULL;
}
}
}
if (NULL != pwszAlloc)
{
LocalFree(pwszAlloc);
}
return(hr);
}
HRESULT
myLdapDeleteLastValue(
IN LDAP *pld,
IN WCHAR const *pwszDN,
IN WCHAR const *pwszAttribute,
OPTIONAL IN BYTE const *pb,
IN DWORD cb,
OUT DWORD *pdwDisposition,
OPTIONAL OUT WCHAR **ppwszError)
{
HRESULT hr;
DWORD cres;
DWORD cber;
DWORD iber;
DWORD i;
LDAP_TIMEVAL timeval;
LDAPMessage *pmsg = NULL;
LDAPMessage *pres;
WCHAR *apwszAttrs[2];
struct berval **ppberval = NULL;
struct berval *rgpberVals[2];
struct berval certberval;
LDAPMod *mods[2];
LDAPMod certmod;
char chZero = '\0';
*pdwDisposition = LDAP_OTHER;
if (NULL != ppwszError)
{
*ppwszError = NULL;
}
apwszAttrs[0] = const_cast<WCHAR *>(pwszAttribute);
apwszAttrs[1] = NULL;
timeval.tv_sec = csecLDAPTIMEOUT;
timeval.tv_usec = 0;
hr = ldap_search_st(
pld, // ld
const_cast<WCHAR *>(pwszDN), // base
LDAP_SCOPE_BASE, // scope
NULL, // filter
apwszAttrs, // attrs
FALSE, // attrsonly
&timeval, // timeout
&pmsg); // res
if (S_OK != hr)
{
*pdwDisposition = hr;
hr = myHLdapError(pld, hr, NULL);
_JumpErrorStr(hr, error, "ldap_search_st", pwszDN);
}
cres = ldap_count_entries(pld, pmsg);
if (1 != cres)
{
// Exactly one entry was not found.
hr = NTE_NOT_FOUND;
_JumpError(hr, error, "ldap_count_entries");
}
pres = ldap_first_entry(pld, pmsg);
if (NULL == pres)
{
hr = NTE_NOT_FOUND;
_JumpError(hr, error, "ldap_first_entry");
}
ppberval = ldap_get_values_len(
pld,
pres,
const_cast<WCHAR *>(pwszAttribute));
hr = NTE_NOT_FOUND;
if (NULL == ppberval)
{
_JumpError(hr, error, "ppberval");
}
cber = 0;
while (NULL != ppberval[cber])
{
cber++;
}
if (NULL != pb)
{
if (1 != cber)
{
_JumpError(hr, error, "cber");
}
if (ppberval[0]->bv_len != cb ||
0 != memcmp(ppberval[0]->bv_val, pb, cb))
{
_JumpError(hr, error, "memcmp");
}
}
// set disposition assuming there's nothing to do:
*pdwDisposition = LDAP_ATTRIBUTE_OR_VALUE_EXISTS;
mods[0] = &certmod;
mods[1] = NULL;
certmod.mod_op = LDAP_MOD_BVALUES | LDAP_MOD_REPLACE;
certmod.mod_type = const_cast<WCHAR *>(pwszAttribute);
certmod.mod_bvalues = rgpberVals;
rgpberVals[0] = &certberval;
rgpberVals[1] = NULL;
certberval.bv_val = &chZero;
certberval.bv_len = sizeof(chZero);
hr = ldap_modify_ext_s(
pld,
const_cast<WCHAR *>(pwszDN), // base
mods,
NULL,
NULL);
*pdwDisposition = hr;
if (hr != S_OK)
{
hr = myHLdapError(pld, hr, ppwszError);
_JumpError(hr, error, "ldap_modify_ext_s");
}
hr = S_OK;
error:
if (NULL != ppberval)
{
ldap_value_free_len(ppberval);
}
if (NULL != pmsg)
{
ldap_msgfree(pmsg);
}
return(hr);
}
HRESULT
DeleteLastLdapValue(
IN WCHAR const *pwszURL,
OPTIONAL IN BYTE const *pb,
IN DWORD cb)
{
HRESULT hr;
WCHAR *rgpwsz[URLI_MAX];
DWORD i;
DWORD dwDisposition;
WCHAR *pwszError = NULL;
LDAP *pld = NULL;
ZeroMemory(rgpwsz, sizeof(rgpwsz));
hr = ParseLdapUrl(pwszURL, rgpwsz);
_JumpIfErrorStr(hr, error, "ParseLdapUrl", pwszURL);
if (NULL != rgpwsz[URLI_SCOPE] &&
0 != mylstrcmpiS(rgpwsz[URLI_SCOPE], &wszDSBASESEARCH[1]))
{
hr = E_INVALIDARG;
_JumpErrorStr(hr, error, "ldap scope", rgpwsz[URLI_SCOPE]);
}
hr = myLdapOpen(rgpwsz[URLI_DC], 0, &pld, NULL, NULL);
_JumpIfError(hr, error, "myLdapOpen");
hr = myLdapDeleteLastValue(
pld,
rgpwsz[URLI_DN],
rgpwsz[URLI_ATTRIBUTE],
pb,
cb,
&dwDisposition,
&pwszError);
_JumpIfErrorStr(hr, error, "myLdapDeleteLastValue", pwszError);
error:
if (NULL != pwszError)
{
LocalFree(pwszError);
}
for (i = 0; i < ARRAYSIZE(rgpwsz); i++)
{
if (NULL != rgpwsz[i])
{
wprintf(L"DeleteLastLdapValue[%u](%ws)\n", i, rgpwsz[i]);
LocalFree(rgpwsz[i]);
}
}
myLdapClose(pld, NULL, NULL);
return(hr);
}
HRESULT
CommitStore(
IN HCERTSTORE hStore,
IN WCHAR const *pwszStoreName,
IN DWORD Mode,
OPTIONAL IN BYTE const *pb,
IN DWORD cb)
{
HRESULT hr;
if (!CertControlStore(hStore, 0, CERT_STORE_CTRL_COMMIT, NULL))
{
// Add workaround for LdapMapErrorToWin32 incorrect mapping
// LDAP_OBJECT_CLASS_VIOLATION -> E_INVALIDARG. Mapping it to
// the correct code should be pretty safe, CertControlStore
// shouldn't otherwise fail with this error code since we know
// our code passes the right parameters.
hr = myHLastError();
_PrintError(hr, "CertControlStore");
if (DVNS_DSSTORE & Mode)
{
if (E_INVALIDARG == HRESULT_FROM_WIN32(hr))
{
hr = HRESULT_FROM_WIN32(ERROR_DS_OBJ_CLASS_VIOLATION);
_PrintError(hr, "CertControlStore");
}
if (HRESULT_FROM_WIN32(ERROR_DS_OBJ_CLASS_VIOLATION) == hr)
{
hr = DeleteLastLdapValue(pwszStoreName, pb, cb);
_JumpIfError(hr, error, "DeleteLastLdapValue");
}
}
_JumpIfError(hr, error, "CertControlStore");
}
hr = S_OK;
error:
return(hr);
}
HRESULT
verbViewOrDeleteStore(
IN WCHAR const *pwszOption,
OPTIONAL IN WCHAR const *pwszStoreName,
OPTIONAL IN WCHAR const *pwszCertId,
OPTIONAL IN WCHAR const *pwszfnOut,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
WCHAR *pwszCertName = NULL;
WCHAR *pwszStoreNameNew = NULL;
DWORD Mode;
DWORD iCert;
DWORD iCRL;
DWORD iCTL;
HCERTSTORE hStore = NULL;
CERT_CONTEXT const *pCert = NULL;
CERT_CONTEXT const *pCertDeleted = NULL;
BOOL fDelete = g_wszViewDelStore == pwszOption;
WCHAR *pwszSubject = NULL;
hr = ParseCertCRLIndex(pwszCertId, &pwszCertName, &iCert, &iCRL, &iCTL);
_JumpIfErrorStr(hr, error, "ParseCertCRLIndex", pwszCertId);
Mode = DVNS_SAVECERT;
if (fDelete)
{
Mode |= DVNS_WRITESTORE;
}
hr = cuOpenCertStore(pwszStoreName, &Mode, &pwszStoreNameNew, &hStore);
_JumpIfError(hr, error, "cuOpenCertStore");
hr = myGetCertificateFromPicker(
g_hInstance, // hInstance
NULL, // hwndParent
IDS_VIEWSTORE_TITLE, // idTitle
fDelete? IDS_VIEWSTORE_SUBTITLE_DELETE :
IDS_VIEWSTORE_SUBTITLE, // idSubTitle
0, // dwFlags -- CUCS_*
pwszCertName, // pwszCommonName
1, // cStore
&hStore, // rghStore
0, // cpszObjId
NULL, // apszObjId
&pCert); // ppCert
_JumpIfError(hr, error, "myGetCertificateFromPicker");
if (NULL != pCert)
{
hr = myCertNameToStr(
X509_ASN_ENCODING,
&pCert->pCertInfo->Subject,
CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
&pwszSubject);
_JumpIfError(hr, error, "myCertNameToStr");
if (NULL != pwszfnOut)
{
hr = EncodeToFileW(
pwszfnOut,
pCert->pbCertEncoded,
pCert->cbCertEncoded,
CRYPT_STRING_BINARY | g_EncodeFlags);
_JumpIfError(hr, error, "EncodeToFileW");
wprintf(
myLoadResourceString(
IDS_FORMAT_SAVED_CERT_NAME), // "Saved certificate %ws"
pwszSubject);
wprintf(L": %ws\n", pwszfnOut);
}
if (fDelete)
{
pCertDeleted = CertDuplicateCertificateContext(pCert);
if (!CertDeleteCertificateFromStore(pCert))
{
hr = myHLastError();
_JumpError(hr, error, "CertDeleteCertificateFromStore");
}
pCert = NULL;
hr = CommitStore(
hStore,
pwszStoreNameNew,
Mode,
pCertDeleted->pbCertEncoded,
pCertDeleted->cbCertEncoded);
_JumpIfError(hr, error, "CommitStore");
wprintf(
myLoadResourceString(
IDS_FORMAT_DELETED_CERT_NAME), // "Deleted certificate %ws"
pwszSubject);
wprintf(wszNewLine);
}
}
hr = S_OK;
error:
if (NULL != pwszSubject)
{
LocalFree(pwszSubject);
}
if (NULL != pwszCertName)
{
LocalFree(pwszCertName);
}
if (NULL != pwszStoreNameNew)
{
LocalFree(pwszStoreNameNew);
}
if (NULL != pCert)
{
CertFreeCertificateContext(pCert);
}
if (NULL != pCertDeleted)
{
CertFreeCertificateContext(pCertDeleted);
}
if (NULL != hStore)
{
CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
}
return(hr);
}
HRESULT
verbStore(
IN WCHAR const *pwszOption,
IN WCHAR const *pwszStoreName,
IN WCHAR const *pwszCertId,
IN WCHAR const *pwszfnOut,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
WCHAR *pwszCertName = NULL;
DWORD iCert;
DWORD iCRL;
DWORD iCTL;
hr = ParseCertCRLIndex(pwszCertId, &pwszCertName, &iCert, &iCRL, &iCTL);
_JumpIfErrorStr(hr, error, "ParseCertCRLIndex", pwszCertId);
hr = DumpAndVerifyNamedStore(
pwszStoreName,
DVNS_SAVECERT |
DVNS_SAVECRL |
DVNS_SAVECTL |
DVNS_DUMP |
DVNS_DUMPKEYS |
DVNS_DUMPPROPERTIES,
pwszCertName,
iCert,
iCRL,
iCTL,
pwszfnOut,
NULL);
_JumpIfError(hr, error, "DumpAndVerifyNamedStore");
error:
if (NULL != pwszCertName)
{
LocalFree(pwszCertName);
}
return(hr);
}
HRESULT
DisplayAddResult(
OPTIONAL IN CERT_NAME_BLOB const *pName,
IN DWORD Index,
IN DWORD idsMsg)
{
HRESULT hr = S_OK;
WCHAR *pwszName = NULL;
WCHAR wszIndex[cwcDWORDSPRINTF];
if (NULL != pName)
{
hr = myCertNameToStr(
X509_ASN_ENCODING,
pName,
CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
&pwszName);
_JumpIfError(hr, error, "myCertNameToStr");
}
else
{
swprintf(wszIndex, L"%u", Index);
}
wprintf(myLoadResourceString(idsMsg), NULL != pName? pwszName : wszIndex);
wprintf(wszNewLine);
error:
if (NULL != pwszName)
{
LocalFree(pwszName);
}
return(hr);
}
HRESULT
AddCertToStore(
IN HCERTSTORE hStore,
IN WCHAR const *pwszStoreName,
IN CERT_CONTEXT const *pccAdd,
IN DWORD Index)
{
HRESULT hr;
BOOL fRoot = FALSE;
CERT_CONTEXT const *pcc = NULL;
DWORD cDup;
DWORD cDisplay;
DWORD i;
if (CertCompareCertificateName(
X509_ASN_ENCODING,
&pccAdd->pCertInfo->Issuer,
&pccAdd->pCertInfo->Subject))
{
hr = cuVerifySignature(
pccAdd->pbCertEncoded,
pccAdd->cbCertEncoded,
&pccAdd->pCertInfo->SubjectPublicKeyInfo,
FALSE,
FALSE);
fRoot = S_OK == hr;
_PrintIfError(hr, "cuVerifySignature");
}
if (0 == LSTRCMPIS(pwszStoreName, wszROOT_CERTSTORE) &&
!fRoot &&
!g_fForce)
{
wprintf(myLoadResourceString(IDS_ROOT_STORE_NEEDS_ROOT_CERT)); // "Cannot add a non-root certificate to the root store"
wprintf(wszNewLine);
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "Non-root cert");
}
cDup = 0;
cDisplay = 0;
for (i = 0; ; i++)
{
pcc = CertEnumCertificatesInStore(hStore, pcc);
if (NULL == pcc)
{
break;
}
// Skip Certs for other Subjects
if (!CertCompareCertificateName(
X509_ASN_ENCODING,
&pcc->pCertInfo->Issuer,
&pccAdd->pCertInfo->Issuer))
{
continue;
}
// Skip Certs with different public keys
if (!CertComparePublicKeyInfo(
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
&pcc->pCertInfo->SubjectPublicKeyInfo,
&pccAdd->pCertInfo->SubjectPublicKeyInfo))
{
continue;
}
if (0 == cDisplay++)
{
wprintf(myLoadResourceString(IDS_RELATED_CERTS_COLON)); // "Related Certificates:"
wprintf(wszNewLine);
}
wprintf(wszNewLine);
// Remember if an exact match exists
if (pcc->cbCertEncoded == pccAdd->cbCertEncoded &&
0 == memcmp(
pcc->pbCertEncoded,
pccAdd->pbCertEncoded,
pcc->cbCertEncoded))
{
cDup++;
wprintf(myLoadResourceString(IDS_EXACT_MATCH_COLON)); // "Exact match:"
wprintf(wszNewLine);
}
hr = cuDumpAsnBinaryQuiet(
pcc->pbCertEncoded,
pcc->cbCertEncoded,
i);
_PrintIfError(hr, "cuDumpAsnBinaryQuiet");
}
if (0 == cDup)
{
if (!CertAddCertificateContextToStore(
hStore,
pccAdd,
CERT_STORE_ADD_ALWAYS,
NULL))
{
hr = myHLastError();
_JumpError(hr, error, "CertAddCertificateContextToStore");
}
}
else
{
wprintf(wszNewLine);
}
hr = DisplayAddResult(
&pccAdd->pCertInfo->Subject,
Index,
0 != cDup?
IDS_FORMAT_CERT_ALREADY_IN_STORE : // "Certificate ""%ws"" already in store."
IDS_FORMAT_CERT_ADDED_TO_STORE); // "Certificate ""%ws"" added to store."
_JumpIfError(hr, error, "DisplayAddResult");
error:
if (NULL != pcc)
{
CertFreeCertificateContext(pcc);
}
return(hr);
}
HRESULT
AddCRLToStore(
IN HCERTSTORE hStore,
IN CRL_CONTEXT const *pCRLAdd,
IN DWORD Index)
{
HRESULT hr;
CRL_CONTEXT const *pCRL = NULL;
DWORD cDup;
DWORD cDisplay;
BOOL fDeltaAdd;
BOOL fDelta;
DWORD NameId;
DWORD NameIdAdd;
DWORD i;
hr = myIsDeltaCRL(pCRLAdd, &fDeltaAdd);
_JumpIfError(hr, error, "myIsDeltaCRL");
hr = myGetCRLNameId(pCRLAdd, &NameIdAdd);
_PrintIfError2(hr, "DisplayAddResult", hr);
cDup = 0;
cDisplay = 0;
for (i = 0; ; i++)
{
pCRL = CertEnumCRLsInStore(hStore, pCRL);
if (NULL == pCRL)
{
break;
}
hr = myIsDeltaCRL(pCRL, &fDelta);
_JumpIfError(hr, error, "myIsDeltaCRL");
// Skip base or delta CRLs when we're looking for the other.
if (fDeltaAdd ^ fDelta)
{
continue;
}
// Skip CRLs for other Issuers
if (!CertCompareCertificateName(
X509_ASN_ENCODING,
&pCRL->pCrlInfo->Issuer,
&pCRLAdd->pCrlInfo->Issuer))
{
continue;
}
hr = myGetCRLNameId(pCRL, &NameId);
_PrintIfError2(hr, "DisplayAddResult", hr);
// Skip CRLs for different CA keys
if (MAXDWORD != NameIdAdd && MAXDWORD != NameId)
{
if (CANAMEIDTOIKEY(NameIdAdd) != CANAMEIDTOIKEY(NameId))
{
continue;
}
}
if (0 == cDisplay++)
{
wprintf(myLoadResourceString(IDS_RELATED_CRLS_COLON)); // "Related CRLs:"
wprintf(wszNewLine);
}
wprintf(wszNewLine);
// Remember if an exact match exists
if (pCRL->cbCrlEncoded == pCRLAdd->cbCrlEncoded &&
0 == memcmp(
pCRL->pbCrlEncoded,
pCRLAdd->pbCrlEncoded,
pCRL->cbCrlEncoded))
{
cDup++;
wprintf(myLoadResourceString(IDS_EXACT_MATCH_COLON)); // "Exact match:"
wprintf(wszNewLine);
}
hr = cuDumpAsnBinaryQuiet(
pCRL->pbCrlEncoded,
pCRL->cbCrlEncoded,
i);
_PrintIfError(hr, "cuDumpAsnBinaryQuiet");
}
if (0 == cDup)
{
if (!CertAddCRLContextToStore(
hStore,
pCRLAdd,
CERT_STORE_ADD_ALWAYS,
NULL))
{
hr = myHLastError();
_JumpError(hr, error, "CertAddCRLContextToStore");
}
}
else
{
wprintf(wszNewLine);
}
hr = DisplayAddResult(
&pCRLAdd->pCrlInfo->Issuer,
Index,
0 != cDup?
IDS_FORMAT_CRL_ALREADY_IN_STORE : // "CRL ""%ws"" already in store."
IDS_FORMAT_CRL_ADDED_TO_STORE); // "CRL ""%ws"" added to store."
_JumpIfError(hr, error, "DisplayAddResult");
error:
if (NULL != pCRL)
{
CertFreeCRLContext(pCRL);
}
return(hr);
}
HRESULT
AddCTLToStore(
IN HCERTSTORE hStore,
IN CTL_CONTEXT const *pCTL,
IN DWORD Index)
{
HRESULT hr;
BOOL fDup = FALSE;
if (!CertAddCTLContextToStore(hStore, pCTL, CERT_STORE_ADD_NEW, NULL))
{
hr = myHLastError();
if (CRYPT_E_EXISTS != hr)
{
_JumpError(hr, error, "CertAddCTLContextToStore");
}
fDup = TRUE;
}
hr = DisplayAddResult(
NULL,
Index,
fDup?
IDS_FORMAT_CTL_ALREADY_IN_STORE : // "CTL ""%ws"" already in store."
IDS_FORMAT_CTL_ADDED_TO_STORE); // "CTL ""%ws"" added to store."
_JumpIfError(hr, error, "DisplayAddResult");
error:
return(hr);
}
HRESULT
AddCertToStoreFromFile(
IN HCERTSTORE hStore,
IN WCHAR const *pwszStoreName,
IN WCHAR const *pwszfnIn,
OUT BOOL *pfBadAsn)
{
HRESULT hr;
CERT_CONTEXT const *pCert = NULL;
BOOL fRoot = FALSE;
*pfBadAsn = FALSE;
// Load and decode certificate
hr = cuLoadCert(pwszfnIn, &pCert);
if (CRYPT_E_ASN1_BADTAG == hr)
{
*pfBadAsn = TRUE;
}
_JumpIfError(hr, error, "cuLoadCert");
hr = AddCertToStore(hStore, pwszStoreName, pCert, 0);
_JumpIfError(hr, error, "AddCertToStore");
error:
cuUnloadCert(&pCert);
return(hr);
}
HRESULT
AddCRLToStoreFromFile(
IN HCERTSTORE hStore,
IN WCHAR const *pwszfnIn,
OUT BOOL *pfBadAsn)
{
HRESULT hr;
CRL_CONTEXT const *pCRL = NULL;
*pfBadAsn = FALSE;
hr = cuLoadCRL(pwszfnIn, &pCRL);
if (CRYPT_E_ASN1_BADTAG == hr)
{
*pfBadAsn = TRUE;
}
_JumpIfError(hr, error, "cuLoadCRL");
hr = AddCRLToStore(hStore, pCRL, 0);
_JumpIfError(hr, error, "AddCRLToStore");
error:
cuUnloadCRL(&pCRL);
return(hr);
}
HRESULT
AddPKCS7ToStoreFromFile(
IN HCERTSTORE hStore,
IN WCHAR const *pwszStoreName,
IN WCHAR const *pwszfnIn)
{
HRESULT hr;
BYTE *pb = NULL;
DWORD cb;
HCERTSTORE hStorePKCS7 = NULL;
DWORD i;
CERT_CONTEXT const *pCert = NULL;
CRL_CONTEXT const *pCRL = NULL;
CTL_CONTEXT const *pCTL = NULL;
hr = DecodeFileW(pwszfnIn, &pb, &cb, CRYPT_STRING_ANY);
if (S_OK != hr)
{
cuPrintError(IDS_ERR_FORMAT_DECODEFILE, hr);
goto error;
}
hr = myDecodePKCS7(
pb,
cb,
NULL, // ppbContents
NULL, // pcbContents
NULL, // pdwMsgType
NULL, // ppszInnerContentObjId
NULL, // pcSigner
NULL, // pcRecipient
&hStore,
NULL); // phMsg
_JumpIfError(hr, error, "myDecodePKCS7");
for (i = 0; ; i++)
{
pCert = CertEnumCertificatesInStore(hStore, pCert);
if (NULL == pCert)
{
break;
}
hr = AddCertToStore(hStore, pwszStoreName, pCert, i);
_JumpIfError(hr, error, "AddCertToStore");
}
for (i = 0; ; i++)
{
pCRL = CertEnumCRLsInStore(hStore, pCRL);
if (NULL == pCRL)
{
break;
}
hr = AddCRLToStore(hStore, pCRL, i);
_JumpIfError(hr, error, "AddCRLToStore");
}
for (i = 0; ; i++)
{
pCTL = CertEnumCTLsInStore(hStore, pCTL);
if (NULL == pCTL)
{
break;
}
hr = AddCTLToStore(hStore, pCTL, i);
_JumpIfError(hr, error, "AddCTLToStore");
}
hr = S_OK;
error:
if (NULL != pCert)
{
CertFreeCertificateContext(pCert);
}
if (NULL != pCRL)
{
CertFreeCRLContext(pCRL);
}
if (NULL != pCTL)
{
CertFreeCTLContext(pCTL);
}
if (NULL != hStorePKCS7)
{
CertCloseStore(hStorePKCS7, CERT_CLOSE_STORE_CHECK_FLAG);
}
if (NULL != pb)
{
LocalFree(pb);
}
return(hr);
}
HRESULT
verbAddStore(
IN WCHAR const *pwszOption,
IN WCHAR const *pwszStoreName,
IN WCHAR const *pwszfnIn,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
DWORD Mode;
HCERTSTORE hStore = NULL;
BOOL fBadAsn;
Mode = DVNS_WRITESTORE; // force open for write
hr = cuOpenCertStore(pwszStoreName, &Mode, NULL, &hStore);
if (S_OK != hr)
{
wprintf(
myLoadResourceString(
g_fForce?
IDS_CANNOT_CREATE_STORE : // "Cannot open Cert store."
IDS_CANNOT_OPEN_STORE),
L"-f"); // "Cannot open existing Cert store. Use %ws switch to force Cert store creation."
wprintf(wszNewLine);
_JumpErrorStr(hr, error, "cuOpenCertStore", pwszStoreName);
}
hr = AddCertToStoreFromFile(hStore, pwszStoreName, pwszfnIn, &fBadAsn);
if (S_OK != hr)
{
if (!fBadAsn)
{
_JumpError(hr, error, "AddCertToStoreFromFile");
}
hr = AddCRLToStoreFromFile(hStore, pwszfnIn, &fBadAsn);
if (S_OK != hr)
{
if (!fBadAsn)
{
_JumpError(hr, error, "AddCRLToStoreFromFile");
}
hr = AddPKCS7ToStoreFromFile(hStore, pwszStoreName, pwszfnIn);
_JumpIfError(hr, error, "AddPKCS7ToStoreFromFile");
}
}
CSASSERT(S_OK == hr);
error:
if (NULL != hStore)
{
CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
}
return(hr);
}
HRESULT
SaveFirstBlob(
IN BYTE const *pbEncoded,
IN DWORD cbEncoded,
IN OUT BYTE **ppbDeleted,
IN OUT DWORD *pcbDeleted)
{
HRESULT hr;
if (NULL == *ppbDeleted)
{
*pcbDeleted = cbEncoded;
*ppbDeleted = (BYTE *) LocalAlloc(LMEM_FIXED, cbEncoded);
if (NULL == *ppbDeleted)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
CopyMemory(*ppbDeleted, pbEncoded, cbEncoded);
}
hr = S_OK;
error:
return(hr);
}
HRESULT
verbDelStore(
IN WCHAR const *pwszOption,
IN WCHAR const *pwszStoreName,
IN WCHAR const *pwszCertId,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
WCHAR *pwszStore = NULL;
HCERTSTORE hStore = NULL;
CERT_CONTEXT const *pCert = NULL;
CRL_CONTEXT const *pCRL = NULL;
WCHAR *pwszCertName = NULL;
BYTE *pbHash = NULL;
DWORD cbHash;
BSTR strSerialNumber = NULL;
DWORD Mode;
DWORD iCert;
DWORD iCertDel;
DWORD iCRL;
DWORD iCRLDel;
DWORD iCTL;
DWORD iCTLDel;
DWORD cCertDeleted;
DWORD cCRLDeleted;
BYTE *pbDeleted = NULL;
DWORD cbDeleted;
if (NULL == pwszStoreName || 0 == wcscmp(L"*", pwszStoreName))
{
pwszStoreName = wszCA_CERTSTORE;
}
hr = ParseCertCRLIndex(pwszCertId, &pwszCertName, &iCertDel, &iCRLDel, &iCTLDel);
_JumpIfErrorStr(hr, error, "ParseCertCRLIndex", pwszCertId);
if (MAXDWORD == iCertDel && NULL == pwszCertName && MAXDWORD == iCRLDel)
{
hr = E_INVALIDARG;
_JumpErrorStr(hr, error, "incomplete Index arg", pwszCertId);
}
if (NULL != pwszCertName)
{
hr = WszToMultiByteInteger(TRUE, pwszCertName, &cbHash, &pbHash);
_PrintIfError2(hr, "WszToMultiByteInteger", hr);
hr = myMakeSerialBstr(pwszCertName, &strSerialNumber);
_PrintIfError2(hr, "myMakeSerialBstr", hr);
}
Mode = DVNS_WRITESTORE; // force open for write
hr = cuOpenCertStore(pwszStoreName, &Mode, NULL, &hStore);
_JumpIfError(hr, error, "cuOpenCertStore");
cCertDeleted = 0;
cCRLDeleted = 0;
if (MAXDWORD != iCertDel || NULL != pwszCertName)
{
for (iCert = 0; ; iCert++)
{
pCert = CertEnumCertificatesInStore(hStore, pCert);
if (NULL == pCert)
{
break;
}
if (iCert == iCertDel ||
(MAXDWORD == iCertDel && NULL != pwszCertName))
{
CERT_CONTEXT const *pCertT;
if (NULL != pwszCertName)
{
BOOL fMatch;
hr = myCertMatch(
pCert,
pwszCertName,
FALSE, // fAllowMissingCN
pbHash,
cbHash,
strSerialNumber,
&fMatch);
_JumpIfError(hr, error, "myCertMatch");
if (!fMatch)
{
continue;
}
}
wprintf(
myLoadResourceString(IDS_FORMAT_DELETE_CERT_INDEX), // "Deleting Certificate %d"
iCert);
wprintf(wszNewLine);
cCertDeleted++;
SaveFirstBlob(
pCert->pbCertEncoded,
pCert->cbCertEncoded,
&pbDeleted,
&cbDeleted);
pCertT = CertDuplicateCertificateContext(pCert);
if (!CertDeleteCertificateFromStore(pCertT))
{
hr = myHLastError();
_JumpError(hr, error, "CertDeleteCertificateFromStore");
}
if (iCert == iCertDel)
{
break;
}
}
}
}
if (MAXDWORD != iCRLDel || NULL != pwszCertName)
{
for (iCRL = 0; ; iCRL++)
{
pCRL = CertEnumCRLsInStore(hStore, pCRL);
if (NULL == pCRL)
{
break;
}
if (iCRL == iCRLDel ||
(MAXDWORD == iCRLDel && NULL != pwszCertName))
{
CRL_CONTEXT const *pCRLT;
if (NULL != pwszCertName)
{
BOOL fMatch;
hr = myCRLMatch(
pCRL,
pwszCertName,
FALSE, // fAllowMissingCN
pbHash,
cbHash,
&fMatch);
_JumpIfError(hr, error, "myCRLMatch");
if (!fMatch)
{
continue;
}
}
wprintf(
myLoadResourceString(IDS_FORMAT_DELETE_CRL_INDEX), // "Deleting CRL %d"
iCRL);
wprintf(wszNewLine);
cCRLDeleted++;
SaveFirstBlob(
pCRL->pbCrlEncoded,
pCRL->cbCrlEncoded,
&pbDeleted,
&cbDeleted);
pCRLT = CertDuplicateCRLContext(pCRL);
if (!CertDeleteCRLFromStore(pCRLT))
{
hr = myHLastError();
_JumpError(hr, error, "CertDeleteCRLFromStore");
}
if (iCRL == iCRLDel)
{
break;
}
}
}
}
if (0 != cCertDeleted + cCRLDeleted)
{
BOOL fSingle = 1 == cCertDeleted + cCRLDeleted;
hr = CommitStore(
hStore,
pwszStoreName,
Mode,
fSingle? pbDeleted : NULL,
fSingle? cbDeleted : 0);
_JumpIfError(hr, error, "CommitStore");
}
hr = S_OK;
error:
if (NULL != strSerialNumber)
{
SysFreeString(strSerialNumber);
}
if (NULL != pbDeleted)
{
LocalFree(pbDeleted);
}
if (NULL != pbHash)
{
LocalFree(pbHash);
}
if (NULL != pwszCertName)
{
LocalFree(pwszCertName);
}
if (NULL != pwszStore)
{
LocalFree(pwszStore);
}
if (NULL != pCert)
{
CertFreeCertificateContext(pCert);
}
if (NULL != pCRL)
{
CertFreeCRLContext(pCRL);
}
if (NULL != hStore)
{
CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
}
return(hr);
}
HRESULT
verbVerifyStore(
IN WCHAR const *pwszOption,
IN WCHAR const *pwszStoreName,
IN WCHAR const *pwszCertId,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
WCHAR *pwszCertName = NULL;
DWORD iCert;
DWORD iCRL;
DWORD iCTL;
hr = ParseCertCRLIndex(pwszCertId, &pwszCertName, &iCert, &iCRL, &iCTL);
_JumpIfErrorStr(hr, error, "ParseCertCRLIndex", pwszCertId);
hr = DumpAndVerifyNamedStore(
pwszStoreName,
DVNS_SAVECERT |
DVNS_SAVECRL |
DVNS_SAVECTL |
DVNS_VERIFYCERT |
DVNS_DUMPKEYS |
DVNS_DUMPPROPERTIES,
pwszCertName,
iCert,
iCRL,
iCTL,
NULL,
NULL);
_JumpIfError(hr, error, "DumpAndVerifyNamedStore");
error:
if (NULL != pwszCertName)
{
LocalFree(pwszCertName);
}
return(hr);
}
HRESULT
verbRepairStore(
IN WCHAR const *pwszOption,
IN WCHAR const *pwszStoreName,
IN WCHAR const *pwszCertId,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
WCHAR *pwszCertName = NULL;
DWORD iCert;
DWORD iCRL;
DWORD iCTL;
hr = ParseCertCRLIndex(pwszCertId, &pwszCertName, &iCert, &iCRL, &iCTL);
_JumpIfErrorStr(hr, error, "ParseCertCRLIndex", pwszCertId);
hr = DumpAndVerifyNamedStore(
pwszStoreName,
DVNS_SAVECERT |
DVNS_SAVECRL |
DVNS_SAVECTL |
DVNS_REPAIRKPI |
DVNS_DUMPKEYS,
pwszCertName,
iCert,
iCRL,
iCTL,
NULL,
NULL);
_JumpIfError(hr, error, "DumpAndVerifyNamedStore");
error:
if (NULL != pwszCertName)
{
LocalFree(pwszCertName);
}
return(hr);
}
HRESULT
verbExportPVK(
IN WCHAR const *pwszOption,
IN WCHAR const *pwszCertId,
IN WCHAR const *pwszfnPVKBaseName,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
WCHAR *pwszCertName = NULL;
DWORD iCert;
DWORD iCRL;
DWORD iCTL;
hr = ParseCertCRLIndex(pwszCertId, &pwszCertName, &iCert, &iCRL, &iCTL);
_JumpIfErrorStr(hr, error, "ParseCertCRLIndex", pwszCertId);
hr = DumpAndVerifyNamedStore(
wszMY_CERTSTORE,
DVNS_SAVEPVK | DVNS_DUMPKEYS,
pwszCertName,
iCert,
iCRL,
iCTL,
pwszfnPVKBaseName,
g_pwszPassword);
_JumpIfError(hr, error, "DumpAndVerifyNamedStore");
error:
if (NULL != pwszCertName)
{
LocalFree(pwszCertName);
}
return(hr);
}
HRESULT
verbExportPFX(
IN WCHAR const *pwszOption,
IN WCHAR const *pwszCertId,
IN WCHAR const *pwszfnPFX,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
WCHAR *pwszCertName = NULL;
DWORD iCert;
DWORD iCRL;
DWORD iCTL;
hr = ParseCertCRLIndex(pwszCertId, &pwszCertName, &iCert, &iCRL, &iCTL);
_JumpIfErrorStr(hr, error, "ParseCertCRLIndex", pwszCertId);
hr = DumpAndVerifyNamedStore(
wszMY_CERTSTORE,
DVNS_SAVEPFX | DVNS_DUMPKEYS,
pwszCertName,
iCert,
iCRL,
iCTL,
pwszfnPFX,
g_pwszPassword);
_JumpIfError(hr, error, "DumpAndVerifyNamedStore");
error:
if (NULL != pwszCertName)
{
LocalFree(pwszCertName);
}
return(hr);
}
HRESULT
cuGenerateKeyContainerName(
IN CERT_CONTEXT const *pcc,
OUT WCHAR **ppwszKeyContainerName)
{
HRESULT hr;
GUID guid;
WCHAR *pwszGUID = NULL;
WCHAR *pwszSimpleName = NULL;
WCHAR *pwszRawContainerName = NULL;
DWORD cwc;
*ppwszKeyContainerName = NULL;
hr = myCertGetNameString(
pcc,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
&pwszSimpleName);
_JumpIfError(hr, error, "myCertGetNameString");
myUuidCreate(&guid);
hr = myCLSIDToWsz(&guid, &pwszGUID);
_JumpIfError(hr, error, "myCLSIDToWsz");
cwc = wcslen(pwszSimpleName) + 1 + wcslen(pwszGUID);
pwszRawContainerName = (WCHAR *) LocalAlloc(
LMEM_FIXED,
(cwc + 1) * sizeof(WCHAR));
if (NULL == pwszRawContainerName)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
wcscpy(pwszRawContainerName, pwszSimpleName);
wcscat(pwszRawContainerName, L"-");
wcscat(pwszRawContainerName, pwszGUID);
hr = mySanitizeName(pwszRawContainerName, ppwszKeyContainerName);
_JumpIfError(hr, error, "mySanitizeName");
wprintf(L"%ws -- %ws\n", pwszSimpleName, *ppwszKeyContainerName);
error:
if (NULL != pwszGUID)
{
LocalFree(pwszGUID);
}
if (NULL != pwszSimpleName)
{
LocalFree(pwszSimpleName);
}
if (NULL != pwszRawContainerName)
{
LocalFree(pwszRawContainerName);
}
return(hr);
}
HRESULT
cuImportChainAndKeys(
IN CERT_CHAIN_CONTEXT const *pChain,
OPTIONAL IN WCHAR const *pwszNewCSP,
IN BOOL fUser,
OPTIONAL IN WCHAR const *pwszStoreName)
{
HRESULT hr;
CRYPT_KEY_PROV_INFO *pkpi = NULL;
WCHAR *pwszKeyContainerName = NULL;
CERT_CONTEXT const *pcc;
if (NULL == pwszStoreName)
{
pwszStoreName = wszMY_CERTSTORE;
}
pcc = pChain->rgpChain[0]->rgpElement[0]->pCertContext;
hr = myCertGetKeyProviderInfo(pcc, &pkpi);
_JumpIfError(hr, error, "myCertGetKeyProviderInfo");
hr = cuGenerateKeyContainerName(pcc, &pwszKeyContainerName);
_JumpIfError(hr, error, "cuGenerateKeyContainerName");
if (NULL == pwszNewCSP)
{
pwszNewCSP = pkpi->pwszProvName;
}
hr = myCopyKeys(
pkpi,
pkpi->pwszContainerName, // pwszOldContainer
pwszKeyContainerName, // pwszNewContainer
pwszNewCSP, // pwszNewCSP
fUser, // fOldUserKey
fUser, // fNewUserKey
g_fProtect,
g_fForce);
_JumpIfError(hr, error, "myCopyKeys");
pkpi->pwszContainerName = pwszKeyContainerName;
pkpi->pwszProvName = const_cast<WCHAR *>(pwszNewCSP);
hr = mySaveChainAndKeys(
pChain->rgpChain[0],
pwszStoreName,
cuGetSystemStoreFlags(),
pkpi,
NULL);
_JumpIfError(hr, error, "mySaveChainAndKeys");
error:
if (NULL != pkpi)
{
LocalFree(pkpi);
}
if (NULL != pwszKeyContainerName)
{
LocalFree(pwszKeyContainerName);
}
return(hr);
}
HRESULT
ReadPFXOrEPFIntoCertStore(
IN WCHAR const *pwszfnPFXOrEPF,
IN BOOL fUser,
OUT HCERTSTORE *phStore)
{
HRESULT hr;
CRYPT_DATA_BLOB pfx;
WCHAR const *pwszPassword;
WCHAR wszPassword[MAX_PATH];
HCERTSTORE hStore = NULL;
pfx.pbData = NULL;
*phStore = NULL;
hr = cuGetPassword(
0, // idsPrompt
NULL, // pwszfn
g_pwszPassword,
FALSE, // fVerify
wszPassword,
ARRAYSIZE(wszPassword),
&pwszPassword);
_JumpIfError(hr, error, "cuGetPassword");
hr = DecodeFileW(
pwszfnPFXOrEPF,
&pfx.pbData,
&pfx.cbData,
CRYPT_STRING_ANY);
_JumpIfError(hr, error, "DecodeFileW");
CSASSERT(NULL != pfx.pbData);
if (PFXIsPFXBlob(&pfx))
{
hStore = myPFXImportCertStore(
&pfx,
pwszPassword,
CRYPT_EXPORTABLE |
(fUser? CRYPT_USER_KEYSET : CRYPT_MACHINE_KEYSET));
if (NULL == hStore)
{
hr = myHLastError();
_JumpError(hr, error, "myPFXImportCertStore");
}
}
else
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_PrintError(hr, "PFXIsPFXBlob");
hStore = CertOpenStore(
CERT_STORE_PROV_MEMORY,
X509_ASN_ENCODING,
NULL,
CERT_STORE_NO_CRYPT_RELEASE_FLAG |
CERT_STORE_ENUM_ARCHIVED_FLAG,
NULL);
if (NULL == hStore)
{
hr = myHLastError();
_JumpError(hr, error, "CertOpenStore");
}
hr = EPFFileDump(pwszfnPFXOrEPF, pwszPassword, hStore);
if (S_FALSE == hr) // if not an EPF file
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
}
_JumpIfErrorStr(hr, error, "EPFFileDump", pwszfnPFXOrEPF);
}
*phStore = hStore;
hStore = NULL;
hr = S_OK;
error:
SecureZeroMemory(wszPassword, sizeof(wszPassword)); // password data
if (NULL != hStore)
{
myDeleteGuidKeys(hStore, !fUser);
CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
}
if (NULL != pfx.pbData)
{
LocalFree(pfx.pbData);
}
return(hr);
}
HRESULT
verbImportPFX(
IN WCHAR const *pwszOption,
IN WCHAR const *pwszfnPFXOrEPF,
IN WCHAR const *pwszArg2,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
HCERTSTORE hStorePFX = NULL;
RESTORECHAIN *paRestoreChain = NULL;
DWORD cRestoreChain;
DWORD iChain;
BOOL fUser = !g_fEnterpriseRegistry && g_fUserRegistry;
hr = ReadPFXOrEPFIntoCertStore(pwszfnPFXOrEPF, fUser, &hStorePFX);
_JumpIfError(hr, error, "ReadPFXOrEPFIntoCertStore");
cRestoreChain = 0;
hr = myGetChainArrayFromStore(
hStorePFX,
FALSE,
fUser,
NULL, // ppwszCommonName
&cRestoreChain,
NULL);
_JumpIfError(hr, error, "myGetChainArrayFromStore");
if (0 == cRestoreChain)
{
hr = HRESULT_FROM_WIN32(CRYPT_E_SELF_SIGNED);
_JumpError(hr, error, "myGetChainArrayFromStore <no chain>");
}
paRestoreChain = (RESTORECHAIN *) LocalAlloc(
LMEM_FIXED | LMEM_ZEROINIT,
cRestoreChain * sizeof(paRestoreChain[0]));
if (NULL == paRestoreChain)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
hr = myGetChainArrayFromStore(
hStorePFX,
FALSE,
fUser,
NULL, // ppwszCommonName
&cRestoreChain,
paRestoreChain);
_JumpIfError(hr, error, "myGetChainArrayFromStore");
for (iChain = 0; iChain < cRestoreChain; iChain++)
{
CERT_CHAIN_CONTEXT const *pChain = paRestoreChain[iChain].pChain;
CERT_PUBLIC_KEY_INFO *pPublicKeyInfo;
if (1 > pChain->cChain)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "No Chain Context");
}
hr = cuImportChainAndKeys(pChain, g_pwszCSP, fUser, wszMY_CERTSTORE);
_JumpIfError(hr, error, "cuImportChainAndKeys");
}
hr = S_OK;
error:
if (NULL != paRestoreChain)
{
for (iChain = 0; iChain < cRestoreChain; iChain++)
{
if (NULL != paRestoreChain[iChain].pChain)
{
CertFreeCertificateChain(paRestoreChain[iChain].pChain);
}
}
LocalFree(paRestoreChain);
}
if (NULL != hStorePFX)
{
myDeleteGuidKeys(hStorePFX, !fUser);
CertCloseStore(hStorePFX, CERT_CLOSE_STORE_CHECK_FLAG);
}
return(hr);
}
HRESULT
AddStringToList(
IN WCHAR const *pwszNew,
IN OUT WCHAR ***papwsz)
{
HRESULT hr;
WCHAR *pwszAlloc = NULL;
WCHAR **ppwsz;
DWORD i;
// Count the strings in the existing list.
// If the new string matches an existing string, return imemdiately.
ppwsz = *papwsz;
i = 0;
if (NULL != ppwsz)
{
for ( ; NULL != ppwsz[i]; i++)
{
if (0 == lstrcmp(pwszNew, ppwsz[i]))
{
hr = S_OK;
goto error;
}
}
}
hr = myDupString(pwszNew, &pwszAlloc);
_JumpIfError(hr, error, "myDupString");
ppwsz = (WCHAR **) LocalAlloc(LMEM_FIXED, (i + 2) * sizeof(*ppwsz));
if (NULL == ppwsz)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
// Insert the new string at the head of the list.
ppwsz[0] = pwszAlloc;
pwszAlloc = NULL;
if (0 != i)
{
CopyMemory(&ppwsz[1], *papwsz, i * sizeof(*ppwsz));
LocalFree(*papwsz);
}
ppwsz[i + 1] = NULL;
*papwsz = ppwsz;
hr = S_OK;
error:
if (NULL != pwszAlloc)
{
LocalFree(pwszAlloc);
}
return(hr);
}
HRESULT
AddPFXOrEPFToStoreSub(
IN WCHAR const *pwszfn,
IN WCHAR const *pwszPassword,
OPTIONAL IN CRYPT_DATA_BLOB *ppfx,
IN HCERTSTORE hStoreMerge)
{
HRESULT hr;
HCERTSTORE hStorePFX = NULL;
CERT_CONTEXT const *pCert = NULL;
if (NULL == ppfx)
{
hr = EPFFileDump(pwszfn, pwszPassword, hStoreMerge);
if (S_FALSE == hr) // if not an EPF file
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
}
_JumpIfErrorStr(hr, error, "EPFFileDump", pwszfn);
}
else
{
hStorePFX = myPFXImportCertStore(
ppfx,
pwszPassword,
CRYPT_EXPORTABLE |
(g_fUserRegistry?
CRYPT_USER_KEYSET : CRYPT_MACHINE_KEYSET));
if (NULL == hStorePFX)
{
hr = myHLastError();
_JumpErrorStr2(
hr,
error,
"myPFXImportCertStore",
pwszfn,
HRESULT_FROM_WIN32(ERROR_INVALID_PASSWORD));
}
while (TRUE)
{
pCert = CertEnumCertificatesInStore(hStorePFX, pCert);
if (NULL == pCert)
{
break;
}
if (!CertAddCertificateContextToStore(
hStoreMerge,
pCert,
CERT_STORE_ADD_REPLACE_EXISTING,
NULL))
{
hr = myHLastError();
_JumpError(hr, error, "CertAddCertificateContextToStore");
}
if (!CertDeleteCertificateFromStore(pCert))
{
hr = myHLastError();
_JumpError(hr, error, "CertDeleteCertificateFromStore");
}
pCert = NULL;
}
}
hr = S_OK;
error:
if (NULL != pCert)
{
CertFreeCertificateContext(pCert);
}
if (NULL != hStorePFX)
{
myDeleteGuidKeys(hStorePFX, !g_fUserRegistry);
CertCloseStore(hStorePFX, CERT_CLOSE_STORE_CHECK_FLAG);
}
return(hr);
}
HRESULT
myCryptGetDefaultProvider(
DWORD dwProvType,
DWORD dwFlags,
WCHAR **ppwszProvName)
{
HRESULT hr;
DWORD cb;
*ppwszProvName = NULL;
cb = 0;
while (TRUE)
{
if (!CryptGetDefaultProvider(
dwProvType,
NULL, // pdwReserved
dwFlags,
*ppwszProvName,
&cb))
{
hr = myHLastError();
_JumpError(hr, error, "CryptGetDefaultProvider");
}
if (NULL != *ppwszProvName)
{
break;
}
*ppwszProvName = (WCHAR *) LocalAlloc(LMEM_FIXED, cb);
if (NULL == *ppwszProvName)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
}
hr = S_OK;
error:
return(hr);
}
#define cuSIGN_KEY_USAGE \
(CERT_DIGITAL_SIGNATURE_KEY_USAGE | \
CERT_NON_REPUDIATION_KEY_USAGE | \
CERT_KEY_CERT_SIGN_KEY_USAGE | \
CERT_OFFLINE_CRL_SIGN_KEY_USAGE | \
CERT_CRL_SIGN_KEY_USAGE)
#define cuENCRYPT_KEY_USAGE \
(CERT_KEY_ENCIPHERMENT_KEY_USAGE | \
CERT_DATA_ENCIPHERMENT_KEY_USAGE | \
CERT_KEY_AGREEMENT_KEY_USAGE | \
CERT_ENCIPHER_ONLY_KEY_USAGE)
static CHAR const *s_cuapszObjIdSign[] =
{
szOID_PKIX_KP_CLIENT_AUTH,
szOID_PKIX_KP_CODE_SIGNING,
szOID_PKIX_KP_TIMESTAMP_SIGNING,
szOID_KP_TIME_STAMP_SIGNING,
szOID_KP_QUALIFIED_SUBORDINATION,
szOID_KP_DOCUMENT_SIGNING,
szOID_KP_SMARTCARD_LOGON,
};
static CHAR const *s_cuapszObjIdEncrypt[] =
{
szOID_PKIX_KP_EMAIL_PROTECTION,
szOID_KP_KEY_RECOVERY_AGENT,
szOID_KP_KEY_RECOVERY,
szOID_PKIX_KP_SERVER_AUTH,
};
BOOL
IsSigningCert(
IN CERT_CONTEXT const *pcc)
{
HRESULT hr;
BOOL fSigningCert = TRUE;
CERT_EXTENSION const *pExt;
DWORD cb;
BOOL fMatch;
pExt = CertFindExtension(
szOID_KEY_USAGE,
pcc->pCertInfo->cExtension,
pcc->pCertInfo->rgExtension);
if (NULL != pExt)
{
CRYPT_DATA_BLOB aBlob[1 + BLOB_ROUND(2)];
cb = sizeof(aBlob);
if (CryptDecodeObject(
X509_ASN_ENCODING,
X509_KEY_USAGE,
pExt->Value.pbData,
pExt->Value.cbData,
0,
aBlob,
&cb))
{
if (1 <= aBlob[0].cbData)
{
if (cuSIGN_KEY_USAGE & aBlob[0].pbData[0])
{
goto done;
}
if (cuENCRYPT_KEY_USAGE & aBlob[0].pbData[0])
{
fSigningCert = FALSE;
goto done;
}
}
}
}
hr = myCertMatchEKUOrApplicationPolicies(
pcc,
ARRAYSIZE(s_cuapszObjIdSign),
s_cuapszObjIdSign,
FALSE, // fUsageRequired
&fMatch);
if (S_OK == hr && fMatch)
{
goto done;
}
hr = myCertMatchEKUOrApplicationPolicies(
pcc,
ARRAYSIZE(s_cuapszObjIdEncrypt),
s_cuapszObjIdEncrypt,
FALSE, // fUsageRequired
&fMatch);
if (S_OK == hr && fMatch)
{
fSigningCert = FALSE;
goto done;
}
done:
return(fSigningCert);
}
HRESULT
AddCertAndKeyBlobToStore(
IN HCERTSTORE hStore,
IN CERT_CONTEXT const *pcc,
IN BYTE const *pbKey,
IN DWORD cbKey,
IN ALG_ID aiKeyAlg)
{
HRESULT hr;
BYTE *pbKeyAlloc = NULL;
DWORD cbKeyAlloc;
HCRYPTPROV hProv = NULL;
HCRYPTKEY hKey = NULL;
CRYPT_KEY_PROV_INFO kpi;
WCHAR *pwszProviderName = NULL;
WCHAR *pwszKeyContainerName = NULL;
BOOL fSigningKey;
BOOL fMatchingKey;
BOOL fQuiet;
#if 0
wprintf(wszNewLine);
DumpHex(
DH_NOTABPREFIX | DH_NOASCIIHEX | DH_PRIVATEDATA | 4,
pbKey,
cbKey);
#endif
hr = cuGenerateKeyContainerName(pcc, &pwszKeyContainerName);
_JumpIfError(hr, error, "cuGenerateKeyContainerName");
hr = myCryptGetDefaultProvider(
PROV_RSA_FULL,
g_fUserRegistry?
CRYPT_USER_DEFAULT : CRYPT_MACHINE_DEFAULT,
&pwszProviderName);
_JumpIfError(hr, error, "myCryptGetDefaultProvider");
if (!CryptAcquireContext(
&hProv,
pwszKeyContainerName,
pwszProviderName,
PROV_RSA_FULL,
CRYPT_NEWKEYSET))
{
hr = myHLastError();
_JumpError(hr, error, "CryptAcquireContext");
}
if (PRIVATEKEYBLOB == ((PUBLICKEYSTRUC const *) pbKey)->bType &&
CUR_BLOB_VERSION == ((PUBLICKEYSTRUC const *) pbKey)->bVersion &&
RSAPRIV_MAGIC ==
((RSAPUBKEY const *) &pbKey[sizeof(PUBLICKEYSTRUC)])->magic)
{
if (0 == aiKeyAlg)
{
aiKeyAlg = ((PUBLICKEYSTRUC const *) pbKey)->aiKeyAlg;
}
else
if (aiKeyAlg != ((PUBLICKEYSTRUC const *) pbKey)->aiKeyAlg)
{
((PUBLICKEYSTRUC *) pbKey)->aiKeyAlg = aiKeyAlg;
}
}
if (0 == aiKeyAlg)
{
aiKeyAlg = IsSigningCert(pcc)? CALG_RSA_SIGN : CALG_RSA_KEYX;
}
if (!CryptImportKey(hProv, pbKey, cbKey, NULL, CRYPT_EXPORTABLE, &hKey))
{
hr = myHLastError();
_PrintError(hr, "CryptImportKey");
hr = myDecodeKMSRSAKey(
pbKey,
cbKey,
aiKeyAlg,
&pbKeyAlloc,
&cbKeyAlloc);
_JumpIfError(hr, error, "myDecodeKMSRSAKey");
pbKey = pbKeyAlloc;
cbKey = cbKeyAlloc;
//cuDumpPrivateKeyBlob(pbKey, cbKey, FALSE);
if (!CryptImportKey(hProv, pbKey, cbKey, NULL, CRYPT_EXPORTABLE, &hKey))
{
hr = myHLastError();
_JumpError(hr, error, "CryptImportKey");
}
}
ZeroMemory(&kpi, sizeof(kpi));
kpi.pwszContainerName = pwszKeyContainerName;
kpi.pwszProvName = pwszProviderName;
kpi.dwProvType = PROV_RSA_FULL;
kpi.dwKeySpec = CALG_RSA_SIGN == aiKeyAlg? AT_SIGNATURE : AT_KEYEXCHANGE;
if (!CertSetCertificateContextProperty(
pcc,
CERT_KEY_PROV_INFO_PROP_ID,
0,
&kpi))
{
hr = myHLastError();
_JumpError(hr, error, "CertSetCertificateContextProperty");
}
if (!CertAddCertificateContextToStore(
hStore,
pcc,
CERT_STORE_ADD_NEW,
NULL))
{
hr = myHLastError();
_JumpError(hr, error, "CertAddCertificateContextToStore");
}
fQuiet = g_fQuiet;
g_fQuiet = TRUE;
hr = cuDumpPrivateKey(pcc, &fSigningKey, &fMatchingKey);
g_fQuiet = fQuiet;
if (!IsHrSkipPrivateKey(hr))
{
if (S_OK != hr)
{
wprintf(myLoadResourceString(
fSigningKey?
IDS_SIGNATURE_BAD : // "Signature test FAILED"
IDS_ENCRYPTION_BAD)); // "Encryption test FAILED"
wprintf(wszNewLine);
_PrintError(hr, "cuDumpPrivateKey");
fMatchingKey = FALSE;
}
if (fMatchingKey)
{
wprintf(myLoadResourceString(
fSigningKey?
IDS_SIGNATURE_OK : // "Signature test passed"
IDS_ENCRYPTION_OK)); // "Encryption test passed"
wprintf(wszNewLine);
}
}
hr = S_OK;
error:
if (NULL != pwszProviderName)
{
LocalFree(pwszProviderName);
}
if (NULL != pwszKeyContainerName)
{
LocalFree(pwszKeyContainerName);
}
if (NULL != hKey)
{
CryptDestroyKey(hKey);
}
if (NULL != hProv)
{
CryptReleaseContext(hProv, 0);
}
if (NULL != pbKeyAlloc)
{
SecureZeroMemory(pbKeyAlloc, cbKeyAlloc); // Key material
LocalFree(pbKeyAlloc);
}
return(hr);
}
#define cwcEXTMAX 4
typedef struct _KEYEXTENSION {
WCHAR const *pwszExt;
ALG_ID aiKeyAlg;
} KEYEXTENSION;
KEYEXTENSION s_akePrivate[] =
{
{ L".sig", CALG_RSA_SIGN },
{ L".enc", CALG_RSA_KEYX },
{ L".key", 0 },
{ L".pri", 0 },
};
HRESULT
AddCertAndKeyToStore(
IN CERT_CONTEXT const *pcc,
IN WCHAR const *pwszfn,
IN HCERTSTORE hStore,
IN BYTE const *pbCert,
IN DWORD cbCert)
{
HRESULT hr;
WCHAR *pwszfnKey = NULL;
WCHAR *pwszfnExt;
KEYEXTENSION const *pke;
BYTE *pbKey = NULL;
DWORD cbKey;
pwszfnKey = (WCHAR *) LocalAlloc(
LMEM_FIXED,
(wcslen(pwszfn) + cwcEXTMAX + 1) * sizeof(WCHAR));
if (NULL == pwszfnKey)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
wcscpy(pwszfnKey, pwszfn);
pwszfnExt = wcsrchr(pwszfnKey, L'.');
if (NULL == pwszfnExt || NULL != wcschr(pwszfnExt, L'\\'))
{
pwszfnExt = &pwszfnKey[wcslen(pwszfnKey)];
}
for (pke = s_akePrivate; ; pke++)
{
if (pke >= &s_akePrivate[ARRAYSIZE(s_akePrivate)])
{
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
_JumpErrorStr(hr, error, "No private key file", pwszfnKey);
}
CSASSERT(cwcEXTMAX >= wcslen(pke->pwszExt));
wcscpy(pwszfnExt, pke->pwszExt);
hr = DecodeFileW(pwszfnKey, &pbKey, &cbKey, CRYPT_STRING_ANY);
if (S_OK == hr)
{
break;
}
_PrintErrorStr2(hr, "DecodeFileW", pwszfnKey, hr);
}
hr = AddCertAndKeyBlobToStore(hStore, pcc, pbKey, cbKey, pke->aiKeyAlg);
_JumpIfError(hr, error, "AddCertAndKeyBlobToStore");
error:
if (NULL != pbKey)
{
LocalFree(pbKey);
}
if (NULL != pwszfnKey)
{
LocalFree(pwszfnKey);
}
return(hr);
}
HRESULT
AddSimplePKCS8WithCertToSTore(
IN HCERTSTORE hStoreMerge,
IN BYTE *pbIn,
IN DWORD cbIn)
{
HRESULT hr;
DWORD i;
DWORD cbKey;
CERT_CONTEXT const *pcc = NULL;
i = myASNGetDataIndex(
BER_SEQUENCE,
0,
pbIn,
cbIn,
&cbKey);
if (MAXDWORD == i)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "myASNGetDataIndex");
}
cbKey += i;
pcc = CertCreateCertificateContext(
X509_ASN_ENCODING,
&pbIn[cbKey],
cbIn - cbKey);
if (NULL == pcc)
{
hr = myHLastError();
_JumpError(hr, error, "CertCreateCertificateContext");
}
hr = AddCertAndKeyBlobToStore(
hStoreMerge,
pcc,
pbIn,
cbKey,
0); // aiKeyAlg
_JumpIfError(hr, error, "AddCertAndKeyBlobToStore");
error:
if (NULL != pcc)
{
CertFreeCertificateContext(pcc);
}
return(hr);
}
HRESULT
AddPFXOrEPFToStore(
IN WCHAR const *pwszfn,
IN HCERTSTORE hStoreMerge,
IN OUT WCHAR ***papwszPasswordList)
{
HRESULT hr;
WCHAR const * const *ppwszPasswordList = *papwszPasswordList;
BOOL fPFX;
DWORD i;
CRYPT_DATA_BLOB pfx;
WCHAR wszPassword[MAX_PATH];
WCHAR const *pwszPassword;
BOOL fLoaded;
CERT_CONTEXT const *pcc = NULL;
pfx.pbData = NULL;
hr = DecodeFileW(pwszfn, &pfx.pbData, &pfx.cbData, CRYPT_STRING_ANY);
_JumpIfError(hr, error, "DecodeFileW");
fPFX = PFXIsPFXBlob(&pfx);
if (!fPFX)
{
pcc = CertCreateCertificateContext(
X509_ASN_ENCODING,
pfx.pbData,
pfx.cbData);
if (NULL != pcc)
{
hr = AddCertAndKeyToStore(
pcc,
pwszfn,
hStoreMerge,
pfx.pbData,
pfx.cbData);
_PrintIfError(hr, "AddCertAndKeyToStore");
// File was a cert. If we found the key, hr is S_OK & we're done.
// If we didn't found the key, hr is set & we're done.
goto error;
}
else
{
// File was not a cert. See if it's a simple PKCS8 w/appended Cert.
hr = AddSimplePKCS8WithCertToSTore(
hStoreMerge,
pfx.pbData,
pfx.cbData);
_PrintIfError(hr, "AddSimplePKCS8WithCertToSTore");
if (S_OK == hr)
{
// If we succeeded, we're done.
goto error;
}
}
}
// Try all of the passwords collected so far.
fLoaded = FALSE;
if (NULL != ppwszPasswordList)
{
for (i = 0; NULL != ppwszPasswordList[i]; i++)
{
hr = AddPFXOrEPFToStoreSub(
pwszfn,
ppwszPasswordList[i],
fPFX? &pfx : NULL,
hStoreMerge);
if (HRESULT_FROM_WIN32(ERROR_INVALID_PASSWORD) != hr)
{
_JumpIfErrorStr(hr, error, "AddPFXOrEPFToStoreSub", pwszfn);
fLoaded = TRUE;
break; // success
}
}
}
// Try the unparsed command line password, or collect a new one.
pwszPassword = g_pwszPassword;
if (!fLoaded)
{
while (TRUE)
{
if (NULL != pwszPassword)
{
hr = AddPFXOrEPFToStoreSub(
pwszfn,
pwszPassword,
fPFX? &pfx : NULL,
hStoreMerge);
if (HRESULT_FROM_WIN32(ERROR_INVALID_PASSWORD) != hr)
{
_JumpIfErrorStr(hr, error, "AddPFXOrEPFToStoreSub", pwszfn);
break; // success
}
}
hr = cuGetPassword(
IDS_FORMAT_ENTER_PASSWORD,
pwszfn,
NULL, // pwszPasswordIn
FALSE, // fVerify
wszPassword,
ARRAYSIZE(wszPassword),
&pwszPassword);
_JumpIfError(hr, error, "cuGetPassword");
hr = AddStringToList(pwszPassword, papwszPasswordList);
_JumpIfError(hr, error, "AddStringToList");
}
}
hr = S_OK;
error:
SecureZeroMemory(wszPassword, sizeof(wszPassword)); // password data
if (NULL != pcc)
{
CertFreeCertificateContext(pcc);
}
if (NULL != pfx.pbData)
{
LocalFree(pfx.pbData);
}
return(hr);
}
HRESULT
LoadAndSavePFXFiles(
IN BOOL fSaveAsPFX,
IN BOOL dwEPFAlg,
IN WCHAR const *pwszfnPFXInFileList,
IN WCHAR const *pwszfnOutFile,
OPTIONAL IN WCHAR const *pwszNewCSP,
OPTIONAL IN WCHAR const *pwszSalt,
OPTIONAL IN WCHAR const *pwszV3CACertId)
{
HRESULT hr;
WCHAR **ppwszfnList = NULL;
WCHAR **ppwszPasswordList = NULL;
DWORD i;
HCERTSTORE hStoreMerge = NULL;
WCHAR *pwszPasswordAlloc = NULL;
WCHAR *pwszPasswordOut;
hr = cuParseStrings(
pwszfnPFXInFileList,
FALSE,
NULL,
NULL,
&ppwszfnList,
NULL);
_JumpIfError(hr, error, "cuParseStrings");
pwszPasswordOut = NULL;
if (NULL != g_pwszPassword)
{
hr = cuParseStrings(
g_pwszPassword,
FALSE,
NULL,
NULL,
&ppwszPasswordList,
NULL);
_JumpIfError(hr, error, "cuParseStrings");
if (NULL != ppwszPasswordList)
{
if (NULL != g_pwszPassword &&
(L',' == *g_pwszPassword ||
NULL != wcsstr(g_pwszPassword, L",,")))
{
hr = AddStringToList(g_wszEmpty, &ppwszPasswordList);
_JumpIfError(hr, error, "AddStringToList");
// make sure it was added at the head of the list
CSASSERT(L'\0' == ppwszPasswordList[0][0]);
}
for (i = 0; NULL != ppwszPasswordList[i]; i++)
{
}
if (i > 1 && 0 != lstrcmp(L"*", ppwszPasswordList[i - 1]))
{
pwszPasswordOut = ppwszPasswordList[i - 1];
}
}
}
hStoreMerge = CertOpenStore(
CERT_STORE_PROV_MEMORY,
X509_ASN_ENCODING,
NULL,
CERT_STORE_NO_CRYPT_RELEASE_FLAG |
CERT_STORE_ENUM_ARCHIVED_FLAG,
NULL);
if (NULL == hStoreMerge)
{
hr = myHLastError();
_JumpError(hr, error, "CertOpenStore");
}
if (NULL != ppwszfnList)
{
for (i = 0; NULL != ppwszfnList[i]; i++)
{
hr = AddPFXOrEPFToStore(
ppwszfnList[i],
hStoreMerge,
&ppwszPasswordList);
_JumpIfError(hr, error, "AddPFXOrEPFToStore");
}
}
else
{
hr = AddPFXOrEPFToStore(
pwszfnPFXInFileList,
hStoreMerge,
&ppwszPasswordList);
_JumpIfError(hr, error, "AddPFXOrEPFToStore");
}
hr = SavePFXStoreToFile(
hStoreMerge,
pwszfnOutFile,
pwszNewCSP,
pwszSalt,
pwszV3CACertId,
fSaveAsPFX,
dwEPFAlg,
pwszPasswordOut,
&pwszPasswordAlloc);
_JumpIfError(hr, error, "SavePFXStoreToFile");
error:
if (NULL != hStoreMerge)
{
myDeleteGuidKeys(hStoreMerge, !g_fUserRegistry);
CertCloseStore(hStoreMerge, CERT_CLOSE_STORE_CHECK_FLAG);
}
cuFreeStringArray(ppwszPasswordList);
cuFreeStringArray(ppwszfnList);
if (NULL != pwszPasswordAlloc)
{
myZeroDataString(pwszPasswordAlloc); // password data
LocalFree(pwszPasswordAlloc);
}
return(hr);
}
HRESULT
verbMergePFX(
IN WCHAR const *pwszOption,
IN WCHAR const *pwszfnPFXInFileList,
IN WCHAR const *pwszfnPFXOutFile,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
hr = LoadAndSavePFXFiles(
TRUE, // fSaveAsPFX
0, // dwEPFAlg
pwszfnPFXInFileList,
pwszfnPFXOutFile,
g_pwszCSP,
NULL, // pwszSalt
NULL); // pwszV3CACertId
_JumpIfError(hr, error, "LoadAndSavePFXFiles");
error:
return(hr);
}
HRESULT
verbConvertEPF(
IN WCHAR const *pwszOption,
IN WCHAR const *pwszfnPFXInFileList,
IN WCHAR const *pwszfnEPFOutFile,
OPTIONAL IN WCHAR const *pwszV3CACertId,
OPTIONAL IN WCHAR const *pwszAlg)
{
HRESULT hr;
DWORD dwEPFAlg = EPFALG_DEFAULT;
WCHAR *pwszDup = NULL;
WCHAR const *pwsz;
WCHAR *pwszSalt = NULL;
if (NULL != pwszV3CACertId &&
(0 == LSTRCMPIS(pwszV3CACertId, L"cast-") ||
0 == LSTRCMPIS(pwszV3CACertId, L"cast")))
{
pwsz = pwszV3CACertId;
pwszV3CACertId = pwszAlg;
pwszAlg = pwsz;
}
if (NULL != pwszV3CACertId && NULL != wcsrchr(pwszV3CACertId, L','))
{
hr = myDupString(pwszV3CACertId, &pwszDup);
_JumpIfError(hr, error, "myDupString");
pwszV3CACertId = pwszDup;
pwszSalt = wcsrchr(pwszV3CACertId, L',');
*pwszSalt++ = L'\0';
if (L'\0' == *pwszSalt)
{
pwszSalt = NULL;
}
if (L'\0' == *pwszV3CACertId)
{
pwszV3CACertId = NULL;
}
}
if (NULL != pwszAlg)
{
if (0 == LSTRCMPIS(pwszAlg, L"cast-"))
{
dwEPFAlg = EPFALG_CASTEXPORT;
}
else if (0 == LSTRCMPIS(pwszAlg, L"cast"))
{
dwEPFAlg = EPFALG_CAST;
}
else
{
hr = E_INVALIDARG;
_JumpErrorStr(hr, error, "pwszAlg", pwszAlg);
}
}
hr = LoadAndSavePFXFiles(
FALSE, // fSaveAsPFX
dwEPFAlg,
pwszfnPFXInFileList,
pwszfnEPFOutFile,
g_pwszCSP,
pwszSalt,
pwszV3CACertId);
_JumpIfError(hr, error, "LoadAndSavePFXFiles");
error:
if (NULL != pwszDup)
{
LocalFree(pwszDup);
}
return(hr);
}
HRESULT
GetMarshaledDword(
IN BOOL fFetchLength,
IN OUT BYTE const **ppb,
IN OUT DWORD *pcb,
OUT DWORD *pdw)
{
HRESULT hr = HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);
if (sizeof(*pdw) > *pcb)
{
_JumpError(hr, error, "input buffer too small");
}
*pdw = *(DWORD UNALIGNED *) *ppb;
*ppb += sizeof(*pdw);
*pcb -= sizeof(*pdw);
if (fFetchLength && *pdw > *pcb)
{
_JumpError(hr, error, "input buffer too small for length");
}
hr = S_OK;
error:
return(hr);
}
HRESULT
cuDecodeSequence(
IN BYTE const *pbSeq,
IN DWORD cbSeq,
IN DWORD cSeq,
OUT CRYPT_SEQUENCE_OF_ANY **ppSeq)
{
HRESULT hr;
DWORD cb;
DWORD i;
CRYPT_SEQUENCE_OF_ANY *pSeq = NULL;
*ppSeq = NULL;
if (!myDecodeObject(
X509_ASN_ENCODING,
X509_SEQUENCE_OF_ANY,
pbSeq,
cbSeq,
CERTLIB_USE_LOCALALLOC,
(VOID **) &pSeq,
&cb))
{
hr = myHLastError();
_JumpError(hr, error, "myDecodeObject");
}
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
if (cSeq != pSeq->cValue)
{
_JumpError(hr, error, "Sequence count");
}
for (i = 0; i < cSeq; i++)
{
if (NULL == pSeq->rgValue[i].pbData || 0 == pSeq->rgValue[i].cbData)
{
_JumpError(hr, error, "Empty Sequence");
}
}
*ppSeq = pSeq;
pSeq = NULL;
hr = S_OK;
error:
if (NULL != pSeq)
{
LocalFree(pSeq);
}
return(hr);
}
#define k_PrivateKeyVersion 0
HRESULT
VerifyKeyVersion(
IN BYTE const *pbIn,
IN DWORD cbIn)
{
HRESULT hr;
DWORD dwKeyVersion;
DWORD cb;
dwKeyVersion = MAXDWORD;
cb = sizeof(dwKeyVersion);
if (!CryptDecodeObject(
X509_ASN_ENCODING,
X509_INTEGER,
pbIn,
cbIn,
0,
&dwKeyVersion,
&cb))
{
hr = myHLastError();
_JumpError(hr, error, "CryptDecodeObject");
}
if (k_PrivateKeyVersion != dwKeyVersion)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "Public key version");
}
hr = S_OK;
error:
return(hr);
}
HRESULT
EncodeKeyVersion(
OUT BYTE **ppbOut,
OUT DWORD *pcbOut)
{
HRESULT hr;
DWORD dwKeyVersion;
*ppbOut = NULL;
dwKeyVersion = k_PrivateKeyVersion;
if (!myEncodeObject(
X509_ASN_ENCODING,
X509_INTEGER,
&dwKeyVersion,
0,
CERTLIB_USE_LOCALALLOC,
ppbOut,
pcbOut))
{
hr = myHLastError();
_JumpError(hr, error, "myEncodeObject");
}
hr = S_OK;
error:
return(hr);
}
//+-------------------------------------------------------------------------
// Inputs a private key in PKCS PrivateKeyInfo format:
// RSAPrivateKeyInfo ::= SEQUENCE {
// version Version, -- only 0 supported
// privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
// privateKey PrivateKey
// }
//
// Version ::= INTEGER
//
// PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
//
// PrivateKey ::= OCTET STRING -- contains an RSAPrivateKey
//
// RSAPrivateKey ::= SEQUENCE {
// version Version, -- only 0 supported
// modulus INTEGER, -- n
// publicExponent INTEGER, -- e
// privateExponent INTEGER, -- d
// prime1 INTEGER, -- p
// prime2 INTEGER, -- q
// exponent1 INTEGER, -- d mod (p-1)
// exponent2 INTEGER, -- d mod (q-1)
// coefficient INTEGER -- (inverse of q) mod p
// }
//
// returns a PRIVATEKEYBLOB
//--------------------------------------------------------------------------
// Indexes into pSeqOuter:
#define ISO_VERSION 0
#define ISO_ALG 1
#define ISO_KEY 2
#define ISO_MAX 3 // number of elements
// Indexes into pSeqAlg:
#define ISA_OID 0
#define ISA_PARM 1
#define ISA_MAX 2 // number of elements
// Indexes into pSeqKey:
#define ISK_VERSION 0
#define ISK_MODULUS 1 // public key
#define ISK_PUBEXP 2
#define ISK_PRIVEXP 3
#define ISK_PRIME1 4
#define ISK_PRIME2 5
#define ISK_EXP1 6
#define ISK_EXP2 7
#define ISK_COEFF 8
#define ISK_MAX 9 // number of elements
typedef struct _KEYBLOBMAP
{
DWORD dwisk; // index into pSeqKey: ISK_*
DWORD dwdivisor; // cbitKey/dwDivisor is expected byte count
} KEYBLOBMAP;
// The KEYBLOBMAP array defines the order and expected size of the key element
// integers as they will appear in the RSA PRIVATEKEYBLOB.
KEYBLOBMAP g_akbm[] = {
{ ISK_MODULUS, 8 }, // public key
{ ISK_PRIME1, 16 },
{ ISK_PRIME2, 16 },
{ ISK_EXP1, 16 },
{ ISK_EXP2, 16 },
{ ISK_COEFF, 16 },
{ ISK_PRIVEXP, 8 },
};
HRESULT
myDecodeKMSRSAKey(
IN BYTE const *pbKMSRSAKey,
IN DWORD cbKMSRSAKey,
IN ALG_ID aiKeyAlg,
OUT BYTE **ppbKey,
OUT DWORD *pcbKey)
{
HRESULT hr;
CRYPT_SEQUENCE_OF_ANY *pSeqOuter = NULL;
CRYPT_SEQUENCE_OF_ANY *pSeqAlg = NULL;
CRYPT_SEQUENCE_OF_ANY *pSeqKey = NULL;
DWORD cb;
DWORD i;
BYTE *pb;
BYTE *pbKey = NULL;
DWORD cbKey;
DWORD cbitKey;
char *pszObjId = NULL;
CRYPT_DATA_BLOB *pBlobKey = NULL;
CRYPT_INTEGER_BLOB *apIntKey[ISK_MAX];
DWORD dwPubExp;
*ppbKey = NULL;
ZeroMemory(apIntKey, sizeof(apIntKey));
hr = cuDecodeSequence(pbKMSRSAKey, cbKMSRSAKey, ISO_MAX, &pSeqOuter);
_JumpIfError(hr, error, "cuDecodeSequence");
hr = VerifyKeyVersion(
pSeqOuter->rgValue[ISO_VERSION].pbData,
pSeqOuter->rgValue[ISO_VERSION].cbData);
_JumpIfError(hr, error, "VerifyKeyVersion");
hr = cuDecodeSequence(
pSeqOuter->rgValue[ISO_ALG].pbData,
pSeqOuter->rgValue[ISO_ALG].cbData,
ISA_MAX,
&pSeqAlg);
_JumpIfError(hr, error, "cuDecodeSequence");
hr = cuDecodeObjId(
pSeqAlg->rgValue[ISA_OID].pbData,
pSeqAlg->rgValue[ISA_OID].cbData,
&pszObjId);
_JumpIfError(hr, error, "cuDecodeObjId");
// key algorithm must be szOID_RSA_RSA
if (0 != strcmp(szOID_RSA_RSA, pszObjId))
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "Bad key alg ObjId");
}
// key algorithm parms must be NULL (BER_NULL, cb == 0)
if (2 != pSeqAlg->rgValue[ISA_PARM].cbData ||
BER_NULL != pSeqAlg->rgValue[ISA_PARM].pbData[0] ||
0 != pSeqAlg->rgValue[ISA_PARM].pbData[1])
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "Bad key alg parameters");
}
if (!myDecodeObject(
X509_ASN_ENCODING,
X509_OCTET_STRING,
pSeqOuter->rgValue[ISO_KEY].pbData,
pSeqOuter->rgValue[ISO_KEY].cbData,
CERTLIB_USE_LOCALALLOC,
(VOID **) &pBlobKey,
&cb))
{
hr = myHLastError();
_JumpError(hr, error, "myDecodeObject");
}
hr = cuDecodeSequence(
pBlobKey->pbData,
pBlobKey->cbData,
ARRAYSIZE(apIntKey),
&pSeqKey);
_JumpIfError(hr, error, "cuDecodeSequence");
hr = VerifyKeyVersion(
pSeqKey->rgValue[ISK_VERSION].pbData,
pSeqKey->rgValue[ISK_VERSION].cbData);
_JumpIfError(hr, error, "VerifyKeyVersion");
cb = sizeof(dwPubExp);
if (!CryptDecodeObject(
X509_ASN_ENCODING,
X509_INTEGER,
pSeqKey->rgValue[ISK_PUBEXP].pbData,
pSeqKey->rgValue[ISK_PUBEXP].cbData,
0,
&dwPubExp,
&cb))
{
hr = myHLastError();
_JumpError(hr, error, "CryptDecodeObject");
}
for (i = 0; i < ARRAYSIZE(apIntKey); i++)
{
if (!myDecodeObject(
X509_ASN_ENCODING,
X509_MULTI_BYTE_INTEGER,
pSeqKey->rgValue[i].pbData,
pSeqKey->rgValue[i].cbData,
CERTLIB_USE_LOCALALLOC,
(VOID **) &apIntKey[i],
&cb))
{
hr = myHLastError();
_JumpError(hr, error, "myDecodeObject");
}
}
cb = apIntKey[ISK_MODULUS]->cbData;
if (0 < cb && 0 == apIntKey[ISK_MODULUS]->pbData[cb - 1])
{
cb--;
}
cbitKey = 8 * cb;
#if 0
wprintf(L"cbitKey = %u\n", cbitKey);
for (i = 0; i < ARRAYSIZE(apIntKey); i++)
{
wprintf(wszNewLine);
DumpHex(
DH_NOTABPREFIX | DH_NOASCIIHEX | DH_PRIVATEDATA | 4,
apIntKey[i]->pbData,
apIntKey[i]->cbData);
}
#endif
cbKey = sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY);
for (i = 0; i < ARRAYSIZE(g_akbm); i++)
{
cbKey += cbitKey / g_akbm[i].dwdivisor;
}
pbKey = (BYTE *) LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, cbKey);
if (NULL == pbKey)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
pb = pbKey;
((PUBLICKEYSTRUC *) pb)->bType = PRIVATEKEYBLOB;
((PUBLICKEYSTRUC *) pb)->bVersion = CUR_BLOB_VERSION;
((PUBLICKEYSTRUC *) pb)->aiKeyAlg = aiKeyAlg;
pb += sizeof(PUBLICKEYSTRUC);
((RSAPUBKEY *) pb)->magic = RSAPRIV_MAGIC; // "RSA2"
((RSAPUBKEY *) pb)->bitlen = cbitKey;
((RSAPUBKEY *) pb)->pubexp = dwPubExp;
pb += sizeof(RSAPUBKEY);
for (i = 0; i < ARRAYSIZE(g_akbm); i++)
{
DWORD cbcopy;
BYTE const *pbcopy;
CSASSERT(ISK_MAX > g_akbm[i].dwisk);
cb = cbitKey / g_akbm[i].dwdivisor;
cbcopy = apIntKey[g_akbm[i].dwisk]->cbData;
pbcopy = apIntKey[g_akbm[i].dwisk]->pbData;
if (cb < cbcopy)
{
if (cb + 1 != cbcopy || 0 != pbcopy[cb])
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "Bad key element size");
}
//DumpHex(DH_NOTABPREFIX | DH_PRIVATEDATA | 4, pbcopy, cbcopy);
cbcopy--;
}
CopyMemory(pb, pbcopy, cbcopy);
if (cb > cbcopy)
{
ZeroMemory(&pb[cbcopy], cb - cbcopy); // Add trailing zeros
}
pb += cb;
//DumpHex(DH_NOTABPREFIX | DH_NOASCIIHEX | DH_PRIVATEDATA | 4, pb - cb, cb);
}
CSASSERT(pb = &pbKey[cbKey]);
if (g_fVerbose)
{
wprintf(myLoadResourceString(IDS_FORMAT_BIT_KEY), cbitKey);
wprintf(wszNewLine);
if (1 < g_fVerbose)
{
DumpHex(DH_NOTABPREFIX | DH_PRIVATEDATA | 4, pbKey, cbKey);
}
}
*pcbKey = cbKey;
*ppbKey = pbKey;
pbKey = NULL;
hr = S_OK;
error:
if (NULL != pSeqOuter)
{
LocalFree(pSeqOuter);
}
if (NULL != pSeqAlg)
{
LocalFree(pSeqAlg);
}
if (NULL != pSeqKey)
{
LocalFree(pSeqKey);
}
if (NULL != pszObjId)
{
LocalFree(pszObjId);
}
if (NULL != pBlobKey)
{
LocalFree(pBlobKey);
}
for (i = 0; i < ARRAYSIZE(apIntKey); i++)
{
if (NULL != apIntKey[i])
{
LocalFree(apIntKey[i]);
}
}
if (NULL != pbKey)
{
LocalFree(pbKey);
}
return(hr);
}
//+-------------------------------------------------------------------------
// Inputs a private key in PRIVATEKEYBLOB format.
// returns a PKCS PrivateKeyInfo
//--------------------------------------------------------------------------
HRESULT
myEncodeKMSRSAKey(
IN BYTE const *pbKey,
IN DWORD cbKey,
OUT BYTE **ppbKMSRSAKey,
OUT DWORD *pcbKMSRSAKey)
{
HRESULT hr;
DWORD i;
BYTE const *pb;
CRYPT_SEQUENCE_OF_ANY SeqOuter;
CRYPT_SEQUENCE_OF_ANY SeqAlg;
CRYPT_SEQUENCE_OF_ANY SeqKey;
CRYPT_DER_BLOB rgBlobOuter[ISO_MAX];
CRYPT_DER_BLOB rgBlobAlg[ISA_MAX];
CRYPT_DER_BLOB rgBlobKey[ISK_MAX];
CRYPT_DER_BLOB BlobKey;
DWORD cbitKey;
DWORD dwPubExp;
BYTE rgbNull[] = { BER_NULL, 0 };
ZeroMemory(rgBlobOuter, sizeof(rgBlobOuter));
ZeroMemory(rgBlobAlg, sizeof(rgBlobAlg));
ZeroMemory(rgBlobKey, sizeof(rgBlobKey));
BlobKey.pbData = NULL;
pb = pbKey;
if (PRIVATEKEYBLOB != ((PUBLICKEYSTRUC const *) pb)->bType ||
CUR_BLOB_VERSION != ((PUBLICKEYSTRUC const *) pb)->bVersion)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "Bad RSA key type/version");
}
// aiKeyAlg = ((PUBLICKEYSTRUC const *) pb)->aiKeyAlg;
pb += sizeof(PUBLICKEYSTRUC);
if (RSAPRIV_MAGIC != ((RSAPUBKEY const *) pb)->magic) // "RSA2"
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "Bad RSA key magic");
}
cbitKey = ((RSAPUBKEY const *) pb)->bitlen;
dwPubExp = ((RSAPUBKEY const *) pb)->pubexp;
pb += sizeof(RSAPUBKEY);
hr = EncodeKeyVersion(
&rgBlobKey[ISK_VERSION].pbData,
&rgBlobKey[ISK_VERSION].cbData);
_JumpIfError(hr, error, "EncodeKeyVersion");
if (!myEncodeObject(
X509_ASN_ENCODING,
X509_INTEGER,
&dwPubExp,
0,
CERTLIB_USE_LOCALALLOC,
&rgBlobKey[ISK_PUBEXP].pbData,
&rgBlobKey[ISK_PUBEXP].cbData))
{
hr = myHLastError();
_JumpError(hr, error, "myEncodeObject");
}
for (i = 0; i < ARRAYSIZE(g_akbm); i++)
{
DWORD dwisk = g_akbm[i].dwisk;
CRYPT_DER_BLOB Blob;
CSASSERT(ISK_MAX > dwisk);
CSASSERT(NULL == rgBlobKey[dwisk].pbData);
Blob.pbData = const_cast<BYTE *>(pb);
Blob.cbData = cbitKey / g_akbm[i].dwdivisor;
pb += Blob.cbData;
while (1 < Blob.cbData && 0 == Blob.pbData[Blob.cbData - 1])
{
Blob.cbData--;
}
if (!myEncodeObject(
X509_ASN_ENCODING,
X509_MULTI_BYTE_INTEGER,
&Blob,
0,
CERTLIB_USE_LOCALALLOC,
&rgBlobKey[dwisk].pbData,
&rgBlobKey[dwisk].cbData))
{
hr = myHLastError();
_JumpError(hr, error, "myEncodeObject");
}
}
SeqKey.cValue = ARRAYSIZE(rgBlobKey);
SeqKey.rgValue = rgBlobKey;
if (!myEncodeObject(
X509_ASN_ENCODING,
X509_SEQUENCE_OF_ANY,
&SeqKey,
0,
CERTLIB_USE_LOCALALLOC,
&BlobKey.pbData,
&BlobKey.cbData))
{
hr = myHLastError();
_JumpError(hr, error, "myEncodeObject");
}
if (!myEncodeObject(
X509_ASN_ENCODING,
X509_OCTET_STRING,
&BlobKey,
0,
CERTLIB_USE_LOCALALLOC,
&rgBlobOuter[ISO_KEY].pbData,
&rgBlobOuter[ISO_KEY].cbData))
{
hr = myHLastError();
_JumpError(hr, error, "myEncodeObject");
}
// set key algorithm to szOID_RSA_RSA
hr = cuEncodeObjId(
szOID_RSA_RSA,
&rgBlobAlg[ISA_OID].pbData,
&rgBlobAlg[ISA_OID].cbData);
_JumpIfError(hr, error, "cuEncodeObjId");
// set key algorithm parms to NULL (BER_NULL, cb == 0)
rgBlobAlg[ISA_PARM].cbData = ARRAYSIZE(rgbNull);
rgBlobAlg[ISA_PARM].pbData = rgbNull;
SeqAlg.cValue = ARRAYSIZE(rgBlobAlg);
SeqAlg.rgValue = rgBlobAlg;
if (!myEncodeObject(
X509_ASN_ENCODING,
X509_SEQUENCE_OF_ANY,
&SeqAlg,
0,
CERTLIB_USE_LOCALALLOC,
&rgBlobOuter[ISO_ALG].pbData,
&rgBlobOuter[ISO_ALG].cbData))
{
hr = myHLastError();
_JumpError(hr, error, "myEncodeObject");
}
hr = EncodeKeyVersion(
&rgBlobOuter[ISO_VERSION].pbData,
&rgBlobOuter[ISO_VERSION].cbData);
_JumpIfError(hr, error, "EncodeKeyVersion");
SeqOuter.cValue = ARRAYSIZE(rgBlobOuter);
SeqOuter.rgValue = rgBlobOuter;
if (!myEncodeObject(
X509_ASN_ENCODING,
X509_SEQUENCE_OF_ANY,
&SeqOuter,
0,
CERTLIB_USE_LOCALALLOC,
ppbKMSRSAKey,
pcbKMSRSAKey))
{
hr = myHLastError();
_JumpError(hr, error, "myEncodeObject");
}
hr = S_OK;
error:
if (NULL != BlobKey.pbData)
{
LocalFree(BlobKey.pbData);
}
for (i = 0; i < ARRAYSIZE(rgBlobKey); i++)
{
if (NULL != rgBlobKey[i].pbData)
{
LocalFree(rgBlobKey[i].pbData);
}
}
for (i = 0; i < ARRAYSIZE(rgBlobOuter); i++)
{
if (NULL != rgBlobOuter[i].pbData)
{
LocalFree(rgBlobOuter[i].pbData);
}
}
if (NULL != rgBlobAlg[ISA_OID].pbData)
{
LocalFree(rgBlobAlg[ISA_OID].pbData);
}
return(hr);
}
HRESULT
myVerifyKMSKey(
IN BYTE const *pbCert,
IN DWORD cbCert,
IN BYTE const *pbKey,
IN DWORD cbKey,
IN DWORD dwKeySpec,
IN BOOL fQuiet)
{
HRESULT hr;
CERT_CONTEXT const *pCert;
HCRYPTPROV hProv = NULL;
HCRYPTKEY hKey = NULL;
CERT_PUBLIC_KEY_INFO *pPublicKeyInfo = NULL;
DWORD cb;
pCert = CertCreateCertificateContext(X509_ASN_ENCODING, pbCert, cbCert);
if (NULL == pCert)
{
hr = myHLastError();
_JumpError(hr, error, "CertCreateCertificateContext");
}
if (!CryptAcquireContext(
&hProv,
NULL,
NULL,
PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT))
{
hr = myHLastError();
_JumpError(hr, error, "CryptAcquireContext");
}
if (!CryptImportKey(hProv, pbKey, cbKey, NULL, CRYPT_EXPORTABLE, &hKey))
{
hr = myHLastError();
_JumpError(hr, error, "CryptImportKey");
}
if (!myCryptExportPublicKeyInfo(
hProv,
dwKeySpec,
CERTLIB_USE_LOCALALLOC,
&pPublicKeyInfo,
&cb))
{
hr = myHLastError();
_JumpError(hr, error, "myCryptExportPublicKeyInfo");
}
if (g_fVerbose)
{
cuDumpVersion(pCert->pCertInfo->dwVersion + 1);
if (1 < g_fVerbose)
{
cuDumpPublicKey(&pCert->pCertInfo->SubjectPublicKeyInfo);
cuDisplayKeyId(&pCert->pCertInfo->SubjectPublicKeyInfo, 0, NULL);
cuDumpPublicKey(pPublicKeyInfo);
}
}
cuDisplayKeyId(pPublicKeyInfo, 0, NULL);
if (!myCertComparePublicKeyInfo(
X509_ASN_ENCODING,
CERT_V1 == pCert->pCertInfo->dwVersion,
pPublicKeyInfo,
&pCert->pCertInfo->SubjectPublicKeyInfo))
{
// by design, (my)CertComparePublicKeyInfo doesn't set last error!
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
if (!fQuiet)
{
wprintf(myLoadResourceString(IDS_ERR_PUBLICKEY_MISMATCH)); // "ERROR: Certificate public key does NOT match stored keyset"
wprintf(wszNewLine);
}
_JumpError2(hr, error, "myCertComparePublicKeyInfo", fQuiet? hr : S_OK);
}
if (AT_SIGNATURE == dwKeySpec)
{
hr = myValidateKeyForSigning(
hProv,
&pCert->pCertInfo->SubjectPublicKeyInfo,
CALG_SHA1);
}
else
{
hr = myValidateKeyForEncrypting(
hProv,
&pCert->pCertInfo->SubjectPublicKeyInfo,
CALG_RC4);
}
if (S_OK != hr)
{
wprintf(myLoadResourceString(IDS_ERR_PRIVATEKEY_MISMATCH)); // "ERROR: Certificate public key does NOT match private key"
wprintf(wszNewLine);
_JumpError(hr, error, "myValidateKeyForEncrypting");
}
if (g_fVerbose)
{
wprintf(myLoadResourceString(IDS_PRIVATEKEY_VERIFIES));
wprintf(wszNewLine);
}
error:
if (NULL != pCert)
{
CertFreeCertificateContext(pCert);
}
if (NULL != pPublicKeyInfo)
{
LocalFree(pPublicKeyInfo);
}
if (NULL != hKey)
{
CryptDestroyKey(hKey);
}
if (NULL != hProv)
{
CryptReleaseContext(hProv, 0);
}
return(hr);
}
HRESULT
cuDumpAsnBinaryQuiet(
IN BYTE const *pb,
IN DWORD cb,
IN DWORD iElement)
{
HRESULT hr;
BOOL fVerboseOld = g_fVerbose;
BOOL fQuietOld = g_fQuiet;
if (g_fVerbose)
{
g_fVerbose--;
}
else
{
g_fQuiet = TRUE;
}
hr = cuDumpAsnBinary(pb, cb, iElement);
_JumpIfError(hr, error, "cuDumpAsnBinary");
error:
g_fVerbose = fVerboseOld;
g_fQuiet = fQuietOld;
return(hr);
}
HRESULT
ReadTaggedBlob(
IN HANDLE hFile,
IN DWORD cbRemain,
OUT TagHeader *pth,
OUT BYTE **ppb)
{
HRESULT hr;
DWORD cbRead;
*ppb = NULL;
if (!ReadFile(hFile, pth, sizeof(*pth), &cbRead, NULL))
{
hr = myHLastError();
_JumpError(hr, error, "ReadFile");
}
hr = HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);
if (cbRead != sizeof(*pth))
{
DBGPRINT((
DBG_SS_ERROR,
"ReadFile read %u bytes, requested %u\n",
cbRead,
sizeof(*pth)));
_JumpError(hr, error, "ReadFile(cbRead)");
}
if (cbRead + pth->cbSize > cbRemain)
{
DBGPRINT((
DBG_SS_ERROR,
"Header size %u bytes, cbRemain %u\n",
sizeof(*pth) + pth->cbSize,
cbRemain));
_JumpError(hr, error, "cbRemain");
}
*ppb = (BYTE *) LocalAlloc(LMEM_FIXED, pth->cbSize);
if (NULL == *ppb)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
if (!ReadFile(hFile, *ppb, pth->cbSize, &cbRead, NULL))
{
hr = myHLastError();
_JumpError(hr, error, "ReadFile");
}
if (cbRead != pth->cbSize)
{
hr = HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);
DBGPRINT((
DBG_SS_ERROR,
"ReadFile read %u bytes, requested %u\n",
cbRead,
pth->cbSize));
_JumpError(hr, error, "ReadFile(cbRead)");
}
hr = S_OK;
error:
if (S_OK != hr && NULL != *ppb)
{
LocalFree(*ppb);
*ppb = NULL;
}
return(hr);
}
BOOL
DumpKMSTag(
IN TagHeader const *pth)
{
WCHAR const *pwsz;
WCHAR awctag[cwcDWORDSPRINTF];
pwsz = NULL;
switch (pth->tag)
{
case KMS_LOCKBOX_TAG: pwsz = L"KMS_LOCKBOX_TAG"; break;
case KMS_SIGNING_CERT_TAG: pwsz = L"KMS_SIGNING_CERT_TAG"; break;
case KMS_SIGNATURE_TAG: pwsz = L"KMS_SIGNATURE_TAG"; break;
case KMS_USER_RECORD_TAG: pwsz = L"KMS_USER_RECORD_TAG"; break;
default:
swprintf(awctag, L"%u", pth->tag);
pwsz = awctag;
break;
}
if (1 < g_fVerbose)
{
wprintf(
L"%ws: %x (%u) %ws\n",
pwsz,
pth->cbSize,
pth->cbSize,
myLoadResourceString(IDS_BYTES)); // "Bytes"
}
return(pwsz != awctag); // TRUE if tag is valid
}
HRESULT
VerifyKMSExportFile(
IN HANDLE hFile,
IN DWORD cbFile,
OUT CERT_CONTEXT const **ppccSigner)
{
HRESULT hr;
DWORD cbRemain;
DWORD cbRead;
TagHeader th;
BYTE *pb = NULL;
CERT_CONTEXT const *pccSigner = NULL;
HCRYPTPROV hProv = NULL;
HCRYPTHASH hHash = NULL;
HCRYPTKEY hkeyPub = NULL;
BOOL fVerified = FALSE;
WCHAR *pwszSubject = NULL;
*ppccSigner = NULL;
if (!CryptAcquireContext(
&hProv,
NULL, // pszContainer
NULL, // pszProvider
PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT))
{
hr = myHLastError();
_JumpError(hr, error, "CryptAcquireContext");
}
if (!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash))
{
hr = myHLastError();
_JumpError(hr, error, "CryptCreateHash");
}
cbRemain = cbFile;
while (0 < cbRemain)
{
fVerified = FALSE;
CSASSERT(NULL == pb);
hr = ReadTaggedBlob(hFile, cbRemain, &th, &pb);
_JumpIfError(hr, error, "ReadTaggedBlob");
if (!DumpKMSTag(&th))
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "invalid tag");
}
switch (th.tag)
{
case KMS_SIGNING_CERT_TAG:
if (g_fVerbose || g_fSplitASN)
{
hr = cuDumpAsnBinaryQuiet(pb, th.cbSize, MAXDWORD);
_JumpIfError(hr, error, "cuDumpAsnBinaryQuiet");
}
if (NULL != pccSigner)
{
hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
_JumpError(hr, error, "too many signers");
}
pccSigner = CertCreateCertificateContext(
X509_ASN_ENCODING,
pb,
th.cbSize);
if (NULL == pccSigner)
{
hr = myHLastError();
_JumpError(hr, error, "CertCreateCertificateContext");
}
hr = myCertNameToStr(
X509_ASN_ENCODING,
&pccSigner->pCertInfo->Subject,
CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
&pwszSubject);
_PrintIfError(hr, "myCertNameToStr");
wprintf(myLoadResourceString(IDS_PROCESSING_KMS_EXPORTS_COLON));
wprintf(L"\n %ws\n\n", pwszSubject);
break;
case KMS_SIGNATURE_TAG:
if (NULL != hkeyPub)
{
_JumpError(hr, error, "too many signatures");
}
if (NULL == pccSigner)
{
hr = TRUST_E_NO_SIGNER_CERT;
_JumpError(hr, error, "no signer");
}
if (!CryptImportPublicKeyInfo(
hProv,
X509_ASN_ENCODING,
&pccSigner->pCertInfo->SubjectPublicKeyInfo,
&hkeyPub))
{
hr = myHLastError();
_JumpError(hr, error, "CryptImportPublicKeyInfo");
}
if (!CryptVerifySignature(
hHash,
pb,
th.cbSize,
hkeyPub,
NULL,
0))
{
hr = myHLastError();
_JumpError(hr, error, "CryptVerifySignature");
}
fVerified = TRUE;
wprintf(myLoadResourceString(IDS_KMSEXPORT_SIG_OK)); // "KMS export file signature verifies"
wprintf(wszNewLine);
break;
default:
if (!CryptHashData(hHash, (BYTE *) &th, sizeof(th), 0))
{
hr = myHLastError();
_JumpError(hr, error, "CryptHashData");
}
if (!CryptHashData(hHash, pb, th.cbSize, 0))
{
hr = myHLastError();
_JumpError(hr, error, "CryptHashData");
}
break;
}
LocalFree(pb);
pb = NULL;
CSASSERT(cbRemain >= sizeof(th) + sizeof(th.cbSize));
cbRemain -= sizeof(th) + th.cbSize;
}
if (!fVerified)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "unsigned data");
}
hr = S_OK;
error:
if (NULL != pwszSubject)
{
LocalFree(pwszSubject);
}
if (NULL != pb)
{
LocalFree(pb);
}
if (NULL != hkeyPub)
{
CryptDestroyKey(hkeyPub);
}
if (NULL != hHash)
{
CryptDestroyHash(hHash);
}
if (NULL != hProv)
{
CryptReleaseContext(hProv, 0);
}
return(hr);
}
HRESULT
myEncryptPrivateKey(
IN CERT_CONTEXT const *pccXchg,
IN BYTE const *pbKey,
IN DWORD cbKey,
OUT BYTE **ppbKeyEncrypted,
OUT DWORD *pcbKeyEncrypted)
{
HRESULT hr;
ALG_ID rgalgId[] = { CALG_3DES, CALG_RC4, CALG_RC2 };
DWORD i;
*ppbKeyEncrypted = NULL;
hr = CRYPT_E_NOT_FOUND;
for (i = 0; i < ARRAYSIZE(rgalgId); i++)
{
// encryt into pkcs7
hr = myCryptEncryptMessage(
rgalgId[i],
1, // cCertRecipient
&pccXchg, // rgCertRecipient
pbKey,
cbKey,
NULL, // hCryptProv
ppbKeyEncrypted,
pcbKeyEncrypted);
if (S_OK == hr)
{
break; // done
}
_PrintError2(hr, "myCryptEncryptMessage", hr);
}
_JumpIfError(hr, error, "myCryptEncryptMessage");
error:
return(hr);
}
#define CB_IV 8
typedef struct _KMSSTATS {
HRESULT hr;
DWORD cRecUser;
DWORD cCertWithoutKeys;
DWORD cCertTotal;
DWORD cCertNotSaved;
DWORD cCertAlreadySaved;
DWORD cCertSaved;
DWORD cCertSavedForeign;
DWORD cKeyTotal;
DWORD cKeyNotSaved;
DWORD cKeyAlreadySaved;
DWORD cKeySaved;
DWORD cKeySavedOverwrite;
} KMSSTATS;
HRESULT
ArchiveCertAndKey(
IN DISPATCHINTERFACE *pdiAdmin,
IN CERT_CONTEXT const *pccXchg,
IN BYTE const *pbCert,
IN DWORD cbCert,
IN BYTE const *pbKey,
IN DWORD cbKey,
IN BOOL fSigningKey,
IN OUT KMSSTATS *pkmsStats)
{
HRESULT hr;
LONG RequestId;
BYTE *pbKeyEncrypted = NULL;
DWORD cbKeyEncrypted;
CERT_CONTEXT const *pcc = NULL;
BYTE abHash[CBMAX_CRYPT_HASH_LEN];
DWORD cbHash;
BSTR strHash = NULL;
BOOL fCertSaved = FALSE;
DWORD ids;
pcc = CertCreateCertificateContext(X509_ASN_ENCODING, pbCert, cbCert);
if (NULL == pcc)
{
hr = myHLastError();
_JumpError(hr, error, "CertCreateCertificateContext");
}
ids = 0;
hr = Admin_ImportCertificate(
pdiAdmin,
g_pwszConfig,
(WCHAR const *) pbCert,
cbCert,
CR_IN_BINARY,
&RequestId);
if (g_fForce &&
S_OK != hr &&
HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS) != hr)
{
hr = Admin_ImportCertificate(
pdiAdmin,
g_pwszConfig,
(WCHAR const *) pbCert,
cbCert,
ICF_ALLOWFOREIGN | CR_IN_BINARY,
&RequestId);
if (S_OK == hr)
{
pkmsStats->cCertSavedForeign++;
ids = IDS_IMPORT_CERT_FOREIGN; // "Imported foreign certificate"
}
}
if (HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS) != hr)
{
_JumpIfError2(hr, error, "Admin_ImportCertificate", NTE_BAD_SIGNATURE);
//wprintf(L"RequestId = %u\n", RequestId);
pkmsStats->cCertSaved++;
if (0 == ids)
{
ids = IDS_IMPORT_CERT_DOMESTIC; // "Imported certificate"
}
}
else
{
RequestId = MAXDWORD;
pkmsStats->cCertAlreadySaved++;
ids = IDS_IMPORT_CERT_EXISTS; // "Certificate exists"
cbHash = sizeof(abHash);
if (!CertGetCertificateContextProperty(
pcc,
CERT_SHA1_HASH_PROP_ID,
abHash,
&cbHash))
{
hr = myHLastError();
_JumpError(hr, error, "CertGetCertificateContextProperty");
}
hr = MultiByteIntegerToBstr(TRUE, cbHash, abHash, &strHash);
_JumpIfError(hr, error, "MultiByteIntegerToBstr");
}
fCertSaved = TRUE;
if (g_fVerbose)
{
wprintf(myLoadResourceString(ids));
wprintf(wszNewLine);
}
else
{
wprintf(L".");
}
hr = myEncryptPrivateKey(
pccXchg,
pbKey,
cbKey,
&pbKeyEncrypted,
&cbKeyEncrypted);
_JumpIfError(hr, error, "myEncryptPrivateKey");
ids = 0;
hr = Admin2_ImportKey(
pdiAdmin,
g_pwszConfig,
RequestId,
strHash,
CR_IN_BINARY,
(WCHAR const *) pbKeyEncrypted,
cbKeyEncrypted);
if (g_fForce && HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS) == hr)
{
hr = Admin2_ImportKey(
pdiAdmin,
g_pwszConfig,
RequestId,
strHash,
IKF_OVERWRITE | CR_IN_BINARY,
(WCHAR const *) pbKeyEncrypted,
cbKeyEncrypted);
if (S_OK == hr)
{
pkmsStats->cKeySavedOverwrite++;
ids = IDS_IMPORT_KEY_REPLACED; // "Archived key replaced"
}
}
if (HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS) != hr)
{
_JumpIfError(hr, error, "Admin2_ImportKey");
pkmsStats->cKeySaved++;
if (0 == ids)
{
ids = IDS_IMPORT_KEY_SAVED; // "Archived key"
}
}
else
{
pkmsStats->cKeyAlreadySaved++;
ids = IDS_IMPORT_KEY_EXISTS; // "Key already archived"
}
if (g_fVerbose)
{
wprintf(myLoadResourceString(ids));
wprintf(wszNewLine);
}
else
{
wprintf(L".");
}
hr = S_OK;
error:
if (S_OK != hr)
{
cuPrintErrorMessageText(hr);
if (!fCertSaved)
{
pkmsStats->cCertNotSaved++;
}
pkmsStats->cKeyNotSaved++;
if (fSigningKey && NTE_BAD_KEY_STATE == hr)
{
hr = S_OK;
}
else
if (S_OK == pkmsStats->hr)
{
pkmsStats->hr = hr;
}
}
if (NULL != pbKeyEncrypted)
{
LocalFree(pbKeyEncrypted);
}
if (NULL != strHash)
{
SysFreeString(strHash);
}
if (NULL != pcc)
{
CertFreeCertificateContext(pcc);
}
return(hr);
}
HRESULT
ImportOneKMSUser(
IN DISPATCHINTERFACE *pdiAdmin,
IN CERT_CONTEXT const *pccXchg,
IN BYTE const *pbRecUser,
IN DWORD cbRecUser,
IN HCRYPTKEY hkeySym,
IN OUT KMSSTATS *pkmsStats)
{
HRESULT hr;
BYTE const *pbT = pbRecUser;
WCHAR *pwszUser = NULL;
DWORD cbT = cbRecUser;
DWORD cb;
DWORD dw;
CLSID clsid;
WCHAR *pwszGUID = NULL;
BYTE *pbKeyASN = NULL;
DWORD cbKeyASN;
DWORD cbStream;
pkmsStats->cRecUser++;
// Get the user's directory GUID
CopyMemory(&clsid, pbT, sizeof(clsid));
hr = myCLSIDToWsz(&clsid, &pwszGUID);
_JumpIfError(hr, error, "myCLSIDToWsz");
pbT += sizeof(GUID);
cbT -= sizeof(GUID);
// Get the user's name length
hr = GetMarshaledDword(TRUE, &pbT, &cbT, &cb);
_JumpIfError(hr, error, "GetMarshaledDword");
pwszUser = (WCHAR *) LocalAlloc(
LMEM_FIXED,
((cb / sizeof(WCHAR)) + 1) * sizeof(WCHAR));
if (NULL == pwszUser)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
CopyMemory(pwszUser, pbT, cb);
pwszUser[cb / sizeof(WCHAR)] = L'\0';
if (g_fVerbose)
{
wprintf(L"\n----------------------\n");
wprintf(myLoadResourceString(IDS_USER_COLON));
wprintf(L" %ws -- %ws\n", pwszUser, pwszGUID);
}
pbT += cb;
cbT -= cb;
// for each User cert:
while (0 < cbT)
{
DWORD CertStatus;
FILETIME ftRevoke;
BYTE const *pbCert;
DWORD cbCert;
if (g_fVerbose)
{
wprintf(wszNewLine);
}
hr = GetMarshaledDword(FALSE, &pbT, &cbT, &CertStatus);
_JumpIfError(hr, error, "GetMarshaledDword");
if (1 < g_fVerbose)
{
wprintf(wszNewLine);
cuRegPrintDwordValue(
TRUE,
wszKMSCERTSTATUS,
wszKMSCERTSTATUS,
CertStatus);
}
hr = GetMarshaledDword(TRUE, &pbT, &cbT, &cb);
_JumpIfError(hr, error, "GetMarshaledDword");
// Dump one user cert:
pbCert = pbT;
cbCert = cb;
if (g_fSplitASN)
{
wprintf(wszNewLine);
hr = cuDumpAsnBinaryQuiet(pbCert, cbCert, MAXDWORD);
_JumpIfError(hr, error, "cuDumpAsnBinaryQuiet");
}
pbT += cb;
cbT -= cb;
// Get the revocation date (KMS export date):
hr = GetMarshaledDword(
FALSE,
&pbT,
&cbT,
&ftRevoke.dwLowDateTime);
_JumpIfError(hr, error, "GetMarshaledDword");
hr = GetMarshaledDword(
FALSE,
&pbT,
&cbT,
&ftRevoke.dwHighDateTime);
_JumpIfError(hr, error, "GetMarshaledDword");
if (g_fVerbose)
{
hr = cuDumpFileTime(IDS_REVOCATIONDATE, NULL, &ftRevoke);
_PrintIfError(hr, "cuDumpFileTime");
}
// Only encryption certs have archived keys:
if (0 == (CERTFLAGS_SEALING & CertStatus))
{
pkmsStats->cCertWithoutKeys++;
if (g_fVerbose)
{
wprintf(myLoadResourceString(IDS_IMPORT_CERT_SKIPPED_SIGNING)); // "Ignored signing certificate"
wprintf(wszNewLine);
}
continue;
}
pkmsStats->cCertTotal++;
pkmsStats->cKeyTotal++;
// get encrypted private key size
hr = GetMarshaledDword(TRUE, &pbT, &cbT, &cb);
_JumpIfError(hr, error, "GetMarshaledDword");
// get 8 byte RC2 IV
if (1 < g_fVerbose)
{
wprintf(L"IV:\n");
DumpHex(
DH_NOADDRESS | DH_NOTABPREFIX | DH_NOASCIIHEX | 4,
pbT,
CB_IV);
}
if (NULL != hkeySym)
{
// Set IV
if (!CryptSetKeyParam(
hkeySym,
KP_IV,
const_cast<BYTE *>(pbT),
0))
{
hr = GetLastError();
_JumpIfError(hr, error, "CryptSetKeyParam");
}
}
pbT += CB_IV;
cbT -= CB_IV;
cb -= CB_IV;
if (1 < g_fVerbose)
{
wprintf(wszNewLine);
wprintf(myLoadResourceString(IDS_ENCRYPTED_KEY_COLON));
wprintf(wszNewLine);
DumpHex(0, pbT, cb);
}
// decrypt key using hkeySym
// in-place decode is Ok because the size of the
// original data is always less than or equal to that
// of the encrypted data
cbStream = cb; // save off the real stream size first
if (NULL != hkeySym)
{
cbKeyASN = cb;
pbKeyASN = (BYTE *) LocalAlloc(LMEM_FIXED, cb);
if (NULL == pbKeyASN)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
CopyMemory(pbKeyASN, pbT, cbKeyASN);
if (!CryptDecrypt(hkeySym, NULL, TRUE, 0, pbKeyASN, &cb))
{
hr = GetLastError();
_PrintError(hr, "CryptDecrypt");
}
else
{
BYTE *pbKey;
DWORD cbKey;
if (1 < g_fVerbose)
{
wprintf(wszNewLine);
wprintf(myLoadResourceString(IDS_DECRYPTED_KEY_COLON));
wprintf(wszNewLine);
DumpHex(DH_PRIVATEDATA, pbKeyASN, cb);
}
hr = myDecodeKMSRSAKey(
pbKeyASN,
cbKeyASN,
CALG_RSA_KEYX,
&pbKey,
&cbKey);
_JumpIfError(hr, error, "myDecodeKMSRSAKey");
hr = myVerifyKMSKey(
pbCert,
cbCert,
pbKey,
cbKey,
AT_KEYEXCHANGE,
FALSE);
_PrintIfError(hr, "myVerifyKMSKey");
hr = ArchiveCertAndKey(
pdiAdmin,
pccXchg,
pbCert,
cbCert,
pbKey,
cbKey,
FALSE, // fSigningKey
pkmsStats);
_PrintIfError2(hr, "ArchiveCertAndKey", NTE_BAD_SIGNATURE);
SecureZeroMemory(pbKey, cbKey); // Key material
LocalFree(pbKey);
}
SecureZeroMemory(pbKeyASN, cbKeyASN); // Key material
LocalFree(pbKeyASN);
pbKeyASN = NULL;
}
// skip cbStream bytes, not cb
pbT += cbStream;
cbT -= cbStream;
}
hr = S_OK;
error:
if (NULL != pwszGUID)
{
LocalFree(pwszGUID);
}
if (NULL != pbKeyASN)
{
SecureZeroMemory(pbKeyASN, cbKeyASN); // Key material
LocalFree(pbKeyASN);
}
return(hr);
}
HRESULT
GetCAXchgCert(
IN DISPATCHINTERFACE *pdiAdmin,
OUT CERT_CONTEXT const **ppccXchg)
{
HRESULT hr;
BSTR strCert = NULL;
*ppccXchg = NULL;
hr = Admin2_GetCAProperty(
pdiAdmin,
g_pwszConfig,
CR_PROP_CAXCHGCERT,
0, // PropIndex
PROPTYPE_BINARY,
CR_OUT_BINARY,
&strCert);
_JumpIfError(hr, error, "Admin2_GetCAProperty");
*ppccXchg = CertCreateCertificateContext(
X509_ASN_ENCODING,
(BYTE const *) strCert,
SysStringByteLen(strCert));
if (NULL == *ppccXchg)
{
hr = myHLastError();
_JumpError(hr, error, "CertCreateCertificateContext");
}
hr = S_OK;
error:
if (NULL != strCert)
{
SysFreeString(strCert);
}
return(hr);
}
typedef struct _KMSMAP {
DWORD dwFieldOffset;
DWORD idMsg;
} KMSMAP;
KMSMAP g_akmUsers[] = {
{ FIELD_OFFSET(KMSSTATS, cRecUser), IDS_KMS_USERS, },
};
KMSMAP g_akmCerts[] = {
{ FIELD_OFFSET(KMSSTATS, cCertWithoutKeys), IDS_KMS_CERTS_SKIPPED, },
{ FIELD_OFFSET(KMSSTATS, cCertTotal), IDS_KMS_CERTS_TOTAL, },
{ FIELD_OFFSET(KMSSTATS, cCertSavedForeign), IDS_KMS_CERTS_FOREIGN, },
{ FIELD_OFFSET(KMSSTATS, cCertAlreadySaved), IDS_KMS_CERTS_ALREADYSAVED, },
{ FIELD_OFFSET(KMSSTATS, cCertSaved), IDS_KMS_CERTS_SAVED, },
{ FIELD_OFFSET(KMSSTATS, cCertNotSaved), IDS_KMS_CERTS_NOTSAVED, },
};
KMSMAP g_akmKeys[] = {
{ FIELD_OFFSET(KMSSTATS, cKeyTotal), IDS_KMS_KEYS_TOTAL, },
{ FIELD_OFFSET(KMSSTATS, cKeyAlreadySaved), IDS_KMS_KEYS_ALREADYSAVED, },
{ FIELD_OFFSET(KMSSTATS, cKeySavedOverwrite), IDS_KMS_KEYS_UPDATED, },
{ FIELD_OFFSET(KMSSTATS, cKeySaved), IDS_KMS_KEYS_SAVED, },
{ FIELD_OFFSET(KMSSTATS, cKeyNotSaved), IDS_KMS_KEYS_NOTSAVED, },
};
VOID
DumpKMSMap(
IN KMSSTATS const *pkmsStats,
IN KMSMAP const *pkm,
IN DWORD ckm)
{
DWORD i;
BOOL fFirst = TRUE;
DWORD count;
for (i = 0; i < ckm; i++)
{
count = *(DWORD *) Add2ConstPtr(pkmsStats, pkm[i].dwFieldOffset);
if (g_fVerbose || 0 != count)
{
if (fFirst)
{
wprintf(wszNewLine);
fFirst = FALSE;
}
wprintf(myLoadResourceString(pkm[i].idMsg));
wprintf(L": %u\n", count);
}
}
}
HRESULT
DumpKMSStats(
IN KMSSTATS const *pkmsStats)
{
DumpKMSMap(pkmsStats, g_akmUsers, ARRAYSIZE(g_akmUsers));
DumpKMSMap(pkmsStats, g_akmCerts, ARRAYSIZE(g_akmCerts));
DumpKMSMap(pkmsStats, g_akmKeys, ARRAYSIZE(g_akmKeys));
return(pkmsStats->hr);
}
HRESULT
ImportKMSExportedUsers(
IN HANDLE hFile,
IN DWORD cbFile,
IN HCRYPTPROV hProvKMS,
IN HCRYPTKEY hkeyKMS)
{
HRESULT hr;
HRESULT hrImport = S_OK;
DWORD cbRemain;
DWORD cbRead;
TagHeader th;
BYTE *pb = NULL;
HCRYPTKEY hkeySym = NULL;
KMSSTATS kmsStats;
DISPATCHINTERFACE diAdmin;
BOOL fMustRelease = FALSE;
CERT_CONTEXT const *pccXchg = NULL;
DWORD cImportFailures;
ZeroMemory(&kmsStats, sizeof(kmsStats));
hr = Admin_Init(g_DispatchFlags, &diAdmin);
_JumpIfError(hr, error, "Admin_Init");
fMustRelease = TRUE;
hr = GetCAXchgCert(&diAdmin, &pccXchg);
_JumpIfError(hr, error, "GetCAXchgCert");
cImportFailures = 0;
cbRemain = cbFile;
while (0 < cbRemain)
{
CSASSERT(NULL == pb);
hr = ReadTaggedBlob(hFile, cbRemain, &th, &pb);
_JumpIfError(hr, error, "ReadTaggedBlob");
if (!DumpKMSTag(&th))
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "invalid tag");
}
switch (th.tag)
{
case KMS_LOCKBOX_TAG:
{
if (1 < g_fVerbose)
{
hr = cuDumpPrivateKeyBlob(pb, th.cbSize, FALSE);
_PrintIfError(hr, "cuDumpPrivateKeyBlob");
}
// only need one symmetric key per file
if (NULL == hkeySym)
{
// 0x0000660c ALG_ID CALG_RC2_128
//
// CALG_RC2_128:
// ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_RC2_128
//
// CALG_CYLINK_MEK:
// ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_CYLINK_MEK
//
// UGH! Exchange's CALG_RC2_128 #define collides with
// wincrypt.h's CALG_CYLINK_MEK -- fix it up to be the
// correct CALG_RC2 algid from wincrypt.h.
((PUBLICKEYSTRUC *) pb)->aiKeyAlg = CALG_RC2;
// dump the fixed-up blob
if (1 < g_fVerbose)
{
hr = cuDumpPrivateKeyBlob(pb, th.cbSize, FALSE);
_PrintIfError(hr, "cuDumpPrivateKeyBlob");
}
// import 128 bit key
if (!CryptImportKey(
hProvKMS,
pb,
th.cbSize,
hkeyKMS,
0,
&hkeySym))
{
hrImport = myHLastError();
_PrintError2(hrImport, "CryptImportKey", hrImport);
if (0 < cImportFailures++)
{
wprintf(myLoadResourceString(IDS_ERROR_SYMMETRIC_KEY));
wprintf(wszNewLine);
_PrintError(hrImport, "CryptImportKey");
}
}
else
{
// We found the right lockbox. Effective keylen is
// still 40 bits in our CSP, reset to 128
DWORD dwEffectiveKeylen = 128;
if (!CryptSetKeyParam(
hkeySym,
KP_EFFECTIVE_KEYLEN,
(BYTE *) &dwEffectiveKeylen,
0))
{
hr = myHLastError();
_JumpError(hr, error, "CryptSetKeyParam(KP_EFFECTIVE_KEYLEN)");
}
wprintf(myLoadResourceString(IDS_SYMMETRIC_KEY_IMPORTED));
wprintf(wszNewLine);
hrImport = S_OK;
}
}
break;
}
case KMS_USER_RECORD_TAG:
hr = ImportOneKMSUser(
&diAdmin,
pccXchg,
pb,
th.cbSize,
hkeySym,
&kmsStats);
_JumpIfError(hr, error, "ImportOneKMSUser");
break;
default:
break;
}
LocalFree(pb);
pb = NULL;
CSASSERT(cbRemain >= sizeof(th) + sizeof(th.cbSize));
cbRemain -= sizeof(th) + th.cbSize;
}
if (!g_fVerbose)
{
wprintf(wszNewLine);
}
hr = DumpKMSStats(&kmsStats);
_PrintIfError(hr, "DumpKMSStats");
if (S_OK != hrImport)
{
hr = hrImport;
}
_JumpIfError(hr, error, "hrImport");
error:
if (NULL != pccXchg)
{
CertFreeCertificateContext(pccXchg);
}
if (fMustRelease)
{
Admin_Release(&diAdmin);
}
if (NULL != hkeySym)
{
CryptDestroyKey(hkeySym);
}
return(hr);
}
HRESULT
LoadKMSCert(
IN WCHAR const *pwszCertIdDecrypt,
OUT CERT_CONTEXT const **ppccKMS,
OUT HCRYPTPROV *phProvKMS,
OUT HCRYPTKEY *phkeyKMS)
{
HRESULT hr;
CRYPT_KEY_PROV_INFO *pkpiKMS = NULL;
DWORD cbkpiKMS;
BYTE *pbKey = NULL;
DWORD cbKey;
HCRYPTKEY hkeyKMSSig = NULL;
*ppccKMS = NULL;
*phProvKMS = NULL;
*phkeyKMS = NULL;
hr = myGetCertificateFromPicker(
g_hInstance,
NULL, // hwndParent
IDS_GETCERT_TITLE, // "Certificate List"
IDS_GETDECRYPTCERT_SUBTITLE,
// dwFlags: HKLM+HKCU My store
CUCS_MYSTORE |
CUCS_MACHINESTORE |
CUCS_USERSTORE |
CUCS_PRIVATEKEYREQUIRED |
(g_fCryptSilent? CUCS_SILENT : 0),
pwszCertIdDecrypt,
0, // cStore
NULL, // rghStore
0, // cpszObjId
NULL, // apszObjId
ppccKMS); // ppCert
_JumpIfError(hr, error, "myGetCertificateFromPicker");
if (NULL == *ppccKMS)
{
hr = ERROR_CANCELLED;
_JumpError(hr, error, "myGetCertificateFromPicker");
}
if (!myCertGetCertificateContextProperty(
*ppccKMS,
CERT_KEY_PROV_INFO_PROP_ID,
CERTLIB_USE_LOCALALLOC,
(VOID **) &pkpiKMS,
&cbkpiKMS))
{
hr = myHLastError();
_JumpError(hr, error, "myCertGetCertificateContextProperty");
}
if (0 == LSTRCMPIS(pkpiKMS->pwszProvName, MS_DEF_PROV_W))
{
pkpiKMS->pwszProvName = MS_STRONG_PROV_W;
}
if (g_fVerbose)
{
wprintf(
L"CryptAcquireContext(%ws, %ws)\n",
pkpiKMS->pwszContainerName,
pkpiKMS->pwszProvName);
}
if (!CryptAcquireContext(
phProvKMS,
pkpiKMS->pwszContainerName,
pkpiKMS->pwszProvName,
pkpiKMS->dwProvType,
pkpiKMS->dwFlags))
{
hr = myHLastError();
wprintf(L"CryptAcquireContext() --> %x\n", hr);
_JumpError(hr, error, "CryptAcquireContext");
}
if (!CryptGetUserKey(*phProvKMS, AT_KEYEXCHANGE, phkeyKMS))
{
hr = myHLastError();
if (hr != NTE_NO_KEY)
{
_JumpError(hr, error, "CryptGetUserKey");
}
if (!CryptGetUserKey(*phProvKMS, AT_SIGNATURE, &hkeyKMSSig))
{
hr = myHLastError();
_JumpError(hr, error, "CryptGetUserKey - sig");
}
// UGH! migrate from AT_SIGNATURE container!
cbKey = 0;
hr = myCryptExportKey(
hkeyKMSSig, // hKey
NULL, // hKeyExp
PRIVATEKEYBLOB, // dwBlobType
0, // dwFlags
&pbKey,
&cbKey);
_JumpIfError(hr, error, "myCryptExportKey");
// UGH! fix up the algid to signature...
((PUBLICKEYSTRUC *) pbKey)->aiKeyAlg = CALG_RSA_KEYX;
// and re-import it
if (!CryptImportKey(
*phProvKMS,
pbKey,
cbKey,
NULL,
CRYPT_EXPORTABLE,
phkeyKMS))
{
hr = myHLastError();
_JumpError(hr, error, "CryptImportKey");
}
wprintf(myLoadResourceString(IDS_MOVED_SIGNATURE_KEY));
wprintf(wszNewLine);
}
hr = S_OK;
error:
if (S_OK != hr)
{
if (NULL != *ppccKMS)
{
CertFreeCertificateContext(*ppccKMS);
*ppccKMS = NULL;
}
if (NULL != *phProvKMS)
{
CryptReleaseContext(*phProvKMS, 0);
*phProvKMS = NULL;
}
}
if (NULL != pbKey)
{
LocalFree(pbKey);
}
if (NULL != pkpiKMS)
{
LocalFree(pkpiKMS);
}
if (NULL != hkeyKMSSig)
{
CryptDestroyKey(hkeyKMSSig);
}
return(hr);
}
HRESULT
ImportOnePFXCert(
IN DISPATCHINTERFACE *pdiAdmin,
IN CERT_CONTEXT const *pccXchg,
IN CERT_CONTEXT const *pCert,
IN OUT KMSSTATS *pkmsStats)
{
HRESULT hr;
CRYPT_KEY_PROV_INFO *pkpi = NULL;
HCRYPTPROV hProv = NULL;
HCRYPTKEY hKey = NULL;
BYTE *pbKey = NULL;
DWORD cbKey;
hr = myCertGetKeyProviderInfo(pCert, &pkpi);
if (S_OK != hr)
{
_PrintError(hr, "myCertGetKeyProviderInfo");
pkmsStats->cCertWithoutKeys++;
hr = S_OK;
goto error;
}
pkmsStats->cCertTotal++;
if (!CryptAcquireContext(
&hProv,
pkpi->pwszContainerName,
pkpi->pwszProvName,
pkpi->dwProvType,
pkpi->dwFlags))
{
hr = myHLastError();
_JumpError(hr, error, "CryptAcquireContext");
}
if (!CryptGetUserKey(hProv, pkpi->dwKeySpec, &hKey))
{
hr = myHLastError();
_JumpIfError(hr, error, "CryptGetUserKey");
}
hr = myCryptExportPrivateKey(hKey, &pbKey, &cbKey);
_JumpIfError(hr, error, "myCryptExportPrivateKey");
pkmsStats->cKeyTotal++;
hr = myVerifyKMSKey(
pCert->pbCertEncoded,
pCert->cbCertEncoded,
pbKey,
cbKey,
pkpi->dwKeySpec,
FALSE);
_JumpIfError(hr, error, "myVerifyKMSKey");
hr = ArchiveCertAndKey(
pdiAdmin,
pccXchg,
pCert->pbCertEncoded,
pCert->cbCertEncoded,
pbKey,
cbKey,
AT_KEYEXCHANGE != pkpi->dwKeySpec, // fSigningKey
pkmsStats);
_JumpIfError(hr, error, "ArchiveCertAndKey");
error:
if (NULL != pbKey)
{
SecureZeroMemory(pbKey, cbKey); // Key material
LocalFree(pbKey);
}
if (NULL != hProv)
{
CryptReleaseContext(hProv, 0);
}
if (NULL != pkpi)
{
LocalFree(pkpi);
}
return(hr);
}
HRESULT
ImportKMSPFXOrEPFFile(
IN WCHAR const *pwszfn)
{
HRESULT hr;
CERT_CONTEXT const *pccXchg = NULL;
HCERTSTORE hStorePFX = NULL;
CERT_CONTEXT const *pCert = NULL;
DISPATCHINTERFACE diAdmin;
BOOL fMustRelease = FALSE;
KMSSTATS kmsStats;
BOOL fUser = TRUE;
ZeroMemory(&kmsStats, sizeof(kmsStats));
hr = ReadPFXOrEPFIntoCertStore(pwszfn, fUser, &hStorePFX);
_JumpIfError(hr, error, "ReadPFXOrEPFIntoCertStore");
hr = Admin_Init(g_DispatchFlags, &diAdmin);
_JumpIfError(hr, error, "Admin_Init");
fMustRelease = TRUE;
hr = GetCAXchgCert(&diAdmin, &pccXchg);
_JumpIfError(hr, error, "GetCAXchgCert");
while (TRUE)
{
pCert = CertEnumCertificatesInStore(hStorePFX, pCert);
if (NULL == pCert)
{
break;
}
hr = ImportOnePFXCert(&diAdmin, pccXchg, pCert, &kmsStats);
_PrintIfError(hr, "ImportOnePFXCert");
}
hr = DumpKMSStats(&kmsStats);
_JumpIfError(hr, error, "DumpKMSStats");
error:
if (NULL != hStorePFX)
{
myDeleteGuidKeys(hStorePFX, !fUser);
CertCloseStore(hStorePFX, CERT_CLOSE_STORE_CHECK_FLAG);
}
if (NULL != pccXchg)
{
CertFreeCertificateContext(pccXchg);
}
if (fMustRelease)
{
Admin_Release(&diAdmin);
}
return(hr);
}
HRESULT
ImportKMSExportFile(
IN WCHAR const *pwszfnKMS,
IN WCHAR const *pwszCertIdDecrypt,
OUT BOOL *pfBadTag)
{
HRESULT hr;
CERT_CONTEXT const *pccKMS = NULL;
HCRYPTPROV hProvKMS = NULL;
HCRYPTKEY hkeyKMS = NULL;
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD cbFile;
CERT_CONTEXT const *pccSigner = NULL;
*pfBadTag = TRUE;
hFile = CreateFile(
pwszfnKMS,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN,
NULL);
if (INVALID_HANDLE_VALUE == hFile)
{
hr = myHLastError();
_JumpError(hr, error, "CreateFile");
}
cbFile = GetFileSize(hFile, NULL);
if (MAXDWORD == cbFile)
{
hr = myHLastError();
_JumpError(hr, error, "GetFileSize");
}
// verify the KMS data signature
hr = VerifyKMSExportFile(hFile, cbFile, &pccSigner);
_JumpIfError(hr, error, "VerifyKMSExportFile");
*pfBadTag = FALSE;
if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, 0, NULL, FILE_BEGIN))
{
hr = myHLastError();
_JumpError(hr, error, "SetFilePointer");
}
// Load the KMS recipient cert to be used to decrypt user keys
hr = LoadKMSCert(pwszCertIdDecrypt, &pccKMS, &hProvKMS, &hkeyKMS);
_JumpIfError(hr, error, "LoadKMSCert");
// import the KMS data
hr = ImportKMSExportedUsers(hFile, cbFile, hProvKMS, hkeyKMS);
_JumpIfError(hr, error, "ImportKMSExportedUsers");
error:
if (NULL != pccKMS)
{
CertFreeCertificateContext(pccKMS);
}
if (NULL != pccSigner)
{
CertFreeCertificateContext(pccSigner);
}
if (NULL != hkeyKMS)
{
CryptDestroyKey(hkeyKMS);
}
if (NULL != hProvKMS)
{
CryptReleaseContext(hProvKMS, 0);
}
if (INVALID_HANDLE_VALUE != hFile)
{
CloseHandle(hFile);
}
return(hr);
}
HRESULT
verbImportKMS(
IN WCHAR const *pwszOption,
IN WCHAR const *pwszfnKMS,
IN WCHAR const *pwszCertIdDecrypt,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
BOOL fBadTag;
hr = ImportKMSExportFile(pwszfnKMS, pwszCertIdDecrypt, &fBadTag);
if (S_OK != hr)
{
_PrintError(hr, "ImportKMSExportFile");
if (!fBadTag)
{
goto error;
}
if (NULL != pwszCertIdDecrypt)
{
hr = E_INVALIDARG;
_JumpErrorStr(hr, error, "unexpected arg", pwszCertIdDecrypt);
}
hr = ImportKMSPFXOrEPFFile(pwszfnKMS);
_JumpIfError(hr, error, "ImportKMSPFXOrEPFFile");
}
error:
return(hr);
}
HRESULT
storeDumpPrivateKey(
IN HCRYPTPROV hProv,
IN DWORD dwKeySpec)
{
HRESULT hr;
HCRYPTKEY hKey = NULL;
CRYPT_BIT_BLOB PrivateKey;
ZeroMemory(&PrivateKey, sizeof(PrivateKey));
if (!CryptGetUserKey(hProv, dwKeySpec, &hKey))
{
hr = myHLastError();
_PrintError(hr, "CryptGetUserKey");
cuPrintError(IDS_ERR_FORMAT_LOADKEY, hr);
goto error;
}
hr = myCryptExportPrivateKey(
hKey,
&PrivateKey.pbData,
&PrivateKey.cbData);
if (NTE_BAD_KEY_STATE == hr || NTE_PERM == hr)
{
wprintf(myLoadResourceString(IDS_PRIVATE_KEY_NOT_EXPORTABLE)); // "Private key is NOT exportable"
wprintf(wszNewLine);
}
else
{
_JumpIfError(hr, error, "myCryptExportPrivateKey");
}
if (NULL != PrivateKey.pbData)
{
hr = cuDumpPrivateKeyBlob(
PrivateKey.pbData,
PrivateKey.cbData,
FALSE);
_JumpIfError(hr, error, "cuDumpPrivateKeyBlob");
}
hr = S_OK;
error:
if (NULL != PrivateKey.pbData)
{
SecureZeroMemory(PrivateKey.pbData, PrivateKey.cbData); // Key material
LocalFree(PrivateKey.pbData);
}
if (NULL != hKey)
{
CryptDestroyKey(hKey);
}
return(hr);
}
HRESULT
myCryptGetProvParamToUnicode(
IN HCRYPTPROV hProv,
IN DWORD dwParam,
OUT WCHAR **ppwszOut,
IN DWORD dwFlags);
HRESULT
DisplayUniqueContainer(
IN HCRYPTPROV hProv)
{
HRESULT hr;
WCHAR *pwszUniqueContainer = NULL;
hr = myCryptGetProvParamToUnicode(
hProv,
PP_UNIQUE_CONTAINER,
&pwszUniqueContainer,
0);
_JumpIfError(hr, error, "myCryptGetProvParamToUnicode");
wprintf(L" %ws\n", pwszUniqueContainer);
error:
if (NULL != pwszUniqueContainer)
{
LocalFree(pwszUniqueContainer);
}
return(hr);
}
HRESULT
EnumKeys(
IN WCHAR const *pwszProvName,
IN DWORD dwProvType,
IN BOOL fSkipKeys,
OPTIONAL IN WCHAR const *pwszKeyContainerName)
{
HRESULT hr;
KEY_LIST *pKeyList = NULL;
KEY_LIST *pKeyT;
WCHAR *pwszRevert = NULL;
CERT_PUBLIC_KEY_INFO *pPubKeyInfoSig = NULL;
CERT_PUBLIC_KEY_INFO *pPubKeyInfoXchg = NULL;
WCHAR const *pwszPrefix;
if (!fSkipKeys)
{
hr = csiGetKeyList(
dwProvType, // dwProvType
pwszProvName, // pwszProvName
!g_fUserRegistry, // fMachineKeyset
!g_fCryptSilent, // inverted fSilent: default is Silent!
&pKeyList);
_JumpIfErrorStr(hr, error, "csiGetKeyList", pwszProvName);
}
if (fSkipKeys || NULL != pKeyList)
{
wprintf(L"%ws:\n", pwszProvName);
}
for (pKeyT = pKeyList; NULL != pKeyT; pKeyT = pKeyT->next)
{
DWORD dwProvTypeT;
hr = myRevertSanitizeName(pKeyT->pwszName, &pwszRevert);
_JumpIfError(hr, error, "myRevertSanitizeName");
if (NULL == pwszKeyContainerName ||
0 == mylstrcmpiL(pwszKeyContainerName, pwszRevert) ||
0 == mylstrcmpiL(pwszKeyContainerName, pKeyT->pwszName))
{
HCRYPTPROV hProv = NULL;
wprintf(L" %ws", pwszRevert);
if (g_fVerbose && 0 != lstrcmp(pKeyT->pwszName, pwszRevert))
{
wprintf(L" -- %ws", pKeyT->pwszName);
}
wprintf(wszNewLine);
dwProvTypeT = dwProvType;
hr = cuLoadKeys(
pwszProvName,
&dwProvTypeT,
pKeyT->pwszName,
!g_fUserRegistry, // fMachineKeyset
TRUE,
&hProv,
&pPubKeyInfoSig,
&pPubKeyInfoXchg);
if (S_OK != hr)
{
cuPrintError(IDS_ERR_FORMAT_LOADKEYS, hr);
}
else if (g_fVerbose && NULL != hProv)
{
DisplayUniqueContainer(hProv);
}
if (NULL != pPubKeyInfoSig || NULL != pPubKeyInfoXchg)
{
pwszPrefix = g_wszPad4;
if (NULL != pPubKeyInfoSig)
{
if (g_fVerbose)
{
wprintf(wszNewLine);
}
wprintf(L"%wsAT_SIGNATURE", pwszPrefix);
pwszPrefix = L", ";
if (g_fVerbose)
{
wprintf(L":\n");
cuDisplayKeyId(pPubKeyInfoSig, 0, NULL);
wprintf(myLoadResourceString(IDS_CONTAINER_PUBLIC_KEY)); // "Container Public Key:"
wprintf(wszNewLine);
DumpHex(
DH_NOTABPREFIX | DH_NOASCIIHEX | 2,
pPubKeyInfoSig->PublicKey.pbData,
pPubKeyInfoSig->PublicKey.cbData);
wprintf(wszNewLine);
storeDumpPrivateKey(hProv, AT_SIGNATURE);
pwszPrefix = L" ";
}
LocalFree(pPubKeyInfoSig);
pPubKeyInfoSig = NULL;
}
if (NULL != pPubKeyInfoXchg)
{
if (g_fVerbose)
{
wprintf(wszNewLine);
}
wprintf(L"%wsAT_KEYEXCHANGE", pwszPrefix);
if (g_fVerbose)
{
wprintf(L":\n");
cuDisplayKeyId(pPubKeyInfoXchg, 0, NULL);
wprintf(myLoadResourceString(IDS_CONTAINER_PUBLIC_KEY)); // "Container Public Key:"
wprintf(wszNewLine);
DumpHex(
DH_NOTABPREFIX | DH_NOASCIIHEX | 2,
pPubKeyInfoXchg->PublicKey.pbData,
pPubKeyInfoXchg->PublicKey.cbData);
wprintf(wszNewLine);
storeDumpPrivateKey(hProv, AT_KEYEXCHANGE);
}
LocalFree(pPubKeyInfoXchg);
pPubKeyInfoXchg = NULL;
}
wprintf(wszNewLine);
}
if (NULL != hProv)
{
CryptReleaseContext(hProv, 0);
}
if (NULL == pwszKeyContainerName)
{
wprintf(wszNewLine);
}
}
LocalFree(pwszRevert);
pwszRevert = NULL;
}
hr = S_OK;
error:
if (NULL != pPubKeyInfoSig)
{
LocalFree(pPubKeyInfoSig);
}
if (NULL != pPubKeyInfoXchg)
{
LocalFree(pPubKeyInfoXchg);
}
if (NULL != pwszRevert)
{
LocalFree(pwszRevert);
}
if (NULL != pKeyList)
{
csiFreeKeyList(pKeyList);
}
return(hr);
}
HRESULT
verbKey(
IN WCHAR const *pwszOption,
OPTIONAL IN WCHAR const *pwszKeyContainerName,
IN WCHAR const *pwszArg2,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
WCHAR *pwszProvider = g_pwszCSP;
WCHAR *pwszProvName = NULL;
WCHAR *pwszProvNameDefault = NULL;
DWORD i;
DWORD dwProvType;
BOOL fSkipKeys = FALSE;
if (NULL == pwszProvider)
{
hr = myCryptGetDefaultProvider(
PROV_RSA_FULL,
g_fUserRegistry?
CRYPT_USER_DEFAULT : CRYPT_MACHINE_DEFAULT,
&pwszProvNameDefault);
_JumpIfError(hr, error, "myCryptGetDefaultProvider");
pwszProvider = pwszProvNameDefault;
}
else if (0 == lstrcmp(L"*", pwszProvider))
{
pwszProvider = NULL; // all CSPs
}
if (NULL != pwszKeyContainerName)
{
if (myIsMinusSignString(pwszKeyContainerName))
{
pwszKeyContainerName = NULL; // all keys
fSkipKeys = TRUE;
}
}
if (NULL != pwszProvider)
{
hr = csiGetProviderTypeFromProviderName(pwszProvider, &dwProvType);
_JumpIfErrorStr(hr, error, "csiGetProviderTypeFromProviderName", pwszProvider);
hr = EnumKeys(
pwszProvider,
dwProvType,
fSkipKeys,
pwszKeyContainerName);
_JumpIfErrorStr(hr, error, "EnumKeys", pwszProvider);
}
else
{
for (i = 0; ; i++)
{
CSASSERT(NULL == pwszProvName);
hr = myEnumProviders(i, NULL, 0, &dwProvType, &pwszProvName);
if (S_OK != hr)
{
if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr ||
NTE_FAIL == hr)
{
// no more providers under type, out of i loop
break;
}
// invalid csp entry, skip it
wprintf(myLoadResourceString(IDS_FORMAT_SKIP_CSP_ENUM), i);
wprintf(wszNewLine);
}
else
{
hr = EnumKeys(
pwszProvName,
dwProvType,
fSkipKeys,
pwszKeyContainerName);
_JumpIfErrorStr(hr, error, "EnumKeys", pwszProvName);
LocalFree(pwszProvName);
pwszProvName = NULL;
}
}
}
hr = S_OK;
error:
if (NULL != pwszProvName)
{
LocalFree(pwszProvName);
}
if (NULL != pwszProvNameDefault)
{
LocalFree(pwszProvNameDefault);
}
return(hr);
}
HRESULT
cuSanitizeNameWithSuffix(
IN WCHAR const *pwszName,
OUT WCHAR **ppwszNameOut)
{
HRESULT hr;
WCHAR const *pwszSuffix;
WCHAR const *pwsz;
WCHAR *pwszBase = NULL;
WCHAR *pwszSanitizedName = NULL;
DWORD cwc;
pwsz = wcsrchr(pwszName, wcLPAREN);
pwszSuffix = pwsz;
if (NULL != pwsz)
{
BOOL fSawDigit = FALSE;
pwsz++;
while (iswdigit(*pwsz))
{
pwsz++;
fSawDigit = TRUE;
}
if (fSawDigit &&
wcRPAREN == *pwsz &&
(L'.' == pwsz[1] || L'\0' == pwsz[1]))
{
cwc = SAFE_SUBTRACT_POINTERS(pwszSuffix, pwszName);
pwszBase = (WCHAR *) LocalAlloc(
LMEM_FIXED,
(cwc + 1) * sizeof(WCHAR));
if (NULL == pwszBase)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
CopyMemory(pwszBase, pwszName, cwc * sizeof(WCHAR));
pwszBase[cwc] = L'\0';
pwszName = pwszBase;
}
else
{
pwszSuffix = NULL;
}
}
hr = mySanitizeName(pwszName, &pwszSanitizedName);
_JumpIfError(hr, error, "mySanitizeName");
if (NULL == pwszSuffix)
{
*ppwszNameOut = pwszSanitizedName;
pwszSanitizedName = NULL;
}
else
{
*ppwszNameOut = (WCHAR *) LocalAlloc(
LMEM_FIXED,
(wcslen(pwszSanitizedName) +
wcslen(pwszSuffix) +
1) * sizeof(WCHAR));
if (NULL == *ppwszNameOut)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
wcscpy(*ppwszNameOut, pwszSanitizedName);
wcscat(*ppwszNameOut, pwszSuffix);
}
hr = S_OK;
error:
if (NULL != pwszSanitizedName)
{
LocalFree(pwszSanitizedName);
}
if (NULL != pwszBase)
{
LocalFree(pwszBase);
}
return(hr);
}
HRESULT
verbDelKey(
IN WCHAR const *pwszOption,
IN WCHAR const *pwszKeyContainerName,
IN WCHAR const *pwszArg2,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
HCRYPTPROV hProv = NULL;
WCHAR *pwszProvider = g_pwszCSP;
WCHAR *pwszProvNameDefault = NULL;
WCHAR *apwszKeyContainer[3];
DWORD i;
DWORD dwProviderType;
DWORD dwFlags = CRYPT_DELETEKEYSET;
// If supplied provider is NULL, use the default provider.
if (pwszProvider == NULL)
{
hr = myCryptGetDefaultProvider(
PROV_RSA_FULL,
g_fUserRegistry?
CRYPT_USER_DEFAULT : CRYPT_MACHINE_DEFAULT,
&pwszProvNameDefault);
_JumpIfError(hr, error, "myCryptGetDefaultProvider");
pwszProvider = pwszProvNameDefault;
}
apwszKeyContainer[0] = const_cast<WCHAR *>(pwszKeyContainerName);
apwszKeyContainer[1] = NULL;
apwszKeyContainer[2] = NULL;
hr = mySanitizeName(pwszKeyContainerName, &apwszKeyContainer[1]);
_JumpIfError(hr, error, "mySanitizeName");
hr = cuSanitizeNameWithSuffix(pwszKeyContainerName, &apwszKeyContainer[2]);
_JumpIfError(hr, error, "cuSanitizeNameWithSuffix");
hr = csiGetProviderTypeFromProviderName(pwszProvider, &dwProviderType);
_JumpIfError(hr, error, "csiGetProviderTypeFromProviderName");
if (g_fCryptSilent)
{
dwFlags |= CRYPT_SILENT;
}
for (i = 0; i < ARRAYSIZE(apwszKeyContainer); i++)
{
if (!myCertSrvCryptAcquireContext(
&hProv,
apwszKeyContainer[i],
pwszProvider,
dwProviderType,
dwFlags,
!g_fUserRegistry)) // fMachineKeyset
{
hr = myHLastError();
_PrintErrorStr2(
hr,
"myCertSrvCryptAcquireContext",
apwszKeyContainer[i],
hr);
}
else
{
DWORD j;
wprintf(L" %ws", apwszKeyContainer[i]);
if (g_fVerbose)
{
wprintf(L" --");
for (j = 0; j < ARRAYSIZE(apwszKeyContainer); j++)
{
wprintf(L" %ws", apwszKeyContainer[j]);
}
}
wprintf(wszNewLine);
hr = S_OK;
break;
}
}
_JumpIfError(hr, error, "myCertSrvCryptAcquireContext");
error:
for (i = 1; i < ARRAYSIZE(apwszKeyContainer); i++)
{
if (NULL != apwszKeyContainer[i])
{
LocalFree(apwszKeyContainer[i]);
}
}
if (NULL != pwszProvNameDefault)
{
LocalFree(pwszProvNameDefault);
}
return(hr);
}