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
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);
|
|
}
|