2025-04-27 07:49:33 -04:00

4610 lines
100 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1995 - 1999
//
// File: store.cpp
//
//--------------------------------------------------------------------------
#include <pch.cpp>
#pragma hdrstop
#include <setupapi.h>
#include "ocmanage.h"
#include "initcert.h"
#include "cscsp.h"
#include "csber.h"
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
// .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 = cuGetLong(pwszCTL, (LONG *) piCTL);
if (S_OK != hr || 64*1024 <= *piCTL)
{
fNumericIndex = FALSE;
}
}
}
if (fNumericIndex && L'\0' != *pwszCRL)
{
hr = cuGetLong(pwszCRL, (LONG *) piCRL);
if (S_OK != hr || 64*1024 <= *piCRL)
{
fNumericIndex = FALSE;
}
}
}
}
if (fNumericIndex && L'\0' != *pwszCert)
{
hr = cuGetLong(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 (g_fVerbose)
{
wprintf(
L"pwszCertIndex=%ws, Name=%ws idx=%d.%d.%d\n",
pwszCertIndex,
*ppwszCertName,
*piCert,
*piCRL,
*piCTL);
}
hr = S_OK;
error:
if (NULL != pwszCopy)
{
LocalFree(pwszCopy);
}
return(hr);
}
HRESULT
SavePFXStoreToFile(
IN HCERTSTORE hStorePFX,
IN WCHAR const *pwszfnOut,
IN WCHAR const *pwszPassword,
IN OUT WCHAR **ppwszPassword)
{
HRESULT hr;
CRYPT_DATA_BLOB pfx;
WCHAR wszPassword[MAX_PATH];
pfx.pbData = NULL;
if (NULL == *ppwszPassword)
{
if (NULL == pwszPassword || 0 == wcscmp(L"*", pwszPassword))
{
wprintf(L"Enter new password for output file %ws:\n", pwszfnOut);
hr = cuGetPassword(TRUE, wszPassword, ARRAYSIZE(wszPassword));
_JumpIfError(hr, error, "cuGetPassword");
pwszPassword = wszPassword;
}
hr = myDupString(pwszPassword, ppwszPassword);
_JumpIfError(hr, error, "myDupString");
}
pwszPassword = *ppwszPassword;
// 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(
hStorePFX,
&pfx,
pwszPassword,
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");
error:
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);
_JumpIfError(hr, error, "myAddChainToMemoryStore");
// End Chain Building
hr = SavePFXStoreToFile(
hTempMemoryStore,
pwszfnOut,
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
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,
NULL == strSerialNumber && // fAllowMissingCN
NULL == pbHash,
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 != 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)
{
if (!CryptFindCertificateKeyProvInfo(
pCert,
0, // dwFlags
NULL)) // pvReserved
{
hr = myHLastError();
_PrintError(hr, "CryptFindCertificateKeyProvInfo");
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,
NULL,
0,
&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,
TRUE, // 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 != 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 != 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,
0,
&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)
{
LocalFree(pwszPassword);
}
return(hr);
}
#define wszLDAPPREFIX L"ldap:///"
HRESULT
cuOpenCertStore(
IN WCHAR const *pwszStoreName,
IN OUT DWORD *pMode,
OUT HCERTSTORE *phStore)
{
HRESULT hr;
WCHAR awc[7];
LPCSTR pszStoreProvider = CERT_STORE_PROV_SYSTEM_REGISTRY_W;
WCHAR *pwszStoreAlloc = NULL;
WCHAR *pwszStoreAlloc2 = NULL;
if (NULL == pwszStoreName ||
0 == wcscmp(L"*", pwszStoreName) ||
0 == lstrcmpi(wszCA_CERTSTORE, pwszStoreName))
{
pwszStoreName = wszCA_CERTSTORE;
*pMode |= DVNS_CASTORE;
}
wcsncpy(awc, pwszStoreName, ARRAYSIZE(awc));
awc[ARRAYSIZE(awc) - 1] = L'\0';
if (0 == lstrcmpi(L"ldap:/", awc))
{
pszStoreProvider = CERT_STORE_PROV_LDAP_W;
*pMode |= DVNS_DSSTORE;
}
else
{
awc[3] = L'\0';
if (0 == lstrcmpi(L"CN=", awc))
{
pszStoreProvider = CERT_STORE_PROV_LDAP_W;
pwszStoreAlloc = (WCHAR *) LocalAlloc(
LMEM_FIXED,
(WSZARRAYSIZE(wszLDAPPREFIX) + wcslen(pwszStoreName) + 1) *
sizeof(WCHAR));
if (NULL == pwszStoreAlloc)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
wcscpy(pwszStoreAlloc, wszLDAPPREFIX);
wcscat(pwszStoreAlloc, pwszStoreName);
pwszStoreName = pwszStoreAlloc;
*pMode |= DVNS_DSSTORE;
}
}
if (DVNS_DSSTORE & *pMode)
{
hr = myInternetUncanonicalizeURL(pwszStoreName, &pwszStoreAlloc2);
_JumpIfError(hr, error, "myInternetUncanonicalizeURL");
pwszStoreName = pwszStoreAlloc2;
}
*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);
}
hr = S_OK;
error:
if (NULL != pwszStoreAlloc)
{
LocalFree(pwszStoreAlloc);
}
if (NULL != pwszStoreAlloc2)
{
LocalFree(pwszStoreAlloc2);
}
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, &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
verbViewOrDeleteStore(
IN WCHAR const *pwszOption,
OPTIONAL IN WCHAR const *pwszStoreName,
OPTIONAL IN WCHAR const *pwszCertIndex,
OPTIONAL IN WCHAR const *pwszfnOut,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
WCHAR *pwszCertName = NULL;
DWORD Mode;
DWORD iCert;
DWORD iCRL;
DWORD iCTL;
HCERTSTORE hStore = NULL;
CERT_CONTEXT const *pCert = NULL;
BOOL fDelete = g_wszViewDelStore == pwszOption;
WCHAR *pwszSubject = NULL;
hr = ParseCertCRLIndex(pwszCertIndex, &pwszCertName, &iCert, &iCRL, &iCTL);
_JumpIfErrorStr(hr, error, "ParseCertCRLIndex", pwszCertIndex);
Mode = DVNS_SAVECERT;
if (fDelete)
{
Mode |= DVNS_WRITESTORE;
}
hr = cuOpenCertStore(pwszStoreName, &Mode, &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)
{
if (!CertDeleteCertificateFromStore(pCert))
{
hr = myHLastError();
_JumpError(hr, error, "CertDeleteCertificateFromStore");
}
pCert = NULL;
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 != pCert)
{
CertFreeCertificateContext(pCert);
}
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 *pwszCertIndex,
IN WCHAR const *pwszfnOut,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
WCHAR *pwszCertName = NULL;
DWORD iCert;
DWORD iCRL;
DWORD iCTL;
hr = ParseCertCRLIndex(pwszCertIndex, &pwszCertName, &iCert, &iCRL, &iCTL);
_JumpIfErrorStr(hr, error, "ParseCertCRLIndex", pwszCertIndex);
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
verbAddStore(
IN WCHAR const *pwszOption,
IN WCHAR const *pwszStoreName,
IN WCHAR const *pwszfnIn,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
WCHAR *pwszStore = NULL;
DWORD Mode;
HCERTSTORE hStore = NULL;
CERT_CONTEXT const *pCertContext = NULL;
CRL_CONTEXT const *pCRLContext = NULL;
BOOL fRoot = FALSE;
Mode = DVNS_WRITESTORE; // force open for write
hr = cuOpenCertStore(pwszStoreName, &Mode, &hStore);
if (S_OK != hr)
{
wprintf(myLoadResourceString(
g_fForce?
IDS_CANNOT_CREATE_STORE : // "Cannot open Cert store."
IDS_CANNOT_OPEN_STORE)); // "Cannot open existing Cert store. Use -f switch to force Cert store creation."
wprintf(wszNewLine);
_JumpErrorStr(hr, error, "cuOpenCertStore", pwszStoreName);
}
// Load and decode certificate
hr = cuLoadCert(pwszfnIn, &pCertContext);
if (S_OK != hr)
{
if (CRYPT_E_ASN1_BADTAG != hr)
{
_JumpError(hr, error, "cuLoadCert");
}
hr = cuLoadCRL(pwszfnIn, &pCRLContext);
_JumpIfError(hr, error, "cuLoadCRL");
if (!CertAddCRLContextToStore(
hStore,
pCRLContext,
CERT_STORE_ADD_REPLACE_EXISTING,
NULL))
{
hr = myHLastError();
_JumpError(hr, error, "CertAddCRLContextToStore");
}
}
else
{
if (CertCompareCertificateName(
X509_ASN_ENCODING,
&pCertContext->pCertInfo->Issuer,
&pCertContext->pCertInfo->Subject))
{
hr = cuVerifySignature(
pCertContext->pbCertEncoded,
pCertContext->cbCertEncoded,
&pCertContext->pCertInfo->SubjectPublicKeyInfo,
FALSE);
fRoot = S_OK == hr;
_PrintIfError(hr, "cuVerifySignature");
}
if (0 == lstrcmpi(pwszStoreName, L"root") && !fRoot)
{
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");
}
if (!CertAddCertificateContextToStore(
hStore,
pCertContext,
CERT_STORE_ADD_REPLACE_EXISTING,
NULL))
{
hr = myHLastError();
_JumpError(hr, error, "CertAddCertificateContextToStore");
}
}
hr = S_OK;
error:
cuUnloadCert(&pCertContext);
cuUnloadCRL(&pCRLContext);
if (NULL != pwszStore)
{
LocalFree(pwszStore);
}
if (NULL != hStore)
{
CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
}
return(hr);
}
HRESULT
verbDelStore(
IN WCHAR const *pwszOption,
IN WCHAR const *pwszStoreName,
IN WCHAR const *pwszCertIndex,
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;
if (NULL == pwszStoreName || 0 == wcscmp(L"*", pwszStoreName))
{
pwszStoreName = wszCA_CERTSTORE;
}
hr = ParseCertCRLIndex(pwszCertIndex, &pwszCertName, &iCertDel, &iCRLDel, &iCTLDel);
_JumpIfErrorStr(hr, error, "ParseCertCRLIndex", pwszCertIndex);
if (MAXDWORD == iCertDel && NULL == pwszCertName && MAXDWORD == iCRLDel)
{
hr = E_INVALIDARG;
_JumpErrorStr(hr, error, "incomplete Index arg", pwszCertIndex);
}
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, &hStore);
_JumpIfError(hr, error, "cuOpenCertStore");
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);
pCertT = CertDuplicateCertificateContext(pCert);
if (!CertDeleteCertificateFromStore(pCertT))
{
hr = myHLastError();
_JumpError(hr, error, "CertDeleteCertificateFromStore");
}
if (iCert == iCertDel)
{
break;
}
}
}
}
if (MAXDWORD != iCRLDel)
{
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);
pCRLT = CertDuplicateCRLContext(pCRL);
if (!CertDeleteCRLFromStore(pCRLT))
{
hr = myHLastError();
_JumpError(hr, error, "CertDeleteCRLFromStore");
}
if (iCRL == iCRLDel)
{
break;
}
}
}
}
hr = S_OK;
error:
if (NULL != strSerialNumber)
{
SysFreeString(strSerialNumber);
}
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 *pwszCertIndex,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
WCHAR *pwszCertName = NULL;
DWORD iCert;
DWORD iCRL;
DWORD iCTL;
hr = ParseCertCRLIndex(pwszCertIndex, &pwszCertName, &iCert, &iCRL, &iCTL);
_JumpIfErrorStr(hr, error, "ParseCertCRLIndex", pwszCertIndex);
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 *pwszCertIndex,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
WCHAR *pwszCertName = NULL;
DWORD iCert;
DWORD iCRL;
DWORD iCTL;
hr = ParseCertCRLIndex(pwszCertIndex, &pwszCertName, &iCert, &iCRL, &iCTL);
_JumpIfErrorStr(hr, error, "ParseCertCRLIndex", pwszCertIndex);
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 *pwszCertIndex,
IN WCHAR const *pwszfnPVKBaseName,
IN WCHAR const *pwszStoreName,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
WCHAR *pwszCertName = NULL;
DWORD iCert;
DWORD iCRL;
DWORD iCTL;
hr = ParseCertCRLIndex(pwszCertIndex, &pwszCertName, &iCert, &iCRL, &iCTL);
_JumpIfErrorStr(hr, error, "ParseCertCRLIndex", pwszCertIndex);
hr = DumpAndVerifyNamedStore(
NULL == pwszStoreName? wszMY_CERTSTORE : pwszStoreName,
DVNS_SAVEPVK | DVNS_DUMPKEYS,
pwszCertName,
iCert,
iCRL,
iCTL,
pwszfnPVKBaseName,
NULL);
_JumpIfError(hr, error, "DumpAndVerifyNamedStore");
error:
if (NULL != pwszCertName)
{
LocalFree(pwszCertName);
}
return(hr);
}
HRESULT
verbExportPFX(
IN WCHAR const *pwszOption,
IN WCHAR const *pwszCertIndex,
IN WCHAR const *pwszfnPFX,
IN WCHAR const *pwszPassword,
IN WCHAR const *pwszStoreName)
{
HRESULT hr;
WCHAR *pwszCertName = NULL;
DWORD iCert;
DWORD iCRL;
DWORD iCTL;
hr = ParseCertCRLIndex(pwszCertIndex, &pwszCertName, &iCert, &iCRL, &iCTL);
_JumpIfErrorStr(hr, error, "ParseCertCRLIndex", pwszCertIndex);
hr = DumpAndVerifyNamedStore(
NULL == pwszStoreName? wszMY_CERTSTORE : pwszStoreName,
DVNS_SAVEPFX | DVNS_DUMPKEYS,
pwszCertName,
iCert,
iCRL,
iCTL,
pwszfnPFX,
pwszPassword);
_JumpIfError(hr, error, "DumpAndVerifyNamedStore");
error:
if (NULL != pwszCertName)
{
LocalFree(pwszCertName);
}
return(hr);
}
HRESULT
cuImportChainAndKeys(
IN CERT_CHAIN_CONTEXT const *pChain,
IN BOOL fUser,
OPTIONAL IN WCHAR const *pwszStoreName)
{
HRESULT hr;
CRYPT_KEY_PROV_INFO *pkpi = NULL;
WCHAR *pwszSimpleName = NULL;
WCHAR *pwszRawContainerName = NULL;
WCHAR *pwszKeyContainerName = NULL;
CERT_CONTEXT const *pcc;
DWORD cwc;
WCHAR *pwsz;
if (NULL == pwszStoreName)
{
pwszStoreName = wszMY_CERTSTORE;
}
pcc = pChain->rgpChain[0]->rgpElement[0]->pCertContext;
hr = myCertGetNameString(
pcc,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
&pwszSimpleName);
_JumpIfError(hr, error, "myCertGetNameString");
hr = myCertGetKeyProviderInfo(pcc, &pkpi);
_JumpIfError(hr, error, "myCertGetKeyProviderInfo");
for (pwsz = pkpi->pwszContainerName; L'\0' != *pwsz; pwsz++)
{
if (L'A' <= *pwsz && L'F' >= *pwsz)
{
*pwsz += L'a' - L'A';
}
}
pwsz = pkpi->pwszContainerName;
if (wcLBRACE == *pwsz)
{
pwsz++;
}
cwc = wcslen(pwszSimpleName) + 1 + wcslen(pwsz);
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, pwsz);
pwsz = &pwszRawContainerName[wcslen(pwszRawContainerName) - 1];
if (wcLBRACE == *pkpi->pwszContainerName && wcRBRACE == *pwsz)
{
*pwsz = L'\0';
}
hr = mySanitizeName(pwszRawContainerName, &pwszKeyContainerName);
_JumpIfError(hr, error, "mySanitizeName");
wprintf(L"%ws -- %ws\n", pwszSimpleName, pwszKeyContainerName);
hr = myCopyKeys(
pkpi,
pkpi->pwszContainerName, // pwszOldContainer
pwszKeyContainerName, // pwszNewContainer
fUser, // fOldUserKey
fUser, // fNewUserKey
g_fForce);
_JumpIfError(hr, error, "myCopyKeys");
pkpi->pwszContainerName = pwszKeyContainerName;
hr = mySaveChainAndKeys(
pChain->rgpChain[0],
pwszStoreName,
cuGetSystemStoreFlags(),
pkpi,
NULL);
_JumpIfError(hr, error, "mySaveChainAndKeys");
error:
if (NULL != pkpi)
{
LocalFree(pkpi);
}
if (NULL != pwszSimpleName)
{
LocalFree(pwszSimpleName);
}
if (NULL != pwszRawContainerName)
{
LocalFree(pwszRawContainerName);
}
if (NULL != pwszKeyContainerName)
{
LocalFree(pwszKeyContainerName);
}
return(hr);
}
HRESULT
verbImportPFX(
IN WCHAR const *pwszOption,
IN WCHAR const *pwszfnPFX,
IN WCHAR const *pwszPassword,
IN WCHAR const *pwszStoreName,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
CRYPT_DATA_BLOB pfx;
WCHAR wszPassword[MAX_PATH];
HCERTSTORE hStorePFX = NULL;
RESTORECHAIN *paRestoreChain = NULL;
DWORD cRestoreChain;
DWORD iChain;
BOOL fUser = !g_fEnterpriseRegistry && g_fUserRegistry;
pfx.pbData = NULL;
if (NULL == pwszPassword || 0 == wcscmp(L"*", pwszPassword))
{
hr = cuGetPassword(FALSE, wszPassword, ARRAYSIZE(wszPassword));
_JumpIfError(hr, error, "cuGetPassword");
pwszPassword = wszPassword;
}
hr = DecodeFileW(pwszfnPFX, &pfx.pbData, &pfx.cbData, CRYPT_STRING_ANY);
_JumpIfError(hr, error, "DecodeFileW");
CSASSERT(NULL != pfx.pbData);
if (!PFXIsPFXBlob(&pfx))
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "PFXIsPFXBlob");
}
hStorePFX = myPFXImportCertStore(
&pfx,
pwszPassword,
CRYPT_EXPORTABLE |
(fUser? 0 : CRYPT_MACHINE_KEYSET));
if (NULL == hStorePFX)
{
hr = myHLastError();
_JumpError(hr, error, "myPFXImportCertStore");
}
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, fUser, pwszStoreName);
_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);
}
if (NULL != pfx.pbData)
{
LocalFree(pfx.pbData);
}
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
AddPFXToStore(
IN WCHAR const *pwszfn,
IN HCERTSTORE hStoreMerge,
IN OUT WCHAR ***papwszPasswordList)
{
HRESULT hr;
WCHAR const * const *ppwszPasswordList = *papwszPasswordList;
DWORD i;
CRYPT_DATA_BLOB pfx;
HCERTSTORE hStorePFX = NULL;
WCHAR wszPassword[MAX_PATH];
WCHAR const *pwszPassword;
CERT_CONTEXT const *pCert = NULL;
pfx.pbData = NULL;
hr = DecodeFileW(pwszfn, &pfx.pbData, &pfx.cbData, CRYPT_STRING_ANY);
_JumpIfError(hr, error, "DecodeFileW");
if (!PFXIsPFXBlob(&pfx))
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "PFXIsPFXBlob");
}
// Try all of the passwords collected so far.
if (NULL != ppwszPasswordList)
{
for (i = 0; NULL != ppwszPasswordList[i]; i++)
{
hStorePFX = myPFXImportCertStore(
&pfx,
ppwszPasswordList[i],
CRYPT_EXPORTABLE);
if (NULL != hStorePFX)
{
break;
}
hr = myHLastError();
_PrintError2(
hr,
"myPFXImportCertStore",
HRESULT_FROM_WIN32(ERROR_INVALID_PASSWORD));
}
}
// Try the unparsed command line password, or collect a new one.
pwszPassword = g_pwszPassword;
while (NULL == hStorePFX)
{
if (NULL != pwszPassword)
{
hStorePFX = myPFXImportCertStore(
&pfx,
pwszPassword,
CRYPT_EXPORTABLE);
if (NULL != hStorePFX)
{
break;
}
hr = myHLastError();
_PrintError2(
hr,
"myPFXImportCertStore",
HRESULT_FROM_WIN32(ERROR_INVALID_PASSWORD));
}
wprintf(L"Enter password for %ws:\n", pwszfn);
hr = cuGetPassword(FALSE, wszPassword, ARRAYSIZE(wszPassword));
_JumpIfError(hr, error, "cuGetPassword");
hr = AddStringToList(wszPassword, papwszPasswordList);
_JumpIfError(hr, error, "AddStringToList");
pwszPassword = wszPassword;
}
CSASSERT(NULL != hStorePFX);
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, FALSE);
CertCloseStore(hStorePFX, CERT_CLOSE_STORE_CHECK_FLAG);
}
if (NULL != pfx.pbData)
{
LocalFree(pfx.pbData);
}
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;
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");
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");
}
for (i = 0; NULL != ppwszfnList[i]; i++)
{
hr = AddPFXToStore(
ppwszfnList[i],
hStoreMerge,
&ppwszPasswordList);
_JumpIfError(hr, error, "AddPFXToStore");
}
hr = SavePFXStoreToFile(
hStoreMerge,
pwszfnPFXOutFile,
pwszPasswordOut,
&pwszPasswordAlloc);
_JumpIfError(hr, error, "SavePFXStoreToFile");
error:
if (NULL != hStoreMerge)
{
myDeleteGuidKeys(hStoreMerge, FALSE);
CertCloseStore(hStoreMerge, CERT_CLOSE_STORE_CHECK_FLAG);
}
cuFreeStringArray(ppwszPasswordList);
cuFreeStringArray(ppwszfnList);
if (NULL != pwszPasswordAlloc)
{
LocalFree(pwszPasswordAlloc);
}
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
DecodeSequence(
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);
}
//+-------------------------------------------------------------------------
// 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,
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 = DecodeSequence(pbKMSRSAKey, cbKMSRSAKey, ISO_MAX, &pSeqOuter);
_JumpIfError(hr, error, "DecodeSequence");
hr = VerifyKeyVersion(
pSeqOuter->rgValue[ISO_VERSION].pbData,
pSeqOuter->rgValue[ISO_VERSION].cbData);
_JumpIfError(hr, error, "VerifyKeyVersion");
hr = DecodeSequence(
pSeqOuter->rgValue[ISO_ALG].pbData,
pSeqOuter->rgValue[ISO_ALG].cbData,
ISA_MAX,
&pSeqAlg);
_JumpIfError(hr, error, "DecodeSequence");
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 = DecodeSequence(
pBlobKey->pbData,
pBlobKey->cbData,
ARRAYSIZE(apIntKey),
&pSeqKey);
_JumpIfError(hr, error, "DecodeSequence");
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");
}
}
cbitKey = apIntKey[ISK_MODULUS]->cbData * 8;
#if 0
for (i = 0; i < ARRAYSIZE(apIntKey); i++)
{
wprintf(wszNewLine);
DumpHex(
DH_NOTABPREFIX | DH_NOASCIIHEX | 4,
apIntKey[i]->pbData,
apIntKey[i]->cbData);
}
#endif
cbKey = sizeof(BLOBHEADER) + 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;
((BLOBHEADER *) pb)->bType = PRIVATEKEYBLOB;
((BLOBHEADER *) pb)->bVersion = CUR_BLOB_VERSION;
((BLOBHEADER *) pb)->aiKeyAlg = CALG_RSA_KEYX;
pb += sizeof(BLOBHEADER);
((RSAPUBKEY *) pb)->magic = 0x32415352; // "RSA2"
((RSAPUBKEY *) pb)->bitlen = cbitKey;
((RSAPUBKEY *) pb)->pubexp = dwPubExp;
pb += sizeof(RSAPUBKEY);
for (i = 0; i < ARRAYSIZE(g_akbm); i++)
{
CSASSERT(ISK_MAX > g_akbm[i].dwisk);
cb = cbitKey / g_akbm[i].dwdivisor;
if (cb != apIntKey[g_akbm[i].dwisk]->cbData)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "Bad key element size");
}
CopyMemory(pb, apIntKey[g_akbm[i].dwisk]->pbData, cb);
pb += cb;
}
CSASSERT(pb = &pbKey[cbKey]);
if (g_fVerbose)
{
wprintf(L"%d bit key\n", cbitKey);
if (1 < g_fVerbose)
{
DumpHex(DH_NOTABPREFIX | 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);
}
HRESULT
myVerifyKMSKey(
IN BYTE const *pbCert,
IN DWORD cbCert,
IN BYTE const *pbKey,
IN DWORD cbKey)
{
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,
AT_KEYEXCHANGE,
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);
cuDumpPublicKey(pPublicKeyInfo);
}
}
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);
wprintf(myLoadResourceString(IDS_ERR_PUBLICKEY_MISMATCH)); // "ERROR: Certificate public key does NOT match stored keyset"
wprintf(wszNewLine);
_JumpError(hr, error, "myCertComparePublicKeyInfo");
}
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(L"Private key verifies\n");
}
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[20];
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(L"Processing KMS exports from:");
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(L"KMS export file signature verifies\n");
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 {
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 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 (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");
}
if (g_fVerbose)
{
wprintf(L"User: %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(L"Encrypted key:\n");
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(L"Decrypted key:\n");
DumpHex(0, pbKeyASN, cb);
}
hr = myDecodeKMSRSAKey(pbKeyASN, cbKeyASN, &pbKey, &cbKey);
_JumpIfError(hr, error, "myDecodeKMSRSAKey");
hr = myVerifyKMSKey(pbCert, cbCert, pbKey, cbKey);
_PrintIfError(hr, "myVerifyKMSKey");
hr = ArchiveCertAndKey(
pdiAdmin,
pccXchg,
pbCert,
cbCert,
pbKey,
cbKey,
pkmsStats);
_PrintIfError2(hr, "ArchiveCertAndKey", NTE_BAD_SIGNATURE);
ZeroMemory(pbKey, cbKey); // Key material
LocalFree(pbKey);
}
ZeroMemory(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)
{
ZeroMemory(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);
}
}
}
VOID
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));
}
HRESULT
ImportKMSExportedUsers(
IN HANDLE hFile,
IN DWORD cbFile,
IN HCRYPTPROV hProvKMS,
IN HCRYPTKEY hkeyKMS)
{
HRESULT hr;
DWORD cbRemain;
DWORD cbRead;
TagHeader th;
BYTE *pb = NULL;
HCRYPTKEY hkeySym = NULL;
KMSSTATS kmsStats;
DISPATCHINTERFACE diAdmin;
BOOL fMustRelease = FALSE;
CERT_CONTEXT const *pccXchg = NULL;
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");
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))
{
hr = myHLastError();
_PrintError(hr, "CryptImportKey");
wprintf(L"Failed to import symmetric key\n");
}
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(L"Lock box opened, symmetric key successfully decrypted\n");
}
}
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);
}
DumpKMSStats(&kmsStats);
hr = S_OK;
error:
if (NULL != pccXchg)
{
CertFreeCertificateContext(pccXchg);
}
if (fMustRelease)
{
Admin_Release(&diAdmin);
}
if (NULL != hkeySym)
{
CryptDestroyKey(hkeySym);
}
return(hr);
}
HRESULT
LoadKMSCert(
IN WCHAR const *pwszCertId,
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),
pwszCertId,
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 (g_fVerbose)
{
wprintf(L"CryptAcquireContext(%ws)\n", pkpiKMS->pwszContainerName);
}
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,
0,
phkeyKMS))
{
hr = myHLastError();
_JumpError(hr, error, "CryptImportKey");
}
wprintf(L"Moved AT_SIGNATURE key to AT_KEYEXCHANGE\n");
}
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,
0))
{
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);
_JumpIfError(hr, error, "myVerifyKMSKey");
hr = ArchiveCertAndKey(
pdiAdmin,
pccXchg,
pCert->pbCertEncoded,
pCert->cbCertEncoded,
pbKey,
cbKey,
pkmsStats);
_JumpIfError(hr, error, "ArchiveCertAndKey");
error:
if (NULL != pbKey)
{
ZeroMemory(pbKey, cbKey); // Key material
LocalFree(pbKey);
}
if (NULL != hProv)
{
CryptReleaseContext(hProv, 0);
}
if (NULL != pkpi)
{
LocalFree(pkpi);
}
return(hr);
}
HRESULT
ImportKMSPFXFile(
IN WCHAR const *pwszfn)
{
HRESULT hr;
CRYPT_DATA_BLOB pfx;
WCHAR wszPassword[MAX_PATH];
WCHAR const *pwszPassword;
CERT_CONTEXT const *pccXchg = NULL;
HCERTSTORE hStorePFX = NULL;
CERT_CONTEXT const *pCert = NULL;
DISPATCHINTERFACE diAdmin;
BOOL fMustRelease = FALSE;
KMSSTATS kmsStats;
ZeroMemory(&kmsStats, sizeof(kmsStats));
pfx.pbData = NULL;
hr = DecodeFileW(pwszfn, &pfx.pbData, &pfx.cbData, CRYPT_STRING_ANY);
if (S_OK != hr)
{
cuPrintError(IDS_ERR_FORMAT_DECODEFILE, hr);
goto error;
}
if (!PFXIsPFXBlob(&pfx))
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "not a PFX");
}
pwszPassword = g_pwszPassword;
if (NULL == pwszPassword)
{
hr = cuGetPassword(FALSE, wszPassword, ARRAYSIZE(wszPassword));
_JumpIfError(hr, error, "cuGetPassword");
}
hStorePFX = myPFXImportCertStore(&pfx, pwszPassword, CRYPT_EXPORTABLE);
if (NULL == hStorePFX)
{
hr = myHLastError();
_JumpError(hr, error, "myPFXImportCertStore");
}
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");
}
DumpKMSStats(&kmsStats);
hr = S_OK;
error:
if (NULL != hStorePFX)
{
myDeleteGuidKeys(hStorePFX, FALSE);
CertCloseStore(hStorePFX, CERT_CLOSE_STORE_CHECK_FLAG);
}
if (NULL != pccXchg)
{
CertFreeCertificateContext(pccXchg);
}
if (fMustRelease)
{
Admin_Release(&diAdmin);
}
if (NULL != pfx.pbData)
{
LocalFree(pfx.pbData);
}
return(hr);
}
HRESULT
ImportKMSExportFile(
IN WCHAR const *pwszfnKMS,
IN WCHAR const *pwszCertId,
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(pwszCertId, &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 *pwszCertId,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
BOOL fBadTag;
hr = ImportKMSExportFile(pwszfnKMS, pwszCertId, &fBadTag);
if (S_OK != hr)
{
_PrintError(hr, "ImportKMSExportFile");
if (!fBadTag)
{
goto error;
}
hr = ImportKMSPFXFile(pwszfnKMS);
_JumpIfError(hr, error, "ImportKMSPFXFile");
}
error:
return(hr);
}
WCHAR const g_wszProviderNameDefault[] = MS_DEF_PROV_W;
DWORD g_dwProviderType = PROV_RSA_FULL;
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 == lstrcmpi(pwszKeyContainerName, pwszRevert))
{
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,
NULL,
&pPubKeyInfoSig,
&pPubKeyInfoXchg);
if (S_OK != hr)
{
cuPrintError(IDS_ERR_FORMAT_LOADKEYS, hr);
}
if (NULL != pPubKeyInfoSig || NULL != pPubKeyInfoXchg)
{
pwszPrefix = g_wszPad4;
if (NULL != pPubKeyInfoSig)
{
wprintf(L" AT_SIGNATURE");
LocalFree(pPubKeyInfoSig);
pPubKeyInfoSig = NULL;
pwszPrefix = L", ";
}
if (NULL != pPubKeyInfoXchg)
{
wprintf(L"%wsAT_KEYEXCHANGE", pwszPrefix);
LocalFree(pPubKeyInfoXchg);
pPubKeyInfoXchg = NULL;
}
wprintf(wszNewLine);
}
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,
OPTIONAL IN WCHAR const *pwszProvider,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
WCHAR *pwszProvName = NULL;
DWORD i;
DWORD dwProvType;
BOOL fSkipKeys = FALSE;
if (NULL == pwszProvider)
{
pwszProvider = g_wszProviderNameDefault; // default CSP
}
else if (0 == lstrcmp(L"*", pwszProvider))
{
pwszProvider = NULL; // all CSPs
}
if (NULL != pwszKeyContainerName)
{
if (0 == lstrcmp(L"*", pwszKeyContainerName))
{
pwszKeyContainerName = NULL; // all keys
}
else if (0 == lstrcmp(L"-", 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(L"Failed to enum CSP at (%ld)\n", i);
}
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);
}
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,
OPTIONAL IN WCHAR const *pwszProvider,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
HCRYPTPROV hProv = NULL;
WCHAR *apwszKeyContainer[3];
DWORD i, dwProviderType;
DWORD dwFlags = CRYPT_DELETEKEYSET;
// If supplied provider is NULL, use the default provider.
if (pwszProvider == NULL)
{
pwszProvider = g_wszProviderNameDefault;
}
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]);
}
}
return(hr);
}