|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1995 - 1999
//
// File: admin.cpp
//
//--------------------------------------------------------------------------
#include <pch.cpp>
#pragma hdrstop
#include <setupapi.h>
#include <ocmanage.h>
#include "initcert.h"
#include "cscsp.h"
#define __dwFILE__ __dwFILE_CERTUTIL_ADMIN_CPP__
#define wszV1SUFFIX L"-v1"
#define wszP12SUFFIX L".p12"
#define wszRECSUFFIX L".rec"
#define wszEPFSUFFIX L".epf"
HRESULT verbDenyRequest( IN WCHAR const *pwszOption, IN WCHAR const *pwszRequestId, IN WCHAR const *pwszArg2, IN WCHAR const *pwszArg3, IN WCHAR const *pwszArg4) { HRESULT hr; DISPATCHINTERFACE diAdmin; LONG RequestId; BOOL fMustRelease = FALSE;
hr = myGetLong(pwszRequestId, &RequestId); _JumpIfError(hr, error, "RequestId must be a number");
hr = Admin_Init(g_DispatchFlags, &diAdmin); _JumpIfError(hr, error, "Admin_Init");
fMustRelease = TRUE;
hr = Admin_DenyRequest(&diAdmin, g_pwszConfig, RequestId); _JumpIfError(hr, error, "Admin_DenyRequest");
error: if (fMustRelease) { Admin_Release(&diAdmin); } return(hr); }
WCHAR const * wszFromSubmitDisposition( LONG Disposition) { DWORD idMsg;
switch (Disposition) { case CR_DISP_INCOMPLETE: idMsg = IDS_CR_DISP_INCOMPLETE; break; case CR_DISP_ERROR: idMsg = IDS_CR_DISP_ERROR; break; case CR_DISP_DENIED: idMsg = IDS_CR_DISP_DENIED; break; case CR_DISP_ISSUED: idMsg = IDS_CR_DISP_ISSUED; break; case CR_DISP_ISSUED_OUT_OF_BAND: idMsg = IDS_CR_DISP_ISSUED_OUT_OF_BAND; break; case CR_DISP_UNDER_SUBMISSION: idMsg = IDS_CR_DISP_UNDER_SUBMISSION; break; case CR_DISP_REVOKED: idMsg = IDS_CR_DISP_REVOKED; break; default: idMsg = IDS_UNKNOWN; break; } return(myLoadResourceString(idMsg)); }
HRESULT verbResubmitRequest( IN WCHAR const *pwszOption, IN WCHAR const *pwszRequestId, IN WCHAR const *pwszArg2, IN WCHAR const *pwszArg3, IN WCHAR const *pwszArg4) { HRESULT hr; DISPATCHINTERFACE diAdmin; LONG RequestId; LONG Disposition; BOOL fMustRelease = FALSE;
hr = myGetLong(pwszRequestId, &RequestId); _JumpIfError(hr, error, "RequestId must be a number");
hr = Admin_Init(g_DispatchFlags, &diAdmin); _JumpIfError(hr, error, "Admin_Init");
fMustRelease = TRUE;
hr = Admin_ResubmitRequest(&diAdmin, g_pwszConfig, RequestId, &Disposition); _JumpIfError(hr, error, "Admin_ResubmitRequest");
if (CR_DISP_UNDER_SUBMISSION == Disposition) { wprintf( myLoadResourceString(IDS_FORMAT_PENDING_REQUESTID), // "Certificate request is pending: RequestId: %u"
RequestId); wprintf(wszNewLine); } else if (CR_DISP_ISSUED == Disposition) { wprintf(myLoadResourceString(IDS_CERT_ISSUED)); // "Certificate issued."
wprintf(wszNewLine); } else { if (FAILED(Disposition)) { hr = Disposition; Disposition = CR_DISP_DENIED; } wprintf( myLoadResourceString(IDS_CERT_NOT_ISSUED_DISPOSITION), // "Certificate has not been issued: Disposition: %d -- %ws"
Disposition, wszFromSubmitDisposition(Disposition)); wprintf(wszNewLine); if (S_OK != hr) { WCHAR const *pwszMessage;
pwszMessage = myGetErrorMessageText(hr, FALSE); if (NULL != pwszMessage) { wprintf(L"%ws\n", pwszMessage); LocalFree(const_cast<WCHAR *>(pwszMessage)); } } }
error: if (fMustRelease) { Admin_Release(&diAdmin); } return(hr); }
typedef struct _cuCRLREASON { WCHAR *pwszReason; LONG lReason; int idReason; } cuCRLREASON;
#define cuREASON(r, id) { L#r, (r), (id) }
cuCRLREASON g_cuReason[] = { cuREASON(CRL_REASON_UNSPECIFIED, IDS_CRL_REASON_UNSPECIFIED), cuREASON(CRL_REASON_KEY_COMPROMISE, IDS_CRL_REASON_KEY_COMPROMISE), cuREASON(CRL_REASON_CA_COMPROMISE, IDS_CRL_REASON_CA_COMPROMISE), cuREASON(CRL_REASON_AFFILIATION_CHANGED, IDS_CRL_REASON_AFFILIATION_CHANGED), cuREASON(CRL_REASON_SUPERSEDED, IDS_CRL_REASON_SUPERSEDED), cuREASON(CRL_REASON_CESSATION_OF_OPERATION, IDS_CRL_REASON_CESSATION_OF_OPERATION), cuREASON(CRL_REASON_CERTIFICATE_HOLD, IDS_CRL_REASON_CERTIFICATE_HOLD), cuREASON(CRL_REASON_REMOVE_FROM_CRL, IDS_CRL_REASON_REMOVE_FROM_CRL), { L"Unrevoke", MAXDWORD, IDS_CRL_REASON_UNREVOKE }, { NULL, MAXDWORD, IDS_CRL_REASON_UNRECOGNIZED }, };
#define wszCRLPREFIX L"CRL_REASON_"
HRESULT cuParseReason( IN WCHAR const *pwszReason, OUT LONG *plReason) { HRESULT hr; hr = myGetSignedLong(pwszReason, plReason); if (S_OK != hr) { cuCRLREASON const *pr; for (pr = g_cuReason; ; pr++) { if (NULL == pr->pwszReason) { hr = E_INVALIDARG; _JumpIfError(hr, error, "Invalid Reason string"); } if (0 == mylstrcmpiS(pr->pwszReason, pwszReason)) { break; } if (wcslen(pr->pwszReason) > WSZARRAYSIZE(wszCRLPREFIX) && 0 == memcmp( pr->pwszReason, wszCRLPREFIX, WSZARRAYSIZE(wszCRLPREFIX) * sizeof(WCHAR)) && 0 == LSTRCMPIS( pwszReason, &pr->pwszReason[WSZARRAYSIZE(wszCRLPREFIX)])) { break; } } *plReason = pr->lReason; hr = S_OK; } CSASSERT(S_OK == hr);
error: return(hr); }
int cuidCRLReason( IN LONG Reason) { cuCRLREASON const *pr; for (pr = g_cuReason; NULL != pr->pwszReason; pr++) { if (pr->lReason == Reason) { break; } } return(pr->idReason); }
WCHAR const * wszCRLReason( IN LONG Reason) { return(myLoadResourceString(cuidCRLReason(Reason))); }
HRESULT verbRevokeCertificate( IN WCHAR const *pwszOption, IN WCHAR const *pwszSerialNumberList, IN WCHAR const *pwszReason, IN WCHAR const *pwszArg3, IN WCHAR const *pwszArg4) { HRESULT hr; HRESULT hr2; DISPATCHINTERFACE diAdmin; WCHAR **ppwszSerialList = NULL; BSTR strSerialNumber = NULL; LONG Reason = CRL_REASON_UNSPECIFIED; SYSTEMTIME st; FILETIME ft; DATE Date; BOOL fMustRelease = FALSE;
GetSystemTime(&st); if (!SystemTimeToFileTime(&st, &ft)) { hr = myHLastError(); _JumpIfError(hr, error, "SystemTimeToFileTime"); } hr = myFileTimeToDate(&ft, &Date); _JumpIfError(hr, error, "myFileTimeToDate");
//Date -= 1.0; // Revoke effective yesterday
if (NULL != pwszReason) { hr = cuParseReason(pwszReason, &Reason); _JumpIfError(hr, error, "Invalid Reason"); }
hr = cuParseStrings( pwszSerialNumberList, FALSE, NULL, NULL, &ppwszSerialList, NULL); _JumpIfError(hr, error, "cuParseStrings");
hr = Admin_Init(g_DispatchFlags, &diAdmin); _JumpIfError(hr, error, "Admin_Init");
fMustRelease = TRUE;
if (NULL != ppwszSerialList) { DWORD i;
for (i = 0; NULL != ppwszSerialList[i]; i++) { hr2 = myMakeSerialBstr(ppwszSerialList[i], &strSerialNumber); if (S_OK == hr) { hr = hr2; } _JumpIfError(hr2, error, "myMakeSerialBstr");
wprintf(myLoadResourceString(IDS_REVOKING), strSerialNumber); // "Revoking "%ws""
wprintf(L" -- %ws", wszCRLReason(Reason)); // "Reason: xxxx"
wprintf(wszNewLine);
hr2 = Admin_RevokeCertificate( &diAdmin, g_pwszConfig, strSerialNumber, Reason, Date); if (S_OK != hr2) { cuPrintAPIError(L"ICertAdmin::RevokeCertificate", hr2); _PrintError(hr2, "Admin_RevokeCertificate"); if (S_OK == hr) { hr = hr2; } } SysFreeString(strSerialNumber); strSerialNumber = NULL; } } _JumpIfError(hr, error, "Admin_RevokeCertificate");
error: cuFreeStringArray(ppwszSerialList); if (fMustRelease) { Admin_Release(&diAdmin); } if (NULL != strSerialNumber) { SysFreeString(strSerialNumber); } return(hr); }
HRESULT cuParseDaysHours( IN WCHAR const *pwszDaysHours, OUT FILETIME *pft) { HRESULT hr; WCHAR *pwszDays = NULL; WCHAR *pwszHours; DWORD dwDays; DWORD dwHours; BOOL fValid; LONGLONG delta;
hr = myDupString(pwszDaysHours, &pwszDays); _JumpIfError(hr, error, "myDupString");
hr = E_INVALIDARG; pwszHours = wcschr(pwszDays, L':'); if (NULL == pwszHours) { _JumpError(hr, error, "missing colon"); } *pwszHours++ = L'\0'; dwDays = myWtoI(pwszDays, &fValid); if (!fValid) { _JumpError(hr, error, "bad day count"); } dwHours = myWtoI(pwszHours, &fValid); if (!fValid) { _JumpError(hr, error, "bad hour count"); } if (0 == dwDays && 0 == dwHours) { _JumpError(hr, error, "zero day+hour counts"); } GetSystemTimeAsFileTime(pft);
// add specified days and hours to compute expiration date
delta = dwDays * CVT_DAYS; delta += dwHours * CVT_HOURS; myAddToFileTime(pft, delta * CVT_BASE); hr = S_OK;
error: if (NULL != pwszDays) { LocalFree(pwszDays); } return(hr); }
HRESULT verbPublishCRL( IN WCHAR const *pwszOption, OPTIONAL IN WCHAR const *pwszDaysHours, OPTIONAL IN WCHAR const *pwszDelta, IN WCHAR const *pwszArg3, IN WCHAR const *pwszArg4) { HRESULT hr; DISPATCHINTERFACE diAdmin; BOOL fMustRelease = FALSE; DATE Date; DWORD Flags = 0;
if (NULL != pwszDaysHours && 0 == LSTRCMPIS(pwszDaysHours, L"delta")) { WCHAR const *pwsz = pwszDaysHours;
pwszDaysHours = pwszDelta; pwszDelta = pwsz; } Date = 0.0; if (NULL != pwszDaysHours) { if (0 == LSTRCMPIS(pwszDaysHours, L"republish")) { Flags |= CA_CRL_REPUBLISH; } else { FILETIME ft; hr = cuParseDaysHours(pwszDaysHours, &ft); _JumpIfError(hr, error, "cuParseDaysHours");
hr = myFileTimeToDate(&ft, &Date); _JumpIfError(hr, error, "myFileTimeToDate"); } } if (NULL != pwszDelta) { if (0 != LSTRCMPIS(pwszDelta, L"delta")) { hr = E_INVALIDARG; _JumpError(hr, error, "bad delta arg"); } Flags |= CA_CRL_DELTA; } if (0 == (CA_CRL_DELTA & Flags)) { Flags |= CA_CRL_BASE; }
hr = Admin_Init(g_DispatchFlags, &diAdmin); _JumpIfError(hr, error, "Admin_Init");
fMustRelease = TRUE;
if ((CA_CRL_DELTA | CA_CRL_REPUBLISH) & Flags) { hr = Admin2_PublishCRLs(&diAdmin, g_pwszConfig, Date, Flags); _JumpIfError(hr, error, "Admin2_PublishCRLs"); } else { BOOL fV1 = g_fV1Interface;
if (!fV1) { hr = Admin2_PublishCRLs(&diAdmin, g_pwszConfig, Date, Flags); if (E_NOTIMPL != hr && RPC_E_VERSION_MISMATCH != hr) { _JumpIfError(hr, error, "Admin2_PublishCRLs"); } else { _PrintError(hr, "Admin2_PublishCRLs down level server"); fV1 = TRUE; } } if (fV1) { hr = Admin_PublishCRL(&diAdmin, g_pwszConfig, Date); _JumpIfError(hr, error, "Admin_PublishCRL"); } }
error: if (fMustRelease) { Admin_Release(&diAdmin); } return(hr); }
HRESULT verbGetCRL( IN WCHAR const *pwszOption, IN WCHAR const *pwszfnOut, OPTIONAL IN WCHAR const *pwszDelta, OPTIONAL IN WCHAR const *pwszIndex, IN WCHAR const *pwszArg4) { HRESULT hr; DISPATCHINTERFACE diAdmin; BOOL fMustRelease = FALSE; BOOL fDelta = FALSE; DWORD Index = MAXDWORD; // default to latest CRL
BSTR strCRL = NULL;
if (NULL != pwszDelta && 0 != LSTRCMPIS(pwszDelta, L"delta")) { WCHAR const *pwsz = pwszIndex;
pwszIndex = pwszDelta; pwszDelta = pwsz; } if (NULL != pwszDelta && 0 == LSTRCMPIS(pwszDelta, L"delta")) { fDelta = TRUE; } if (NULL != pwszIndex) { hr = myGetSignedLong(pwszIndex, (LONG *) &Index); _JumpIfErrorStr(hr, error, "Cert index not a number", pwszIndex); } hr = Admin_Init(g_DispatchFlags, &diAdmin); _JumpIfError(hr, error, "Admin_Init");
fMustRelease = TRUE;
if (fDelta) { hr = Admin2_GetCAProperty( &diAdmin, g_pwszConfig, CR_PROP_DELTACRL, Index, PROPTYPE_BINARY, CR_OUT_BINARY, &strCRL); _JumpIfError(hr, error, "Admin2_GetCAProperty"); } else { BOOL fV1 = g_fV1Interface;
if (!fV1) { hr = Admin2_GetCAProperty( &diAdmin, g_pwszConfig, CR_PROP_BASECRL, Index, PROPTYPE_BINARY, CR_OUT_BINARY, &strCRL);
if (E_NOTIMPL != hr && RPC_E_VERSION_MISMATCH != hr) { _JumpIfError(hr, error, "Admin2_GetCAProperty"); } else { _PrintError(hr, "Admin2_CAProperty down level server"); fV1 = TRUE; } } if (fV1) { if (NULL != pwszIndex) { hr = cuGetCAInfo( pwszOption, pwszfnOut, g_wszCAInfoCRL, pwszIndex); _JumpIfError(hr, error, "cuGetCAInfo"); } else { hr = Admin_GetCRL( &diAdmin, g_pwszConfig, CR_OUT_BINARY, &strCRL); _JumpIfError(hr, error, "Admin_GetCRL"); } } }
// if not already saved by cuGetCAInfo
if (NULL != strCRL) { hr = EncodeToFileW( pwszfnOut, (BYTE const *) strCRL, SysStringByteLen(strCRL), CRYPT_STRING_BINARY | g_EncodeFlags); _JumpIfError(hr, error, "EncodeToFileW"); }
error: if (fMustRelease) { Admin_Release(&diAdmin); } if (NULL != strCRL) { SysFreeString(strCRL); } return(hr); }
HRESULT BuildDummyCert( IN CERT_CONTEXT const *pCert, IN WCHAR const *pwszSerialNumber, IN CHAR const *pszObjId, OUT BYTE **ppbCert, OUT DWORD *pcbCert) { HRESULT hr; CERT_INFO CertInfoOut; CERT_INFO const *pCertInfo; BYTE *pbUnsigned = NULL; DWORD cbUnsigned; CERT_CONTEXT CertContext; WCHAR *pwszContainer = NULL; HCRYPTPROV hProv = NULL; CERT_PUBLIC_KEY_INFO *pPubKey = NULL; DWORD cbPubKey; CERT_EXTENSION extSKI = {szOID_SUBJECT_KEY_IDENTIFIER, FALSE, 0, NULL}; CERT_EXTENSION extAKI = {szOID_AUTHORITY_KEY_IDENTIFIER2, FALSE, 0, NULL}; CERT_EXTENSION aExt[2]; CERT_EXTENSION *pExt; CRYPT_DATA_BLOB *pBlob = NULL; DWORD cb;
*ppbCert = NULL; ZeroMemory(&CertInfoOut, sizeof(CertInfoOut)); pCertInfo = pCert->pCertInfo; CertInfoOut.Issuer = pCertInfo->Issuer; CertInfoOut.NotBefore = pCertInfo->NotBefore; CertInfoOut.NotAfter = pCertInfo->NotAfter;
CertInfoOut.SignatureAlgorithm.pszObjId = const_cast<CHAR *>(pszObjId); hr = WszToMultiByteInteger( FALSE, pwszSerialNumber, &CertInfoOut.SerialNumber.cbData, &CertInfoOut.SerialNumber.pbData); _JumpIfError(hr, error, "WszToMultiByteInteger");
hr = myCertStrToName( X509_ASN_ENCODING, L"CN=Dummy", // pszX500
CERT_NAME_STR_REVERSE_FLAG, NULL, // pvReserved
&CertInfoOut.Subject.pbData, &CertInfoOut.Subject.cbData, NULL); // ppszError
_JumpIfError(hr, error, "myCertStrToName");
ZeroMemory(&CertContext, sizeof(CertContext)); CertContext.dwCertEncodingType = X509_ASN_ENCODING; CertContext.pCertInfo = &CertInfoOut;
hr = cuGenerateKeyContainerName(&CertContext, &pwszContainer); _JumpIfError(hr, error, "cuGenerateKeyContainerName");
hr = myGenerateKeys( pwszContainer, NULL, // pwszProvName
0, // dwFlags
FALSE, // fMachineKeySet
AT_SIGNATURE, PROV_RSA_FULL, 0, // dwKeySize (use default)
&hProv); _JumpIfError(hr, error, "myGenerateKeys");
if (!myCryptExportPublicKeyInfo( hProv, AT_SIGNATURE, CERTLIB_USE_LOCALALLOC, &pPubKey, &cbPubKey)) { hr = myHLastError(); _JumpError(hr, error, "myCryptExportPublicKeyInfo"); } CertInfoOut.SubjectPublicKeyInfo = *pPubKey; // Structure assignment
// Subject Key Identifier extension:
hr = myCreateSubjectKeyIdentifierExtension( pPubKey, &extSKI.Value.pbData, &extSKI.Value.cbData); _JumpIfError(hr, error, "myCreateSubjectKeyIdentifierExtension");
CertInfoOut.rgExtension = aExt; aExt[CertInfoOut.cExtension] = extSKI; CertInfoOut.cExtension++;
//AKI extension?
pExt = CertFindExtension( szOID_SUBJECT_KEY_IDENTIFIER, pCertInfo->cExtension, pCertInfo->rgExtension); if (NULL != pExt) { CERT_AUTHORITY_KEY_ID2_INFO AKI;
if (!myDecodeObject( X509_ASN_ENCODING, X509_OCTET_STRING, pExt->Value.pbData, pExt->Value.cbData, CERTLIB_USE_LOCALALLOC, (VOID **) &pBlob, &cb)) { hr = myHLastError(); _JumpError(hr, error, "myDecodeObject"); } ZeroMemory(&AKI, sizeof(AKI)); AKI.KeyId = *pBlob;
if (!myEncodeKeyAuthority2( X509_ASN_ENCODING, &AKI, CERTLIB_USE_LOCALALLOC, &extAKI.Value.pbData, &extAKI.Value.cbData)) { hr = myHLastError(); _JumpError(hr, error, "myEncodeKeyAuthority2"); }
aExt[CertInfoOut.cExtension] = extAKI; CertInfoOut.cExtension++; }
CertInfoOut.dwVersion = CERT_V3;
if (!myEncodeObject( X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED, &CertInfoOut, 0, CERTLIB_USE_LOCALALLOC, &pbUnsigned, // pbEncoded
&cbUnsigned)) { hr = myHLastError(); _JumpError(hr, error, "myEncodeObject"); } *ppbCert = pbUnsigned; pbUnsigned = NULL; *pcbCert = cbUnsigned; hr = S_OK;
error: if (NULL != pbUnsigned) { LocalFree(pbUnsigned); } if (NULL != pBlob) { LocalFree(pBlob); } if (NULL != extSKI.Value.pbData) { LocalFree(extSKI.Value.pbData); } if (NULL != extAKI.Value.pbData) { LocalFree(extAKI.Value.pbData); } if (NULL != CertInfoOut.SerialNumber.pbData) { LocalFree(CertInfoOut.SerialNumber.pbData); } if (NULL != CertInfoOut.Subject.pbData) { LocalFree(CertInfoOut.Subject.pbData); } if (NULL != pPubKey) { LocalFree(pPubKey); } if (NULL != hProv) { CryptReleaseContext(hProv, 0); if (NULL != pwszContainer) { CryptAcquireContext( &hProv, pwszContainer, NULL, // pwszProvName
PROV_RSA_FULL, CRYPT_DELETEKEYSET); } } if (NULL != pwszContainer) { LocalFree(pwszContainer); } return(hr); }
HRESULT FindCertAndSign( OPTIONAL IN CERT_EXTENSION const *pExtKeyId, OPTIONAL IN BYTE const *pbHash, IN DWORD cbHash, OPTIONAL IN BYTE const *pbUnsigned, IN DWORD cbUnsigned, OPTIONAL IN WCHAR const *pwszSerialNumber, OUT BYTE **ppbOut, OUT DWORD *pcbOut) { HRESULT hr; CERT_AUTHORITY_KEY_ID2_INFO *pKeyId = NULL; DWORD cbKeyId; BSTR strKeyId = NULL; CERT_CONTEXT const *pCert = NULL; HCRYPTPROV hProv = NULL; DWORD dwKeySpec; BOOL fCallerFreeProv; CHAR *pszObjId = NULL; BYTE *pbCert = NULL; DWORD cbCert; *ppbOut = NULL; CSASSERT(NULL != pbUnsigned || NULL != pwszSerialNumber); if (NULL == pbHash && NULL != pExtKeyId) { if (!myDecodeObject( X509_ASN_ENCODING, X509_AUTHORITY_KEY_ID2, pExtKeyId->Value.pbData, pExtKeyId->Value.cbData, CERTLIB_USE_LOCALALLOC, (VOID **) &pKeyId, &cbKeyId)) { hr = myHLastError(); _JumpError(hr, error, "myDecodeObject"); } pbHash = pKeyId->KeyId.pbData; cbHash = pKeyId->KeyId.cbData; } if (0 != cbHash && NULL != pbHash) { hr = MultiByteIntegerToBstr(TRUE, cbHash, pbHash, &strKeyId); _JumpIfError(hr, error, "MultiByteIntegerToBstr"); }
// Find CA cert by KeyId from the szOID_AUTHORITY_KEY_IDENTIFIER2 extension.
// Look in HKLM and HKCU My and CA stores.
hr = myGetCertificateFromPicker( g_hInstance, NULL, // hwndParent
IDS_GETCERT_TITLE, IDS_GETCERT_SUBTITLE,
// dwFlags: HKLM+HKCU My store
CUCS_MYSTORE | CUCS_MACHINESTORE | CUCS_USERSTORE | CUCS_PRIVATEKEYREQUIRED | CUCS_ARCHIVED | (g_fCryptSilent? CUCS_SILENT : 0), strKeyId, 0, NULL, 0, // cpszObjId
NULL, // apszObjId
&pCert); _JumpIfError(hr, error, "myGetCertificateFromPicker");
if (NULL == pCert) { hr = HRESULT_FROM_WIN32(ERROR_CANCELLED); _JumpError(hr, error, "no cert"); }
hr = cuDisplayCertName( TRUE, NULL, myLoadResourceString(IDS_SIGNINGSUBJECT), // "Signing certificate Subject"
g_wszPad4, &pCert->pCertInfo->Subject, pCert->pCertInfo); _JumpIfError(hr, error, "cuDisplayCertName(Subject)");
// Search for and load the cryptographic provider and private key.
hr = myLoadPrivateKey( &pCert->pCertInfo->SubjectPublicKeyInfo, CUCS_MACHINESTORE | CUCS_USERSTORE | CUCS_MYSTORE | CUCS_ARCHIVED, &hProv, &dwKeySpec, &fCallerFreeProv); _JumpIfError(hr, error, "myLoadPrivateKey");
if (AT_SIGNATURE != dwKeySpec) { hr = NTE_BAD_KEY_STATE; DBGPRINT((DBG_SS_CERTUTIL, "dwKeySpec = %u\n", dwKeySpec)); _JumpError(hr, error, "dwKeySpec"); }
// The CA cert's private key is available -- use it to sign the data.
// Sign the Cert or CRL and encode the signed info.
hr = myGetSigningOID(hProv, NULL, 0, CALG_SHA1, &pszObjId); _JumpIfError(hr, error, "myGetSigningOID");
if (NULL != pwszSerialNumber) { hr = BuildDummyCert( pCert, pwszSerialNumber, pszObjId, &pbCert, &cbCert); _JumpIfError(hr, error, "BuildDummyCert");
pbUnsigned = pbCert; cbUnsigned = cbCert; }
hr = myEncodeSignedContent( hProv, X509_ASN_ENCODING, pszObjId, const_cast<BYTE *>(pbUnsigned), cbUnsigned, CERTLIB_USE_LOCALALLOC, ppbOut, pcbOut); _JumpIfError(hr, error, "myEncodeSignedContent");
error: if (NULL != pbCert) { LocalFree(pbCert); } if (NULL != pszObjId) { LocalFree(pszObjId); } if (NULL != pKeyId) { LocalFree(pKeyId); } if (NULL != strKeyId) { SysFreeString(strKeyId); } if (NULL != pCert) { CertFreeCertificateContext(pCert); } if (NULL != hProv && fCallerFreeProv) { CryptReleaseContext(hProv, 0); } return(hr); }
VOID SetExpiration( OPTIONAL IN FILETIME const *pftNotAfterNew, IN OUT FILETIME *pftNotBefore, OPTIONAL IN OUT FILETIME *pftNotAfter) { if (NULL == pftNotAfterNew || 0 != pftNotAfterNew->dwLowDateTime || 0 != pftNotAfterNew->dwHighDateTime) { LLFILETIME llftNotBefore; LLFILETIME llft; LLFILETIME llftDelta;
llftNotBefore.ft = *pftNotBefore; // Save orignal value
// current time - clock skew
GetSystemTimeAsFileTime(&llft.ft); llftDelta.ll = CCLOCKSKEWMINUTESDEFAULT * CVT_MINUTES; llftDelta.ll *= CVT_BASE; llft.ll -= llftDelta.ll;
// NotBeforeOut = oldest of NotBefore, (CurrentTime - skew)
if (llftNotBefore.ll > llft.ll) { *pftNotBefore = llft.ft; } if (NULL != pftNotAfter) { LLFILETIME llftNotAfter;
llftNotAfter.ft = *pftNotAfter; // Save orignal value
if (NULL != pftNotAfterNew) { *pftNotAfter = *pftNotAfterNew; } else { // NotAfterOut = (CurrentTime - skew) + (NotAfter - NotBefore);
llft.ll += llftNotAfter.ll; llft.ll -= llftNotBefore.ll; *pftNotAfter = llft.ft; } } } }
HRESULT RemoveExtensions( IN WCHAR const * const *ppwszObjIdList, IN BOOL fValidate, IN DWORD cExtensionIn, IN CERT_EXTENSION *rgExtensionIn, OUT DWORD *pcExtensionOut, OUT CERT_EXTENSION **prgExtensionOut) { HRESULT hr; DWORD cExtension = cExtensionIn; CERT_EXTENSION *rgExtension = NULL;
*prgExtensionOut = NULL; rgExtension = (CERT_EXTENSION *) LocalAlloc( LMEM_FIXED, cExtension * sizeof(rgExtension[0])); if (NULL == rgExtension) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } CopyMemory( rgExtension, rgExtensionIn, cExtension * sizeof(rgExtension[0]));
if (NULL != ppwszObjIdList) { DWORD i;
for (i = 0; NULL != ppwszObjIdList[i]; i++) { WCHAR const *pwszObjId = ppwszObjIdList[i]; char *pszObjId; CERT_EXTENSION *pExt; hr = myVerifyObjId(pwszObjId); if (S_OK != hr) { if (fValidate) { _JumpError(hr, error, "myVerifyObjId"); } continue; }
if (!myConvertWszToSz(&pszObjId, pwszObjId, -1)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "myConvertWszToSz"); } pExt = CertFindExtension(pszObjId, cExtension, rgExtension); if (NULL != pExt) { DWORD iDel = SAFE_SUBTRACT_POINTERS(pExt, rgExtension);
// wprintf(L"iDel=%u cExt=%u\n", iDel, cExtension);
if (iDel < cExtension) { // wprintf(L"copy %u to %u, len=%u\n", iDel + 1, iDel, cExtension - iDel - 1);
MoveMemory( &rgExtension[iDel], &rgExtension[iDel + 1], (cExtension - iDel - 1) * sizeof(rgExtension[iDel])); } cExtension--; } LocalFree(pszObjId); } } *pcExtensionOut = cExtension; *prgExtensionOut = rgExtension; rgExtension = NULL; hr = S_OK;
error: if (NULL != rgExtension) { LocalFree(rgExtension); } return(hr); }
CRL_ENTRY * FindCRLEntry( IN DWORD cbSerial, IN BYTE const *pbSerial, IN DWORD cCRLEntry, IN CRL_ENTRY *rgCRLEntry) { CRL_ENTRY *pCRLEntry = NULL; CRL_ENTRY *rgCRLEntryEnd = &rgCRLEntry[cCRLEntry];
for ( ; rgCRLEntry < rgCRLEntryEnd; rgCRLEntry++) { if (cbSerial == rgCRLEntry->SerialNumber.cbData && 0 == memcmp(pbSerial, rgCRLEntry->SerialNumber.pbData, cbSerial)) { pCRLEntry = rgCRLEntry; break; } } return(pCRLEntry); }
HRESULT AddRemoveSerial( IN WCHAR const * const *ppwszSerialList, IN BOOL fAdd, IN DWORD cCRLEntryIn, IN CRL_ENTRY *rgCRLEntryIn, OUT DWORD *pcCRLEntryOut, OUT CRL_ENTRY **prgCRLEntryOut, OUT DWORD *pcSerialNew, OUT BYTE ***prgpbSerialNew) { HRESULT hr; DWORD cCRLEntry = cCRLEntryIn; CRL_ENTRY *rgCRLEntry = NULL; DWORD cAdd; BYTE **rgpbSerialNew = NULL; DWORD cSerialNew; FILETIME ftCurrent;
*prgCRLEntryOut = NULL; *prgpbSerialNew = NULL; cAdd = 0; if (fAdd) { for (cAdd = 0; NULL != ppwszSerialList[cAdd]; cAdd++) ; cSerialNew = 0; rgpbSerialNew = (BYTE **) LocalAlloc( LMEM_FIXED, cAdd * sizeof(rgpbSerialNew[0])); if (NULL == rgpbSerialNew) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } GetSystemTimeAsFileTime(&ftCurrent); }
rgCRLEntry = (CRL_ENTRY *) LocalAlloc( LMEM_FIXED, (cCRLEntry + cAdd) * sizeof(rgCRLEntry[0])); if (NULL == rgCRLEntry) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } CopyMemory( rgCRLEntry, rgCRLEntryIn, cCRLEntry * sizeof(rgCRLEntry[0]));
if (NULL != ppwszSerialList) { DWORD i;
for (i = 0; NULL != ppwszSerialList[i]; i++) { WCHAR const *pwszSerial = ppwszSerialList[i]; CRL_ENTRY *pCRLEntry; DWORD cbSerial; BYTE *pbSerial; hr = myVerifyObjId(pwszSerial); if (S_OK == hr) { continue; // skip OIDs
} hr = WszToMultiByteInteger( FALSE, pwszSerial, &cbSerial, &pbSerial); _JumpIfErrorStr(hr, error, "WszToMultiByteInteger", pwszSerial);
pCRLEntry = FindCRLEntry( cbSerial, pbSerial, cCRLEntry, rgCRLEntry); if (fAdd) { if (NULL == pCRLEntry) { pCRLEntry = &rgCRLEntry[cCRLEntry]; ZeroMemory(pCRLEntry, sizeof(*pCRLEntry)); pCRLEntry->SerialNumber.pbData = pbSerial; pCRLEntry->SerialNumber.cbData = cbSerial; pCRLEntry->RevocationDate = ftCurrent;
cCRLEntry++; rgpbSerialNew[cSerialNew++] = pbSerial; pbSerial = NULL; } } else { if (NULL != pCRLEntry) { DWORD iDel = SAFE_SUBTRACT_POINTERS(pCRLEntry, rgCRLEntry);
if (iDel < cCRLEntry) { MoveMemory( &rgCRLEntry[iDel], &rgCRLEntry[iDel + 1], (cCRLEntry - iDel - 1) * sizeof(rgCRLEntry[iDel])); } cCRLEntry--; } } if (NULL != pbSerial) { LocalFree(pbSerial); } } } *pcCRLEntryOut = cCRLEntry; *prgCRLEntryOut = rgCRLEntry; rgCRLEntry = NULL; *pcSerialNew = cSerialNew; *prgpbSerialNew = rgpbSerialNew; rgpbSerialNew = NULL; hr = S_OK;
error: if (NULL != rgCRLEntry) { LocalFree(rgCRLEntry); } if (NULL != rgpbSerialNew) { DWORD i;
for (i = 0; i < cSerialNew; i++) { if (NULL != rgpbSerialNew[i]) { LocalFree(rgpbSerialNew[i]); } } LocalFree(rgpbSerialNew); } return(hr); }
HRESULT SignCRL( IN CRL_CONTEXT const *pCRLContext, OPTIONAL IN FILETIME const *pftNextUpdate, IN BOOL fAdd, IN WCHAR const * const *ppwszSerialList, OUT BYTE **ppbOut, OUT DWORD *pcbOut) { HRESULT hr; CRL_INFO const *pCRLInfo; CRL_INFO CRLInfoOut; BYTE *pbUnsigned = NULL; DWORD cbUnsigned; CERT_EXTENSION *pExtKeyId; CERT_EXTENSION *rgExtension = NULL; CRL_ENTRY *rgCRLEntry = NULL; DWORD cSerialNew; BYTE **rgpbSerialNew = NULL;
ZeroMemory(&CRLInfoOut, sizeof(CRLInfoOut));
*ppbOut = NULL;
// CRL extensions to strip out of the re-signed CRL:
static WCHAR const * const apwszObjIdFilter[] = { TEXT(szOID_CRL_NEXT_PUBLISH), NULL }; static WCHAR const * const apwszObjIdFilterNull[] = { NULL };
pCRLInfo = pCRLContext->pCrlInfo; CRLInfoOut = *pCRLInfo;
SetExpiration( pftNextUpdate, &CRLInfoOut.ThisUpdate, (0 != CRLInfoOut.NextUpdate.dwLowDateTime || 0 != CRLInfoOut.NextUpdate.dwHighDateTime)? &CRLInfoOut.NextUpdate : NULL);
hr = cuDumpFileTime(IDS_THISUPDATE, NULL, &CRLInfoOut.ThisUpdate); _JumpIfError(hr, error, "cuDumpFileTime");
hr = cuDumpFileTime(IDS_NEXTUPDATE, NULL, &CRLInfoOut.NextUpdate); _JumpIfError(hr, error, "cuDumpFileTime");
wprintf(myLoadResourceString(IDS_CRLENTRIES)); // "CRL Entries:"
wprintf(L" %u\n", pCRLInfo->cCRLEntry);
wprintf(wszNewLine);
pExtKeyId = CertFindExtension( szOID_AUTHORITY_KEY_IDENTIFIER2, pCRLInfo->cExtension, pCRLInfo->rgExtension);
hr = RemoveExtensions( (NULL == pftNextUpdate || 0 != pftNextUpdate->dwLowDateTime || 0 != pftNextUpdate->dwHighDateTime)? apwszObjIdFilter : apwszObjIdFilterNull, TRUE, CRLInfoOut.cExtension, CRLInfoOut.rgExtension, &CRLInfoOut.cExtension, &rgExtension); _JumpIfError(hr, error, "RemoveExtensions");
CRLInfoOut.rgExtension = rgExtension;
if (!fAdd) { CERT_EXTENSION *rgExtension2 = rgExtension;
hr = RemoveExtensions( ppwszSerialList, FALSE, CRLInfoOut.cExtension, CRLInfoOut.rgExtension, &CRLInfoOut.cExtension, &rgExtension); _JumpIfError(hr, error, "RemoveExtensions");
if (NULL != rgExtension2) { LocalFree(rgExtension2); } CRLInfoOut.rgExtension = rgExtension; }
hr = AddRemoveSerial( ppwszSerialList, fAdd, CRLInfoOut.cCRLEntry, CRLInfoOut.rgCRLEntry, &CRLInfoOut.cCRLEntry, &rgCRLEntry, &cSerialNew, &rgpbSerialNew); _JumpIfError(hr, error, "AddRemoveSerial");
CRLInfoOut.rgCRLEntry = rgCRLEntry;
if (!myEncodeObject( X509_ASN_ENCODING, X509_CERT_CRL_TO_BE_SIGNED, &CRLInfoOut, 0, CERTLIB_USE_LOCALALLOC, &pbUnsigned, // pbEncoded
&cbUnsigned)) { hr = myHLastError(); _JumpError(hr, error, "myEncodeObject"); }
hr = FindCertAndSign( pExtKeyId, NULL, 0, pbUnsigned, cbUnsigned, NULL, // pwszSerialNumber
ppbOut, pcbOut); _JumpIfError(hr, error, "FindCertAndSign");
error: if (NULL != rgpbSerialNew) { DWORD i;
for (i = 0; i < cSerialNew; i++) { if (NULL != rgpbSerialNew[i]) { LocalFree(rgpbSerialNew[i]); } } LocalFree(rgpbSerialNew); } if (NULL != rgCRLEntry) { LocalFree(rgCRLEntry); } if (NULL != rgExtension) { LocalFree(rgExtension); } if (NULL != pbUnsigned) { LocalFree(pbUnsigned); } return(hr); }
HRESULT SignCert( IN CERT_CONTEXT const *pCertContext, OPTIONAL IN WCHAR const *pwszSerialNumber, OPTIONAL IN FILETIME const *pftNotAfter, OPTIONAL IN WCHAR const * const *ppwszObjIdList, OUT BYTE **ppbOut, OUT DWORD *pcbOut) { HRESULT hr; CERT_INFO const *pCertInfo; BYTE *pbUnsigned = NULL; DWORD cbUnsigned; BYTE const *pbHash; BYTE abHash[CBMAX_CRYPT_HASH_LEN]; DWORD cbHash; CERT_EXTENSION *pExtKeyId; CERT_EXTENSION *rgExtension = NULL;
*ppbOut = NULL;
pExtKeyId = NULL; if (NULL != pCertContext) { CERT_INFO CertInfoOut;
ZeroMemory(&CertInfoOut, sizeof(CertInfoOut));
pCertInfo = pCertContext->pCertInfo; CertInfoOut = *pCertInfo;
SetExpiration(pftNotAfter, &CertInfoOut.NotBefore, &CertInfoOut.NotAfter);
hr = cuDumpFileTime(IDS_NOTBEFORE, NULL, &CertInfoOut.NotBefore); _JumpIfError(hr, error, "cuDumpFileTime");
hr = cuDumpFileTime(IDS_NOTAFTER, NULL, &CertInfoOut.NotAfter); _JumpIfError(hr, error, "cuDumpFileTime");
wprintf(wszNewLine);
pbHash = NULL; pExtKeyId = CertFindExtension( szOID_AUTHORITY_KEY_IDENTIFIER2, pCertInfo->cExtension, pCertInfo->rgExtension); if (NULL == pExtKeyId) { hr = cuVerifySignature( pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, &pCertContext->pCertInfo->SubjectPublicKeyInfo, FALSE, TRUE); if (S_OK == hr) { if (CertGetCertificateContextProperty( pCertContext, CERT_KEY_IDENTIFIER_PROP_ID, abHash, &cbHash)) { pbHash = abHash; } } } hr = RemoveExtensions( ppwszObjIdList, TRUE, CertInfoOut.cExtension, CertInfoOut.rgExtension, &CertInfoOut.cExtension, &rgExtension); _JumpIfError(hr, error, "RemoveExtensions");
CertInfoOut.rgExtension = rgExtension;
if (0 == CertInfoOut.cExtension) { CertInfoOut.dwVersion = CERT_V1; } if (!myEncodeObject( X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED, &CertInfoOut, 0, CERTLIB_USE_LOCALALLOC, &pbUnsigned, // pbEncoded
&cbUnsigned)) { hr = myHLastError(); _JumpError(hr, error, "myEncodeObject"); } } hr = FindCertAndSign( pExtKeyId, pbHash, cbHash, pbUnsigned, cbUnsigned, pwszSerialNumber, ppbOut, pcbOut); _JumpIfError(hr, error, "FindCertAndSign");
error: if (NULL != rgExtension) { LocalFree(rgExtension); } if (NULL != pbUnsigned) { LocalFree(pbUnsigned); } return(hr); }
HRESULT verbSign( IN WCHAR const *pwszOption, IN WCHAR const *pwszfnIn, IN WCHAR const *pwszfnOut, OPTIONAL IN WCHAR const *pwszDaysHours, OPTIONAL IN WCHAR const *pwszChangeList) { HRESULT hr; FILETIME ftNextUpdate; FILETIME *pftNextUpdate; CRL_CONTEXT const *pCRLContext = NULL; CERT_CONTEXT const *pCertContext = NULL; BYTE *pbOut = NULL; DWORD cbOut; BOOL fAdd = FALSE; WCHAR **ppwszList = NULL; BSTR strSerialNumber = NULL;
pftNextUpdate = NULL; if (NULL != pwszDaysHours && (myIsMinusSign(*pwszDaysHours) || L'+' == *pwszDaysHours)) { WCHAR const *pwsz = pwszDaysHours;
pwszDaysHours = pwszChangeList; pwszChangeList = pwsz; } if (NULL != pwszChangeList) { if (!myIsMinusSign(*pwszChangeList) && L'+' != *pwszChangeList) { hr = E_INVALIDARG; _JumpError(hr, error, "missing +/-"); } fAdd = L'+' == *pwszChangeList++; hr = cuParseStrings( pwszChangeList, FALSE, NULL, NULL, &ppwszList, NULL); _JumpIfError(hr, error, "cuParseStrings"); } if (NULL != pwszDaysHours) { if (0 == lstrcmp(L"0", pwszDaysHours)) { ZeroMemory(&ftNextUpdate, sizeof(ftNextUpdate)); } else { hr = cuParseDaysHours(pwszDaysHours, &ftNextUpdate); _JumpIfError(hr, error, "cuParseDaysHours"); } pftNextUpdate = &ftNextUpdate; }
if (NULL == pwszDaysHours && NULL == pwszChangeList && !myDoesFileExist(pwszfnIn)) { hr = myMakeSerialBstr(pwszfnIn, &strSerialNumber); _JumpIfError(hr, error, "myMakeSerialBstr");
hr = SignCert( NULL, // pCertContext
strSerialNumber, pftNextUpdate, NULL, // ppwszObjIdList
&pbOut, &cbOut); _JumpIfError(hr, error, "SignCert"); } else { // Load and decode CRL and certificate
hr = cuLoadCRL(pwszfnIn, &pCRLContext); if (S_OK == hr) { hr = SignCRL( pCRLContext, pftNextUpdate, fAdd, ppwszList, &pbOut, &cbOut); _JumpIfError(hr, error, "SignCRL"); } else { hr = cuLoadCert(pwszfnIn, &pCertContext); if (S_OK == hr) { if (fAdd) { hr = E_INVALIDARG; _JumpError(hr, error, "cannot add extensions to cert"); } hr = SignCert( pCertContext, NULL, // pwszSerialNumber
pftNextUpdate, ppwszList, &pbOut, &cbOut); _JumpIfError(hr, error, "SignCert"); } else { cuPrintError(IDS_FORMAT_LOADTESTCRL, hr); goto error; } } }
// Write encoded & signed CRL or Cert to file
hr = EncodeToFileW( pwszfnOut, pbOut, cbOut, CRYPT_STRING_BINARY | g_EncodeFlags); if (S_OK != hr) { cuPrintError(IDS_ERR_FORMAT_ENCODETOFILE, hr); goto error; } wprintf( myLoadResourceString(IDS_FORMAT_OUTPUT_LENGTH), // "Output Length = %d"
cuFileSize(pwszfnOut)); wprintf(wszNewLine);
hr = S_OK;
error: if (NULL != strSerialNumber) { SysFreeString(strSerialNumber); } cuFreeStringArray(ppwszList); if (NULL != pbOut) { LocalFree(pbOut); } cuUnloadCRL(&pCRLContext); cuUnloadCert(&pCertContext); return(hr); }
HRESULT verbShutDownServer( IN WCHAR const *pwszOption, IN WCHAR const *pwszArg1, IN WCHAR const *pwszArg2, IN WCHAR const *pwszArg3, IN WCHAR const *pwszArg4) { HRESULT hr;
hr = CertSrvServerControl(g_pwszConfig, CSCONTROL_SHUTDOWN, NULL, NULL); _JumpIfError(hr, error, "CertSrvServerControl");
error: if (E_ACCESSDENIED == hr) { g_uiExtraErrorInfo = IDS_ERROR_ACCESSDENIED_CAUSE; } return(hr); }
HRESULT verbIsValidCertificate( IN WCHAR const *pwszOption, IN WCHAR const *pwszSerialNumber, IN WCHAR const *pwszArg2, IN WCHAR const *pwszArg3, IN WCHAR const *pwszArg4) { HRESULT hr; DISPATCHINTERFACE diAdmin; BSTR strSerialNumber = NULL; LONG Reason = CRL_REASON_KEY_COMPROMISE; BOOL fMustRelease = FALSE; LONG Disposition;
hr = myMakeSerialBstr(pwszSerialNumber, &strSerialNumber); _JumpIfError(hr, error, "myMakeSerialBstr");
hr = Admin_Init(g_DispatchFlags, &diAdmin); _JumpIfError(hr, error, "Admin_Init");
fMustRelease = TRUE;
hr = Admin_IsValidCertificate( &diAdmin, g_pwszConfig, strSerialNumber, &Disposition); _JumpIfError(hr, error, "Admin_IsValidCertificate");
switch (Disposition) { case CA_DISP_INVALID: wprintf(myLoadResourceString(IDS_CERT_DISPOSITION_INVALID), strSerialNumber); // "Certificate disposition for "%ws" is invalid"
wprintf(wszNewLine); break;
case CA_DISP_VALID: wprintf(myLoadResourceString(IDS_CERT_DISPOSITION_VALID), strSerialNumber); // "Certificate disposition for "%ws" is valid"
wprintf(wszNewLine); break;
case CA_DISP_UNDER_SUBMISSION: wprintf(myLoadResourceString(IDS_CERT_DISPOSITION_PENDING), strSerialNumber); // "Certificate request for "%ws" is pending"
wprintf(wszNewLine); break;
case CA_DISP_REVOKED: hr = Admin_GetRevocationReason(&diAdmin, &Reason); if (S_OK != hr) { _PrintIfError(hr, "Admin_GetRevocationReason"); Reason = CRL_REASON_UNSPECIFIED; } wprintf( myLoadResourceString(IDS_CERT_DISPOSITION_REVOKED), // "Certificate disposition for "%ws" is revoked (%ws)"
strSerialNumber, wszCRLReason(Reason)); wprintf(wszNewLine); break; }
error: if (fMustRelease) { Admin_Release(&diAdmin); } if (NULL != strSerialNumber) { SysFreeString(strSerialNumber); } return(hr); }
#define wszREQUEST L"Request"
#define wszCERT L"Cert"
HRESULT verbDeleteRow( IN WCHAR const *pwszOption, IN WCHAR const *pwszRowIdOrDate, OPTIONAL IN WCHAR const *pwszTable, IN WCHAR const *pwszArg3, IN WCHAR const *pwszArg4) { HRESULT hr; WCHAR *pwszLocalTime = NULL; DISPATCHINTERFACE diAdmin; BOOL fMustRelease = FALSE; DWORD Flags; LONG RowId; DATE date; LONG Table; LONG Count;
hr = myGetLong(pwszRowIdOrDate, &RowId); if (S_OK != hr) { FILETIME ftCurrent; FILETIME ftQuery; RowId = 0;
hr = myWszLocalTimeToGMTDate(pwszRowIdOrDate, &date); _JumpIfError(hr, error, "invalid RowId or date");
hr = myGMTDateToWszLocalTime(&date, g_fSeconds, &pwszLocalTime); _JumpIfError(hr, error, "myGMTDateToWszLocalTime");
GetSystemTimeAsFileTime(&ftCurrent);
hr = myDateToFileTime(&date, &ftQuery); _JumpIfError(hr, error, "myDateToFileTime");
if (0 > CompareFileTime(&ftCurrent, &ftQuery)) { wprintf( myLoadResourceString(IDS_FORMAT_DATE_IN_FUTURE), // "The date specified is in the future: %ws"
pwszLocalTime); wprintf(wszNewLine); if (!g_fForce) { hr = E_INVALIDARG; _JumpError(hr, error, "date in future"); } } if (g_fVerbose) { wprintf(pwszLocalTime); wprintf(wszNewLine); } } else { if (0 == RowId) { hr = E_INVALIDARG; _JumpError(hr, error, "zero RowId"); } date = 0.0; }
hr = E_INVALIDARG; Table = CVRC_TABLE_REQCERT; Flags = 0; if (NULL == pwszTable) { if (0 == RowId) { wprintf( myLoadResourceString(IDS_FORMAT_DATE_REQUIRES_TABLE), // "One of the following tables must be specified when deleting rows older than %ws:"
pwszLocalTime); wprintf(wszNewLine); wprintf(L" %ws\n", wszREQUEST); wprintf(L" %ws\n", wszCERT); wprintf(L" %ws\n", g_wszCRL); _JumpError(hr, error, "date requires table"); } } else if (0 == LSTRCMPIS(pwszTable, wszREQUEST)) { Flags = CDR_REQUEST_LAST_CHANGED; // assume date query
} else if (0 == LSTRCMPIS(pwszTable, wszCERT)) { Flags = CDR_EXPIRED; // assume date query
} else if (0 == mylstrcmpiS(pwszTable, g_wszExt)) { Table = CVRC_TABLE_EXTENSIONS; if (0 == RowId) { _JumpError(hr, error, "no date in Extension table"); } } else if (0 == mylstrcmpiS(pwszTable, g_wszAttrib)) { Table = CVRC_TABLE_ATTRIBUTES; if (0 == RowId) { _JumpError(hr, error, "no date in Request Attribute table"); } } else if (0 == mylstrcmpiS(pwszTable, g_wszCRL)) { Table = CVRC_TABLE_CRL; // assume date query
} else { _JumpError(hr, error, "bad table name"); } if (0 != RowId) { Flags = 0; // not a date query
} else if (g_fVerbose) { wprintf(L"%ws\n", pwszLocalTime); }
hr = Admin_Init(g_DispatchFlags, &diAdmin); _JumpIfError(hr, error, "Admin_Init");
fMustRelease = TRUE;
Count = 0; hr = Admin2_DeleteRow( &diAdmin, g_pwszConfig, Flags, date, Table, RowId, &Count); wprintf(myLoadResourceString(IDS_FORMAT_DELETED_ROW_COUNT), Count); wprintf(wszNewLine); _JumpIfError(hr, error, "Admin2_DeleteRow");
error: if (fMustRelease) { Admin_Release(&diAdmin); } if (NULL != pwszLocalTime) { LocalFree(pwszLocalTime); } return(hr); }
HRESULT verbSetAttributes( IN WCHAR const *pwszOption, IN WCHAR const *pwszRequestId, IN WCHAR const *pwszAttributes, IN WCHAR const *pwszArg3, IN WCHAR const *pwszArg4) { HRESULT hr; DISPATCHINTERFACE diAdmin; LONG RequestId; BSTR strAttributes = NULL; WCHAR *pwsz; BOOL fMustRelease = FALSE;
if (!ConvertWszToBstr(&strAttributes, pwszAttributes, MAXDWORD)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "ConvertWszToBstr"); } for (pwsz = strAttributes; L'\0' != *pwsz; pwsz++) { switch (*pwsz) { case L';': *pwsz = L'\n'; break;
case L'\\': if (L'n' == pwsz[1]) { *pwsz++ = L'\r'; *pwsz = L'\n'; } break; } }
hr = myGetLong(pwszRequestId, &RequestId); _JumpIfError(hr, error, "RequestId must be a number");
hr = Admin_Init(g_DispatchFlags, &diAdmin); _JumpIfError(hr, error, "Admin_Init");
fMustRelease = TRUE;
hr = Admin_SetRequestAttributes( &diAdmin, g_pwszConfig, RequestId, strAttributes); _JumpIfError(hr, error, "Admin_SetAttributes");
error: if (fMustRelease) { Admin_Release(&diAdmin); } if (NULL != strAttributes) { SysFreeString(strAttributes); } return(hr); }
HRESULT verbSetExtension( IN WCHAR const *pwszOption, IN WCHAR const *pwszRequestId, IN WCHAR const *pwszExtensionName, IN WCHAR const *pwszFlags, IN WCHAR const *pwszValue) { HRESULT hr; DISPATCHINTERFACE diAdmin; LONG RequestId; LONG Flags; BSTR strExtensionName = NULL; BSTR strValue = NULL; LONG PropType; VARIANT var; BOOL fMustRelease = FALSE; BYTE *pbValue = NULL; DWORD cbValue;
hr = myGetLong(pwszRequestId, &RequestId); _JumpIfError(hr, error, "RequestId must be a number");
if (!ConvertWszToBstr(&strExtensionName, pwszExtensionName, MAXDWORD)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "ConvertWszToBstr"); } hr = myGetLong(pwszFlags, &Flags); _JumpIfError(hr, error, "Flags must be a number");
if (~EXTENSION_POLICY_MASK & Flags) { hr = E_INVALIDARG; _JumpError(hr, error, "Flags must be <= 0xffff"); } if (L'@' == *pwszValue) { pwszValue++;
// Read in and decode the extension from a file.
// Try Hex-Ascii, Base64 with and without a header, then binary.
hr = DecodeFileW(pwszValue, &pbValue, &cbValue, CRYPT_STRING_HEX_ANY); if (S_OK != hr) { hr = DecodeFileW(pwszValue, &pbValue, &cbValue, CRYPT_STRING_ANY); _JumpIfError(hr, error, "DecodeFileW"); }
CSASSERT(NULL != pbValue && 0 != cbValue);
var.vt = VT_BSTR; PropType = PROPTYPE_BINARY;
DumpHex(0, pbValue, cbValue); if (!ConvertWszToBstr(&strValue, (WCHAR const *) pbValue, cbValue)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "ConvertWszToBstr"); } var.bstrVal = strValue; } else { hr = myGetLong(pwszValue, &var.lVal); if (S_OK == hr) { var.vt = VT_I4; PropType = PROPTYPE_LONG; } else { hr = myWszLocalTimeToGMTDate(pwszValue, &var.date); if (S_OK == hr) { var.vt = VT_DATE; PropType = PROPTYPE_DATE; } else { PropType = PROPTYPE_STRING; if (!ConvertWszToBstr(&strValue, pwszValue, MAXDWORD)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "ConvertWszToBstr"); } var.vt = VT_BSTR; var.bstrVal = strValue; } } }
hr = Admin_Init(g_DispatchFlags, &diAdmin); if (S_OK != hr) { _JumpError(hr, error, "Admin_Init"); } fMustRelease = TRUE;
hr = Admin_SetCertificateExtension( &diAdmin, g_pwszConfig, RequestId, strExtensionName, PropType, Flags, &var); _JumpIfError(hr, error, "Admin_SetExtension");
error: if (NULL != pbValue) { LocalFree(pbValue); } if (fMustRelease) { Admin_Release(&diAdmin); } if (NULL != strExtensionName) { SysFreeString(strExtensionName); } if (NULL != strValue) { SysFreeString(strValue); } return(hr); }
HRESULT verbImportCertificate( IN WCHAR const *pwszOption, IN WCHAR const *pwszCertificateFile, IN WCHAR const *pwszArg2, IN WCHAR const *pwszArg3, IN WCHAR const *pwszArg4) { HRESULT hr; LONG dwReqID; CERT_CONTEXT const *pCertContext = NULL; DISPATCHINTERFACE diAdmin; BOOL fRelease = FALSE; hr = Admin_Init(g_DispatchFlags, &diAdmin); _JumpIfError(hr, error, "Admin_Init");
fRelease = TRUE;
hr = cuLoadCert(pwszCertificateFile, &pCertContext); _JumpIfError(hr, error, "cuLoadCert");
hr = Admin_ImportCertificate( &diAdmin, g_pwszConfig, (WCHAR const *) pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, (g_fForce? ICF_ALLOWFOREIGN : 0) | CR_IN_BINARY, &dwReqID); _JumpIfError(hr, error, "Admin_ImportCertificate");
wprintf(myLoadResourceString(IDS_FORMAT_IMPORTCERT), dwReqID); wprintf(wszNewLine);
error: cuUnloadCert(&pCertContext); if (fRelease) { Admin_Release(&diAdmin); } return(hr); }
HRESULT DumpKeyRecipientInfo( IN BYTE const *pbRecoveryBlob, IN DWORD cbRecoveryBlob) { HRESULT hr; BYTE *pbEncryptedKey = NULL; DWORD cbEncryptedKey; DWORD cRecipient; HCERTSTORE hStore = NULL; HCRYPTMSG hMsg = NULL; DWORD dwMsgType; BYTE abHash[CBMAX_CRYPT_HASH_LEN];
hr = myDecodePKCS7( pbRecoveryBlob, cbRecoveryBlob, &pbEncryptedKey, &cbEncryptedKey, &dwMsgType, NULL, // ppszInnerContentObjId
NULL, // pcSigner
NULL, // pcRecipient
&hStore, NULL); // phMsg
_JumpIfError(hr, error, "myDecodePKCS7");
if (NULL == pbEncryptedKey) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "No Content"); } if (CMSG_SIGNED != dwMsgType) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "Not Signed"); } hr = myDecodePKCS7( pbEncryptedKey, cbEncryptedKey, NULL, // ppbContent
NULL, // pcbContent
&dwMsgType, NULL, // ppszInnerContentObjId
NULL, // pcSigner
&cRecipient, NULL, // phStore
&hMsg); _JumpIfError(hr, error, "myDecodePKCS7");
if (CMSG_ENVELOPED != dwMsgType) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "Not Encrypted"); } if (NULL == hMsg || 0 == cRecipient) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "No Msg or Recipients"); } hr = cuDumpRecipients(hMsg, hStore, cRecipient, TRUE); _JumpIfError(hr, error, "cuDumpRecipients");
error: if (NULL != hMsg) { CryptMsgClose(hMsg); } if (NULL != hStore) { CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG); } if (NULL != pbEncryptedKey) { LocalFree(pbEncryptedKey); } return(hr); }
HRESULT GetArchivedKey( IN WCHAR const *pwszConfig, IN DWORD RequestId, OPTIONAL IN WCHAR const *pwszfnRecoveryBlob) { HRESULT hr; DISPATCHINTERFACE diAdmin; BOOL fRelease = FALSE; BSTR strKey = NULL; WCHAR *pwszT = NULL;
hr = Admin_Init(g_DispatchFlags, &diAdmin); _JumpIfError(hr, error, "Admin_Init");
fRelease = TRUE;
hr = Admin2_GetArchivedKey( &diAdmin, pwszConfig, RequestId, CR_OUT_BINARY, &strKey); _JumpIfError(hr, error, "Admin_GetArchivedKey");
if (NULL == pwszfnRecoveryBlob) { hr = myCryptBinaryToString( (BYTE const *) strKey, SysStringByteLen(strKey), CRYPT_STRING_BASE64HEADER, &pwszT); _JumpIfError(hr, error, "myCryptBinaryToString");
cuPrintCRLFString(NULL, pwszT); } else { hr = EncodeToFileW( pwszfnRecoveryBlob, (BYTE const *) strKey, SysStringByteLen(strKey), CRYPT_STRING_BINARY | g_EncodeFlags); _JumpIfError(hr, error, "EncodeToFileW"); } hr = DumpKeyRecipientInfo((BYTE const *) strKey, SysStringByteLen(strKey)); _PrintIfError(hr, "DumpKeyRecipientInfo");
hr = S_OK;
error: if (NULL != pwszT) { LocalFree(pwszT); } if (NULL != strKey) { SysFreeString(strKey); } if (fRelease) { Admin_Release(&diAdmin); } return(hr); }
typedef struct _GETKEYSERIAL { struct _GETKEYSERIAL *Next; DWORD dwVersion; BSTR strConfig; LONG RequestId; BSTR strSerialNumber; BSTR strCommonName; BSTR strUPN; BSTR strHash; BSTR strCert; } GETKEYSERIAL;
VOID FreeKeySerialEntry( IN OUT GETKEYSERIAL *pks) { if (NULL != pks->strConfig) { SysFreeString(pks->strConfig); } if (NULL != pks->strSerialNumber) { SysFreeString(pks->strSerialNumber); } if (NULL != pks->strCommonName) { SysFreeString(pks->strCommonName); } if (NULL != pks->strUPN) { SysFreeString(pks->strUPN); } if (NULL != pks->strHash) { SysFreeString(pks->strHash); } if (NULL != pks->strCert) { SysFreeString(pks->strCert); } LocalFree(pks); }
HRESULT AddKeySerialList( IN WCHAR const *pwszConfig, IN LONG RequestId, IN WCHAR const *pwszSerialNumber, IN WCHAR const *pwszCommonName, IN WCHAR const *pwszUPN, IN WCHAR const *pwszHash, IN BYTE const *pbCert, IN DWORD cbCert, IN OUT GETKEYSERIAL **ppksList) { HRESULT hr; CERT_CONTEXT const *pcc = NULL; GETKEYSERIAL *pksNew = NULL; GETKEYSERIAL *pksT; GETKEYSERIAL *pksPrev; BOOL fNewConfig = TRUE;
pcc = CertCreateCertificateContext(X509_ASN_ENCODING, pbCert, cbCert); if (NULL == pcc) { hr = myHLastError(); _JumpError(hr, error, "CertCreateCertificateContext"); } pksNew = (GETKEYSERIAL *) LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, sizeof(*pksNew)); if (NULL == pksNew) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } pksNew->RequestId = RequestId; pksNew->dwVersion = pcc->pCertInfo->dwVersion;
pksNew->strConfig = SysAllocString(pwszConfig); pksNew->strSerialNumber = SysAllocString(pwszSerialNumber); pksNew->strCommonName = SysAllocString(pwszCommonName); pksNew->strUPN = SysAllocString(pwszUPN); pksNew->strHash = SysAllocString(pwszHash); pksNew->strCert = SysAllocStringByteLen((char const *) pbCert, cbCert); if (NULL == pksNew->strConfig || NULL == pksNew->strSerialNumber || (NULL != pwszCommonName && NULL == pksNew->strCommonName) || (NULL != pwszUPN && NULL == pksNew->strUPN) || NULL == pksNew->strHash || NULL == pksNew->strCert) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } pksPrev = NULL; for (pksT = *ppksList; NULL != pksT; pksT = pksT->Next) { if (NULL != pksT->strConfig) { fNewConfig = 0 != lstrcmp(pksT->strConfig, pksNew->strConfig); } pksPrev = pksT; } if (NULL == pksPrev) { *ppksList = pksNew; } else { pksPrev->Next = pksNew; } if (!fNewConfig) { SysFreeString(pksNew->strConfig); pksNew->strConfig = NULL; } pksNew = NULL; hr = S_OK;
error: if (NULL != pcc) { CertFreeCertificateContext(pcc); } if (NULL != pksNew) { FreeKeySerialEntry(pksNew); } return(hr); }
HRESULT cuViewQueryWorker( IN WCHAR const *pwszConfig, IN WCHAR const *pwszColumn, IN WCHAR const *pwszValue1, OPTIONAL IN WCHAR const *pwszValue2, IN OUT GETKEYSERIAL **ppksList, OUT BOOL *pfConnectionFailed) { HRESULT hr; DWORD cwc; DISPATCHINTERFACE diView; DISPATCHINTERFACE diViewRow; DISPATCHINTERFACE diViewColumn; BOOL fMustRelease = FALSE; BOOL fMustReleaseRow = FALSE; BOOL fMustReleaseColumn = FALSE; LONG ColIndex; LONG RowIndex; DWORD cRow; VARIANT var; LONG RequestId; DWORD i; static WCHAR *apwszCol[] = { #define IV_REQUESTID 0
wszPROPCERTIFICATEREQUESTID,
#define IV_SERIALNUMBER 1
wszPROPCERTIFICATESERIALNUMBER,
#define IV_COMMONNAME 2
wszPROPCOMMONNAME,
#define IV_ARCHIVEDKEY 3
wszPROPREQUESTRAWARCHIVEDKEY,
#define IV_HASH 4
wszPROPCERTIFICATEHASH,
#define IV_CERT 5
wszPROPRAWCERTIFICATE,
#define IV_UPN 6
wszPROPCERTIFICATEUPN, }; static LONG altype[] = { PROPTYPE_LONG, PROPTYPE_STRING, PROPTYPE_STRING, PROPTYPE_BINARY, PROPTYPE_STRING, PROPTYPE_BINARY, PROPTYPE_STRING, }; BSTR astrValue[ARRAYSIZE(apwszCol)];
ZeroMemory(astrValue, sizeof(astrValue)); VariantInit(&var); *pfConnectionFailed = TRUE; DBGPRINT(( DBG_SS_CERTUTILI, "Query(%ws, %ws == %ws + %ws)\n", pwszConfig, pwszColumn, pwszValue1, pwszValue2));
hr = View_Init(g_DispatchFlags, &diView); _JumpIfError(hr, error, "View_Init");
fMustRelease = TRUE;
hr = View_OpenConnection(&diView, pwszConfig); _JumpIfError(hr, error, "View_OpenConnection");
*pfConnectionFailed = FALSE;
hr = View_GetColumnIndex( &diView, CVRC_COLUMN_SCHEMA, pwszColumn, &ColIndex); _JumpIfErrorStr(hr, error, "View_GetColumnIndex", pwszColumn);
cwc = wcslen(pwszValue1); if (NULL != pwszValue2) { cwc += wcslen(pwszValue2); } var.bstrVal = SysAllocStringLen(NULL, cwc); if (NULL == var.bstrVal) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "SysAllocString"); } var.vt = VT_BSTR; wcscpy(var.bstrVal, pwszValue1); if (NULL != pwszValue2) { wcscat(var.bstrVal, pwszValue2); }
hr = View_SetRestriction( &diView, ColIndex, // Restriction ColumnIndex
CVR_SEEK_EQ, CVR_SORT_ASCEND, &var); // pvarValue
_JumpIfError(hr, error, "View_SetRestriction");
hr = View_SetResultColumnCount(&diView, ARRAYSIZE(apwszCol)); _JumpIfError(hr, error, "View_SetResultColumnCount");
for (i = 0; i < ARRAYSIZE(apwszCol); i++) { hr = View_GetColumnIndex( &diView, CVRC_COLUMN_SCHEMA, apwszCol[i], &ColIndex); _JumpIfErrorStr( hr, error, "View_GetColumnIndex", apwszCol[i]);
hr = View_SetResultColumn(&diView, ColIndex); _JumpIfError(hr, error, "View_SetResultColumn"); }
hr = View_OpenView(&diView, &diViewRow); _JumpIfError(hr, error, "View_OpenView");
fMustReleaseRow = TRUE;
for (cRow = 0; ; cRow++) { hr = ViewRow_Next(&diViewRow, &RowIndex); if (S_FALSE == hr || (S_OK == hr && -1 == RowIndex)) { break; } _JumpIfError(hr, error, "ViewRow_Next");
if (fMustReleaseColumn) { ViewColumn_Release(&diViewColumn); fMustReleaseColumn = FALSE; } hr = ViewRow_EnumCertViewColumn(&diViewRow, &diViewColumn); _JumpIfError(hr, error, "ViewRow_EnumCertViewColumn");
fMustReleaseColumn = TRUE;
for (i = 0; i < ARRAYSIZE(apwszCol); i++) { VOID *pv; hr = ViewColumn_Next(&diViewColumn, &ColIndex); if (S_FALSE == hr || (S_OK == hr && -1 == ColIndex)) { break; } _JumpIfError(hr, error, "ViewColumn_Next");
pv = &RequestId; if (PROPTYPE_LONG != altype[i]) { pv = &astrValue[i]; }
hr = ViewColumn_GetValue( &diViewColumn, CV_OUT_BINARY, altype[i], pv); if (S_OK != hr) { _PrintErrorStr2( hr, "ViewColumn_GetValue", apwszCol[i], CERTSRV_E_PROPERTY_EMPTY); if (CERTSRV_E_PROPERTY_EMPTY != hr) { goto error; } } }
DBGPRINT(( DBG_SS_CERTUTILI, "RequestId=%u Serial=%ws CN=%ws UPN=%ws Key=%u\n", RequestId, astrValue[IV_SERIALNUMBER], astrValue[IV_COMMONNAME], astrValue[IV_UPN], NULL != astrValue[IV_ARCHIVEDKEY]));
if (NULL != astrValue[IV_SERIALNUMBER] && NULL != astrValue[IV_HASH] && NULL != astrValue[IV_CERT] && (g_fForce || NULL != astrValue[IV_ARCHIVEDKEY])) { hr = AddKeySerialList( pwszConfig, RequestId, astrValue[IV_SERIALNUMBER], astrValue[IV_COMMONNAME], astrValue[IV_UPN], astrValue[IV_HASH], (BYTE const *) astrValue[IV_CERT], SysStringByteLen(astrValue[IV_CERT]), ppksList); _JumpIfError(hr, error, "AddKeySerialList"); }
for (i = 0; i < ARRAYSIZE(astrValue); i++) { if (NULL != astrValue[i]) { SysFreeString(astrValue[i]); astrValue[i] = NULL; } } } hr = S_OK;
error: if (fMustReleaseColumn) { ViewColumn_Release(&diViewColumn); } if (fMustReleaseRow) { ViewRow_Release(&diViewRow); } if (fMustRelease) { View_Release(&diView); } for (i = 0; i < ARRAYSIZE(astrValue); i++) { if (NULL != astrValue[i]) { SysFreeString(astrValue[i]); } } VariantClear(&var); return(hr); }
// Print the string, except for the newline at the start or end of the string.
VOID PutStringStripNL( IN WCHAR const *pwszValue) { DWORD cwc; cwc = wcslen(pwszValue); if (L'\n' == *pwszValue) { pwszValue++; cwc--; } else if (NULL != wcschr(pwszValue, L'\n')) { cwc--; CSASSERT('\n' == pwszValue[cwc]); } wprintf(L"%.*ws", cwc, pwszValue); }
HRESULT cuViewQuery( IN WCHAR const *pwszConfig, IN WCHAR const *pwszColumn, IN WCHAR const *pwszValue1, OPTIONAL IN WCHAR const *pwszValue2, IN OUT GETKEYSERIAL **ppksList, OUT BOOL *pfConnectionFailed) { HRESULT hr; if (!g_fQuiet) { if (g_fVerbose) { wprintf(L" %ws: ", pwszColumn); PutStringStripNL(pwszValue1); if (NULL != pwszValue2) { wprintf(L" + "); PutStringStripNL(pwszValue2); } wprintf(wszNewLine); } else { wprintf(L"..."); } } hr = cuViewQueryWorker( pwszConfig, pwszColumn, pwszValue1, pwszValue2, ppksList, pfConnectionFailed); _JumpIfError(hr, error, "cuViewQueryWorker");
error: return(hr); }
#define wszCOMPUTERS L"Computers"
#define wszUSERS L"Users"
#define wszRECIPIENTS L"recipients"
#define wszCOMPUTERSNL wszCOMPUTERS L"\n"
#define wszUSERSNL wszUSERS L"\n"
#define wszRECIPIENTSNL wszRECIPIENTS L"\n"
#define wszNLRECIPIENTS L"\n" wszRECIPIENTS
HRESULT GetKey( IN WCHAR const *pwszConfig, IN WCHAR const *pwszCommonName, OPTIONAL IN WCHAR const *pwszRequesterName, OPTIONAL IN WCHAR const *pwszUPN, OPTIONAL IN WCHAR const *pwszSerialNumber, OPTIONAL IN WCHAR const *pwszHash, IN OUT GETKEYSERIAL **ppksList) { HRESULT hr; BOOL fConnectionFailed;
if (!g_fQuiet) { wprintf(myLoadResourceString(IDS_FORMAT_QUERYING), pwszConfig); if (g_fVerbose) { wprintf(wszNewLine); } }
hr = cuViewQuery( pwszConfig, wszPROPCOMMONNAME, pwszCommonName, NULL, ppksList, &fConnectionFailed); _PrintIfErrorStr(hr, "cuViewQuery", wszPROPSUBJECTCOMMONNAME); if (S_OK != hr) { if (fConnectionFailed) { goto error; } }
if (NULL == wcschr(pwszCommonName, L'\n')) { hr = cuViewQuery( pwszConfig, wszPROPCOMMONNAME, wszCOMPUTERSNL, pwszCommonName, ppksList, &fConnectionFailed); _PrintIfErrorStr(hr, "cuViewQuery", wszCOMPUTERS L"+" wszPROPSUBJECTCOMMONNAME );
hr = cuViewQuery( pwszConfig, wszPROPCOMMONNAME, wszUSERSNL, pwszCommonName, ppksList, &fConnectionFailed); _PrintIfErrorStr(hr, "cuViewQuery", wszUSERS L"+" wszPROPSUBJECTCOMMONNAME );
hr = cuViewQuery( pwszConfig, wszPROPCOMMONNAME, wszRECIPIENTSNL, pwszCommonName, ppksList, &fConnectionFailed); _PrintIfErrorStr(hr, "cuViewQuery", wszRECIPIENTS L"+" wszPROPSUBJECTCOMMONNAME);
hr = cuViewQuery( pwszConfig, wszPROPCOMMONNAME, pwszCommonName, wszNLRECIPIENTS, ppksList, &fConnectionFailed); _PrintIfErrorStr(hr, "cuViewQuery", wszPROPSUBJECTCOMMONNAME L"+" wszRECIPIENTS); }
if (NULL != pwszSerialNumber) { hr = cuViewQuery( pwszConfig, wszPROPCERTIFICATESERIALNUMBER, pwszSerialNumber, NULL, ppksList, &fConnectionFailed); _PrintIfErrorStr(hr, "cuViewQuery", wszPROPCERTIFICATESERIALNUMBER); } if (NULL != pwszHash) { hr = cuViewQuery( pwszConfig, wszPROPCERTIFICATEHASH, pwszHash, NULL, ppksList, &fConnectionFailed); _PrintIfErrorStr(hr, "cuViewQuery", wszPROPCERTIFICATEHASH); } if (NULL != pwszRequesterName) { hr = cuViewQuery( pwszConfig, wszPROPREQUESTERNAME, pwszRequesterName, NULL, ppksList, &fConnectionFailed); _PrintIfErrorStr(hr, "cuViewQuery", wszPROPREQUESTERNAME); }
if (NULL != pwszUPN) { hr = cuViewQuery( pwszConfig, wszPROPCERTIFICATEUPN, pwszUPN, NULL, ppksList, &fConnectionFailed); _PrintIfErrorStr(hr, "cuViewQuery", wszPROPCERTIFICATEUPN); }
if (!g_fQuiet) { wprintf(wszNewLine); } hr = S_OK;
error: return(hr); }
VOID cuConvertEscapeSequences( IN OUT WCHAR *pwsz) { WCHAR *pwszSrc = pwsz; WCHAR *pwszDst = pwsz;
while (L'\0' != *pwszSrc) { WCHAR wc = *pwszSrc++;
if (L'\\' == wc) { switch (*pwszSrc) { case 'n': wc = L'\n'; pwszSrc++; break;
case 'r': wc = L'\r'; pwszSrc++; break;
case 't': wc = L'\t'; pwszSrc++; break;
default: break; } } *pwszDst++ = wc; } *pwszDst = L'\0'; }
WCHAR * SplitToken( IN OUT WCHAR **ppwszIn, IN WCHAR *pwcSeparator) { WCHAR *pwszOut = NULL; WCHAR *pwszNext = NULL; WCHAR *pwszIn; WCHAR *pwsz;
pwszIn = *ppwszIn; if (NULL != pwszIn) { pwszOut = pwszIn; pwsz = wcschr(pwszIn, *pwcSeparator); if (NULL != pwsz) { *pwsz++ = L'\0'; pwszNext = pwsz; } } *ppwszIn = pwszNext; return(pwszOut); }
HRESULT SimplifyCommonName( OPTIONAL IN WCHAR const *pwszCommonName, OUT WCHAR **ppwszSimpleName) { HRESULT hr; WCHAR *pwszDup = NULL; WCHAR *pwszRemain; WCHAR const *pwszToken;
*ppwszSimpleName = NULL;
if (NULL == pwszCommonName) { pwszCommonName = L"EmptyCN"; } hr = myDupString(pwszCommonName, &pwszDup); _JumpIfError(hr, error, "myDupString");
pwszRemain = pwszDup; while (TRUE) { pwszToken = SplitToken(&pwszRemain, wszNAMESEPARATORDEFAULT); if (NULL == pwszToken) { pwszToken = pwszCommonName; break; } if (0 != LSTRCMPIS(pwszToken, wszUSERS) && 0 != LSTRCMPIS(pwszToken, wszRECIPIENTS)) { break; } } hr = mySanitizeName(pwszToken, ppwszSimpleName); _JumpIfError(hr, error, "mySanitizeName");
error: if (NULL != pwszDup) { LocalFree(pwszDup); } return(hr); }
WCHAR const * wszBatchPassword( IN DWORD Index, OPTIONAL IN WCHAR const *pwszPassword) { static WCHAR wsz0[2 * cwcAUTOPASSWORDMAX + 1]; static WCHAR wsz1[2 * cwcAUTOPASSWORDMAX + 1]; WCHAR const *pwszRet; WCHAR *pwsz = 0 == Index? wsz0 : wsz1;
CSASSERT(0 == Index || 1 == Index); CSASSERT(ARRAYSIZE(wsz0) == ARRAYSIZE(wsz1));
if (NULL == pwszPassword) { SecureZeroMemory(pwsz, sizeof(wsz0)); // password data
pwszRet = NULL; } else { CSASSERT(ARRAYSIZE(wsz0) / 2 >= wcslen(pwszPassword)); if (NULL == wcschr(pwszPassword, L'%')) { pwszRet = pwszPassword; } else { WCHAR const *pwszIn; WCHAR *pwszEnd;
pwszIn = pwszPassword; pwszEnd = &pwsz[ARRAYSIZE(wsz0)]; pwszRet = pwsz; while (pwsz < pwszEnd && L'\0' != (*pwsz = *pwszIn++)) { if (L'%' == *pwsz++) { *pwsz++ = L'%'; } } if (L'\0' != *pwsz) { pwszRet = pwszPassword; } } } return(pwszRet); }
HRESULT DumpGetRecoverMergeCommandLine( OPTIONAL IN BSTR const strConfig, // NULL -> -RecoverKey command line
IN BOOL fRecoverKey, IN GETKEYSERIAL const *pks, OPTIONAL IN WCHAR const *pwszPassword, OPTIONAL IN WCHAR const *pwszSuffix, OPTIONAL OUT WCHAR **ppwszSimpleName) { HRESULT hr; CERT_CONTEXT const *pcc = NULL; CERT_INFO *pCertInfo; BSTR strSerialNumber = NULL; WCHAR *pwszSimpleName = NULL;
if (NULL != ppwszSimpleName) { *ppwszSimpleName = NULL; } pcc = CertCreateCertificateContext( X509_ASN_ENCODING, (BYTE const *) pks->strCert, SysStringByteLen(pks->strCert)); if (NULL == pcc) { hr = myHLastError(); _JumpError(hr, error, "CertCreateCertificateContext"); } pCertInfo = pcc->pCertInfo;
// Convert serial number to string
hr = MultiByteIntegerToBstr( FALSE, pCertInfo->SerialNumber.cbData, pCertInfo->SerialNumber.pbData, &strSerialNumber); _JumpIfError(hr, error, "MultiByteIntegerToBstr");
hr = SimplifyCommonName(pks->strCommonName, &pwszSimpleName); _JumpIfError(hr, error, "SimplifyCommonName");
if (NULL != strConfig) { wprintf( L"%ws -config \"%ws\" -getkey %ws \"%ws-%ws%ws\"\n\n", g_pwszProg, strConfig, strSerialNumber, pwszSimpleName, strSerialNumber, wszRECSUFFIX); } else if (fRecoverKey) { wprintf( L"%ws -p \"%ws\" -recoverkey -user \"%ws-%ws%ws\" \"%ws-%ws%ws\"\n\n", g_pwszProg, wszBatchPassword(0, pwszPassword), pwszSimpleName, strSerialNumber, wszRECSUFFIX, pwszSimpleName, strSerialNumber, wszP12SUFFIX); wszBatchPassword(0, NULL); // password data
} else // else just print the filename (for -MergePFX or delete)
{ wprintf( L"\"%ws-%ws%ws\"", pwszSimpleName, strSerialNumber, pwszSuffix); } if (NULL != ppwszSimpleName) { *ppwszSimpleName = pwszSimpleName; pwszSimpleName = NULL; } hr = S_OK;
error: if (NULL != pcc) { CertFreeCertificateContext(pcc); } if (NULL != strSerialNumber) { SysFreeString(strSerialNumber); } if (NULL != pwszSimpleName) { LocalFree(pwszSimpleName); } return(hr); }
HRESULT DumpRecoveryCandidate( IN GETKEYSERIAL const *pks) { HRESULT hr; CERT_CONTEXT const *pcc = NULL; CERT_INFO *pCertInfo;
pcc = CertCreateCertificateContext( X509_ASN_ENCODING, (BYTE const *) pks->strCert, SysStringByteLen(pks->strCert)); if (NULL == pcc) { hr = myHLastError(); _JumpError(hr, error, "CertCreateCertificateContext"); } pCertInfo = pcc->pCertInfo;
hr = cuDumpSerial(g_wszPad2, IDS_SERIAL, &pCertInfo->SerialNumber); _JumpIfError(hr, error, "cuDumpSerial");
hr = cuDisplayCertName( FALSE, // fMultiLine
g_wszPad2, myLoadResourceString(IDS_SUBJECT), // "Subject"
g_wszPad2, &pCertInfo->Subject, pCertInfo); _JumpIfError(hr, error, "cuDisplayCertName(Subject)");
if (NULL != pks->strUPN) { wprintf(g_wszPad2); wprintf(myLoadResourceString(IDS_UPN_COLON)); // "UPN:"
wprintf(L"%ws\n", pks->strUPN); }
wprintf(g_wszPad2); hr = cuDumpFileTime(IDS_NOTBEFORE, NULL, &pCertInfo->NotBefore); _JumpIfError(hr, error, "cuDumpFileTime");
wprintf(g_wszPad2); hr = cuDumpFileTime(IDS_NOTAFTER, NULL, &pCertInfo->NotAfter); _JumpIfError(hr, error, "cuDumpFileTime");
hr = cuDumpCertType(g_wszPad2, pCertInfo); _PrintIfError(hr, "cuDumpCertType");
wprintf(g_wszPad2); wprintf( myLoadResourceString(IDS_FORMAT_VERSION), // "Version: %u"
1 + pks->dwVersion); wprintf(wszNewLine);
wprintf(g_wszPad2); hr = cuDisplayHash(NULL, pcc, NULL, CERT_SHA1_HASH_PROP_ID, L"sha1"); _JumpIfError(hr, error, "cuDisplayHash");
error: wprintf(wszNewLine); if (NULL != pcc) { CertFreeCertificateContext(pcc); } return(hr); }
VOID DumpRecoveryCommandLines( IN GETKEYSERIAL const *pksList, IN DWORD dwVersion, IN DWORD cCandidate, IN WCHAR const *pwszPasswordIntermediate, IN WCHAR const *pwszPasswordFinal) { GETKEYSERIAL const *pksT; BSTR strConfigT; DWORD cPFX; WCHAR *pwszSimpleName = NULL;
strConfigT = NULL; wprintf(L"\n@echo "); wprintf( myLoadResourceString(IDS_FORMAT_RECOVER_VERSIONX_KEYS_COLON), // "Version %u certificates and keys:"
1 + dwVersion); wprintf(wszNewLine);
// generate certutil -getkey commands:
for (pksT = pksList; NULL != pksT; pksT = pksT->Next) { if (NULL != pksT->strConfig) { strConfigT = pksT->strConfig; } if ((CERT_V1 == dwVersion && CERT_V1 == pksT->dwVersion) || (CERT_V1 != dwVersion && CERT_V1 != pksT->dwVersion)) { DumpGetRecoverMergeCommandLine( strConfigT, FALSE, // fRecoverKey
pksT, NULL, // pwszPassword
NULL, // pwszSuffix
NULL); // ppwszSimpleName
} }
// generate certutil -recoverkey commands:
for (pksT = pksList; NULL != pksT; pksT = pksT->Next) { if ((CERT_V1 == dwVersion && CERT_V1 == pksT->dwVersion) || (CERT_V1 != dwVersion && CERT_V1 != pksT->dwVersion)) { DumpGetRecoverMergeCommandLine( NULL, // strConfig
TRUE, // fRecoverKey
pksT, pwszPasswordIntermediate, NULL, // pwszSuffix
NULL); // ppwszSimpleName
} }
// generate certutil -MergePFX command:
cPFX = 0; wprintf( L"%ws -p \"%ws\",\"%ws\" -MergePFX -user ", g_pwszProg, wszBatchPassword(0, pwszPasswordIntermediate), wszBatchPassword(1, CERT_V1 == dwVersion? pwszPasswordIntermediate : pwszPasswordFinal)); wszBatchPassword(0, NULL); // password data
wszBatchPassword(1, NULL); // password data
for (pksT = pksList; NULL != pksT; pksT = pksT->Next) { if ((CERT_V1 == dwVersion && CERT_V1 == pksT->dwVersion) || (CERT_V1 != dwVersion && CERT_V1 != pksT->dwVersion)) { if (0 != cPFX) { wprintf(L","); } DumpGetRecoverMergeCommandLine( NULL, // strConfig
FALSE, // fRecoverKey
pksT, NULL, // pwszPassword
wszP12SUFFIX, 0 == cPFX? &pwszSimpleName : NULL); cPFX++; } } CSASSERT(cCandidate == cPFX); wprintf( L" \"%ws%ws%ws\"\n\n", pwszSimpleName, CERT_V1 == dwVersion? wszV1SUFFIX : L"", wszP12SUFFIX);
// generate intermediate file delete commands:
for (pksT = pksList; NULL != pksT; pksT = pksT->Next) { if ((CERT_V1 == dwVersion && CERT_V1 == pksT->dwVersion) || (CERT_V1 != dwVersion && CERT_V1 != pksT->dwVersion)) { wprintf(L"@del "); DumpGetRecoverMergeCommandLine( NULL, // strConfig
FALSE, // fRecoverKey
pksT, NULL, // pwszPassword
wszRECSUFFIX, NULL); // ppwszSimpleName
wprintf(wszNewLine); wprintf(L"@del "); DumpGetRecoverMergeCommandLine( NULL, // strConfig
FALSE, // fRecoverKey
pksT, NULL, // pwszPassword
wszP12SUFFIX, NULL); // ppwszSimpleName
wprintf(wszNewLine); } }
if (CERT_V1 == dwVersion) { // generate certutil -ConvertEPF command:
wprintf( L"%ws -p \"%ws,%ws\" -ConvertEPF \"%ws%ws%ws\" \"%ws%ws\"\n", g_pwszProg, wszBatchPassword(0, pwszPasswordIntermediate), wszBatchPassword(1, pwszPasswordFinal), pwszSimpleName, wszV1SUFFIX, wszP12SUFFIX, pwszSimpleName, wszEPFSUFFIX); wszBatchPassword(0, NULL); // password data
wszBatchPassword(1, NULL); // password data
// generate V1 intermediate PFX file delete command:
wprintf(L"@del "); wprintf( L"@delete \"%ws%ws%ws\"\n", pwszSimpleName, wszV1SUFFIX, wszP12SUFFIX); }
//error:
if (NULL != pwszSimpleName) { LocalFree(pwszSimpleName); } }
HRESULT cuGenerateOutFilePassword( OUT WCHAR **ppwszPassword) { HRESULT hr; WCHAR wszPassword[MAX_PATH];
*ppwszPassword = NULL; hr = cuGeneratePassword( 1, // cwcMax (use default length)
wszPassword, ARRAYSIZE(wszPassword)); hr = myDupString(wszPassword, ppwszPassword); _JumpIfError(hr, error, "myDupString");
error: SecureZeroMemory(wszPassword, sizeof(wszPassword)); // password data
return(hr); }
HRESULT verbGetKey( IN WCHAR const *pwszOption, IN WCHAR const *pwszUserNameOrSerialNumber, OPTIONAL IN WCHAR const *pwszfnRecoveryBlob, IN WCHAR const *pwszArg3, IN WCHAR const *pwszArg4) { HRESULT hr; DISPATCHINTERFACE diConfig; BOOL fMustRelease = FALSE; WCHAR *pwszCommonName = NULL; WCHAR const *pwszRequesterName = NULL; WCHAR const *pwszUPN = NULL; BSTR strConfig = NULL; BSTR strSerialNumber = NULL; BYTE *pbHash = NULL; DWORD cbHash; BSTR strHash = NULL; GETKEYSERIAL *pksList = NULL; GETKEYSERIAL *pksT; DWORD cCandidate; DWORD cCandidateV1; DWORD cCandidateV3; WCHAR *pwszPasswordIntermediate = NULL; WCHAR *pwszPasswordFinal = NULL;
if (NULL == pwszfnRecoveryBlob) { wprintf(L"\n@goto start\n"); } hr = myMakeSerialBstr(pwszUserNameOrSerialNumber, &strSerialNumber); CSASSERT((S_OK != hr) ^ (NULL != strSerialNumber));
hr = WszToMultiByteInteger( TRUE, pwszUserNameOrSerialNumber, &cbHash, &pbHash); _PrintIfError2(hr, "WszToMultiByteInteger", hr); if (S_OK == hr) { hr = MultiByteIntegerToBstr(TRUE, cbHash, pbHash, &strHash); _JumpIfError(hr, error, "MultiByteIntegerToBstr"); } hr = myDupString(pwszUserNameOrSerialNumber, &pwszCommonName); _JumpIfError(hr, error, "myDupString");
cuConvertEscapeSequences(pwszCommonName);
if (NULL != wcschr(pwszUserNameOrSerialNumber, L'\\')) { pwszRequesterName = pwszUserNameOrSerialNumber; } if (NULL != wcschr(pwszUserNameOrSerialNumber, L'@')) { pwszUPN = pwszUserNameOrSerialNumber; }
if (NULL == g_pwszConfig) { LONG i; LONG count; LONG Index; hr = Config_Init(g_DispatchFlags, &diConfig); _JumpIfError(hr, error, "Config_Init");
fMustRelease = TRUE;
hr = Config_Reset(&diConfig, 0, &count); _JumpIfError(hr, error, "Config_Reset");
Index = 0; for (i = 0; i < count; i++) { hr = Config_Next(&diConfig, &Index); if (S_OK != hr && S_FALSE != hr) { _JumpError(hr, error, "Config_Next"); } hr = S_OK; if (-1 == Index) { break; }
hr = Config_GetField(&diConfig, wszCONFIG_CONFIG, &strConfig); _JumpIfError(hr, error, "Config_GetField");
hr = GetKey( strConfig, pwszCommonName, pwszRequesterName, pwszUPN, strSerialNumber, strHash, &pksList); _PrintIfError(hr, "GetKey"); // Ignore connection failures
} } else { hr = GetKey( g_pwszConfig, pwszCommonName, pwszRequesterName, pwszUPN, strSerialNumber, strHash, &pksList); _JumpIfError(hr, error, "GetKey"); }
cCandidateV1 = 0; cCandidateV3 = 0; for (pksT = pksList; NULL != pksT; pksT = pksT->Next) { if (NULL != pksT->strConfig) { wprintf(L"\n\"%ws\"\n", pksT->strConfig); } hr = DumpRecoveryCandidate(pksT); _JumpIfError(hr, error, "DumpRecoveryCandidate");
if (CERT_V1 == pksT->dwVersion) { cCandidateV1++; } else { cCandidateV3++; } } cCandidate = cCandidateV1 + cCandidateV3; if (NULL == pwszfnRecoveryBlob && 0 != cCandidate) { hr = cuGenerateOutFilePassword(&pwszPasswordIntermediate); _JumpIfError(hr, error, "cuGenerateOutFilePassword");
hr = cuGenerateOutFilePassword(&pwszPasswordFinal); _JumpIfError(hr, error, "cuGenerateOutFilePassword");
wprintf(L"\n:start\n"); if (0 != cCandidateV1) { DumpRecoveryCommandLines( pksList, CERT_V1, cCandidateV1, pwszPasswordIntermediate, pwszPasswordFinal); } if (0 != cCandidateV3) { DumpRecoveryCommandLines( pksList, CERT_V3, cCandidateV3, pwszPasswordIntermediate, pwszPasswordFinal); } wprintf(L"@echo PASSWORD: \"%ws\"\n", wszBatchPassword(0, pwszPasswordFinal)); wszBatchPassword(0, NULL); // password data
wprintf(L"\n@goto exit\n"); } if (1 != cCandidate) { hr = 0 == cCandidate? CRYPT_E_NOT_FOUND : TYPE_E_AMBIGUOUSNAME; _JumpError(hr, error, "GetKey"); } hr = GetArchivedKey( pksList->strConfig, pksList->RequestId, pwszfnRecoveryBlob); _JumpIfError(hr, error, "GetArchivedKey");
error: while (NULL != pksList) { pksT = pksList; pksList = pksList->Next; FreeKeySerialEntry(pksT); } if (fMustRelease) { Config_Release(&diConfig); } if (NULL != strConfig) { SysFreeString(strConfig); } if (NULL != pwszPasswordIntermediate) { myZeroDataString(pwszPasswordIntermediate); // password data
LocalFree(pwszPasswordIntermediate); } if (NULL != pwszPasswordFinal) { myZeroDataString(pwszPasswordFinal); // password data
LocalFree(pwszPasswordFinal); } if (NULL != pwszCommonName) { LocalFree(pwszCommonName); } if (NULL != pbHash) { LocalFree(pbHash); } if (NULL != strHash) { SysFreeString(strHash); } if (NULL != strSerialNumber) { SysFreeString(strSerialNumber); } return(hr); }
VOID DeleteKey( IN CRYPT_KEY_PROV_INFO const *pkpi) { HCRYPTPROV hProv;
CryptAcquireContext( &hProv, pkpi->pwszContainerName, pkpi->pwszProvName, pkpi->dwProvType, CRYPT_DELETEKEYSET | pkpi->dwFlags); }
HRESULT SaveRecoveredKey( IN CERT_CONTEXT const *pccUser, IN BYTE const *pbKey, IN DWORD cbKey, OPTIONAL IN WCHAR const *pwszfnPFX, OPTIONAL IN WCHAR const *pwszPassword) { HRESULT hr; HCERTSTORE hStoreMemory = NULL; BOOL fMatchingKey; WCHAR wszPassword[MAX_PATH]; CRYPT_KEY_PROV_INFO kpi; CRYPT_DATA_BLOB pfx; BOOL fSigningKey;
pfx.pbData = NULL; ZeroMemory(&kpi, sizeof(kpi));
hr = myValidateKeyBlob( pbKey, cbKey, &pccUser->pCertInfo->SubjectPublicKeyInfo, CERT_V1 == pccUser->pCertInfo->dwVersion, &fSigningKey, &kpi); _JumpIfError(hr, error, "myValidateKeyBlob");
if (!CertSetCertificateContextProperty( pccUser, CERT_KEY_PROV_INFO_PROP_ID, 0, &kpi)) { hr = myHLastError(); _JumpError(hr, error, "CertSetCertificateContextProperty"); }
hStoreMemory = CertOpenStore( CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, NULL, 0, NULL); if (NULL == hStoreMemory) { hr = myHLastError(); _JumpError(hr, error, "CertOpenStore"); }
// Begin Chain Building
hr = myAddChainToMemoryStore(hStoreMemory, pccUser, g_dwmsTimeout); _JumpIfError(hr, error, "myAddChainToMemoryStore");
// End Chain Building
if (NULL != pwszfnPFX) { hr = cuGetPassword( 0, // idsPrompt
NULL, // pwszfn
pwszPassword, TRUE, // fVerify
wszPassword, ARRAYSIZE(wszPassword), &pwszPassword); _JumpIfError(hr, error, "cuGetPassword"); } hr = myPFXExportCertStore( hStoreMemory, &pfx, pwszPassword, !g_fWeakPFX, EXPORT_PRIVATE_KEYS | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY); _JumpIfError(hr, error, "myPFXExportCertStore");
if (NULL != pwszfnPFX) { hr = EncodeToFileW( pwszfnPFX, pfx.pbData, pfx.cbData, CRYPT_STRING_BINARY | (g_fForce? DECF_FORCEOVERWRITE : 0)); _JumpIfError(hr, error, "EncodeToFileW"); }
error: SecureZeroMemory(wszPassword, sizeof(wszPassword)); // password data
if (NULL != hStoreMemory) { CertCloseStore(hStoreMemory, CERT_CLOSE_STORE_CHECK_FLAG); } if (NULL != kpi.pwszContainerName) { DeleteKey(&kpi); LocalFree(kpi.pwszContainerName); } if (NULL != pfx.pbData) { LocalFree(pfx.pbData); } return(hr); }
#if DBG_CERTSRV
#define CDWMS 6
VOID DumpRecoverTime( IN char const *pszPrefix, IN DWORD *rgdwms, IN DWORD idwms) { CSASSERT(0 < idwms); CSASSERT(CDWMS > idwms); rgdwms[idwms] = GetTickCount(); DBGPRINT(( g_fVerbose? DBG_SS_CERTUTIL : DBG_SS_CERTUTILI, "RecoverKey[%u]: %hs: %ums/%ums\n", idwms, pszPrefix, rgdwms[idwms] - rgdwms[idwms - 1], rgdwms[idwms] - rgdwms[0])); } #endif
HRESULT verbRecoverKey( IN WCHAR const *pwszOption, IN WCHAR const *pwszfnRecoveryBlob, OPTIONAL IN WCHAR const *pwszfnPFX, OPTIONAL IN WCHAR const *pwszRecipientIndex, IN WCHAR const *pwszArg4) { HRESULT hr; BYTE *pbIn = NULL; DWORD cbIn; BYTE *pbEncryptedPKCS7 = NULL; DWORD cbEncryptedPKCS7; DWORD cSigner; DWORD cRecipient; DWORD dwMsgType; char *pszInnerContentObjId = NULL; HCERTSTORE hStore = NULL; HCRYPTMSG hMsg = NULL; CERT_CONTEXT const *pccUser = NULL; BYTE abHashUserCert[CBMAX_CRYPT_HASH_LEN]; CRYPT_HASH_BLOB BlobHash; BYTE *pbKey = NULL; DWORD cbKey; DWORD RecipientIndex = MAXDWORD; DBGCODE(DWORD adwms[CDWMS]); DBGCODE(adwms[0] = GetTickCount());
if (NULL != pwszRecipientIndex) { hr = myGetLong(pwszRecipientIndex, (LONG *) &RecipientIndex); _JumpIfError(hr, error, "RecipientIndex must be a number"); }
hr = DecodeFileW(pwszfnRecoveryBlob, &pbIn, &cbIn, CRYPT_STRING_ANY); if (S_OK != hr) { cuPrintError(IDS_ERR_FORMAT_DECODEFILE, hr); goto error; }
// Decode outer PKCS 7 signed message, which contains all of the certs.
hr = myDecodePKCS7( pbIn, cbIn, &pbEncryptedPKCS7, &cbEncryptedPKCS7, &dwMsgType, &pszInnerContentObjId, &cSigner, &cRecipient, &hStore, &hMsg); _JumpIfError(hr, error, "myDecodePKCS7(outer)");
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); if (CMSG_SIGNED != dwMsgType) { _JumpError(hr, error, "dwMsgType(outer)"); } if (0 == cSigner) { _JumpError(hr, error, "cSigner(outer)"); } if (0 != cRecipient) { _JumpError(hr, error, "cRecipient(outer)"); } if (NULL == pszInnerContentObjId || 0 != strcmp(szOID_RSA_data, pszInnerContentObjId)) { _JumpError(hr, error, "pszInnerContentObjId(outer)"); } CSASSERT(NULL != hMsg); ZeroMemory(abHashUserCert, sizeof(abHashUserCert)); BlobHash.cbData = sizeof(abHashUserCert); BlobHash.pbData = abHashUserCert; hr = cuDumpSigners( hMsg, pszInnerContentObjId, hStore, cSigner, NULL == pbEncryptedPKCS7, // fContentEmpty
TRUE, // fVerifyOnly
BlobHash.pbData, &BlobHash.cbData); _JumpIfError(hr, error, "cuDumpSigners(outer)");
pccUser = CertFindCertificateInStore( hStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, // dwFindFlags
CERT_FIND_HASH, &BlobHash, NULL); if (NULL == pccUser) { hr = myHLastError(); _JumpError(hr, error, "CertFindCertificateInStore"); } LocalFree(pszInnerContentObjId); pszInnerContentObjId = NULL;
CryptMsgClose(hMsg); hMsg = NULL;
// Decode inner PKCS 7 encrypted message, which contains the private key.
DBGCODE(DumpRecoverTime("Outer PKCS 7", adwms, 1));
hr = myDecodePKCS7( pbEncryptedPKCS7, cbEncryptedPKCS7, NULL, // ppbContents
NULL, // pcbContents
&dwMsgType, &pszInnerContentObjId, &cSigner, &cRecipient, NULL, // phStore
&hMsg); _JumpIfError(hr, error, "myDecodePKCS7(inner)");
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); if (CMSG_ENVELOPED != dwMsgType) { _JumpError(hr, error, "dwMsgType(inner)"); } if (0 != cSigner) { _JumpError(hr, error, "cSigner(inner)"); } if (0 == cRecipient) { _JumpError(hr, error, "cRecipient(inner)"); } if (NULL == pszInnerContentObjId || 0 != strcmp(szOID_RSA_data, pszInnerContentObjId)) { _JumpError(hr, error, "pszInnerContentObjId(inner)"); } CSASSERT(NULL != hMsg); if (MAXDWORD != RecipientIndex && cRecipient <= RecipientIndex) { hr = E_INVALIDARG; _JumpError(hr, error, "RecipientIndex too large"); }
DBGCODE(DumpRecoverTime("Inner PKCS 7", adwms, 2)); hr = cuDumpEncryptedAsnBinary( hMsg, cRecipient, RecipientIndex, hStore, NULL, pbEncryptedPKCS7, cbEncryptedPKCS7, TRUE, &pbKey, &cbKey); { HRESULT hr2;
wprintf(wszNewLine); wprintf(myLoadResourceString(IDS_USER_CERT)); // "User Certificate:"
wprintf(wszNewLine);
hr2 = cuDumpIssuerSerialAndSubject( &pccUser->pCertInfo->Issuer, &pccUser->pCertInfo->SerialNumber, &pccUser->pCertInfo->Subject, NULL); // hStore
_PrintIfError(hr2, "cuDumpIssuerSerialAndSubject(user)");
hr2 = cuDisplayHash( g_wszPad4, pccUser, NULL, CERT_SHA1_HASH_PROP_ID, L"sha1"); _PrintIfError(hr2, "cuDisplayHash"); }
DBGCODE(DumpRecoverTime("Decrypt key", adwms, 3)); if (CRYPT_E_NO_DECRYPT_CERT != hr) { _JumpIfError(hr, error, "cuDumpEncryptedAsnBinary");
if (g_fVerbose) { wprintf(wszNewLine); hr = cuDumpPrivateKeyBlob(pbKey, cbKey, FALSE); _JumpIfError(hr, error, "cuDumpPrivateKeyBlob"); }
// Verify the key matches the cert, then save in a PFX
hr = SaveRecoveredKey( pccUser, pbKey, cbKey, pwszfnPFX, g_pwszPassword); _JumpIfError(hr, error, "SaveRecoveredKey");
DBGCODE(DumpRecoverTime("Save key", adwms, 4)); } else { // Can't decrypt the private key, list Recipient cert info.
wprintf(myLoadResourceString(IDS_CANT_DECRYPT)); // "Cannot decrypt message content."
wprintf(wszNewLine); DBGCODE(DumpRecoverTime("nop", adwms, 4)); } if (CRYPT_E_NO_DECRYPT_CERT == hr || NULL == pwszfnPFX) { HRESULT hrDecrypt = hr;
wprintf(wszNewLine); wprintf(myLoadResourceString(IDS_NEED_RECOVERY_CERT)); // "Key recovery requires one of the following certificates and its private key:"
wprintf(wszNewLine);
hr = cuDumpRecipients(hMsg, hStore, cRecipient, TRUE); _JumpIfError(hr, error, "cuDumpRecipients");
hr = hrDecrypt; _JumpIfError(hr, error, "Cannot decrypt"); } DBGCODE(DumpRecoverTime("Done", adwms, 5)); hr = S_OK;
error: if (NULL != pccUser) { CertFreeCertificateContext(pccUser); } if (NULL != pbKey) { LocalFree(pbKey); } if (NULL != pbIn) { LocalFree(pbIn); } if (NULL != pbEncryptedPKCS7) { LocalFree(pbEncryptedPKCS7); } if (NULL != pszInnerContentObjId) { LocalFree(pszInnerContentObjId); } if (NULL != hStore) { CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG); } if (NULL != hMsg) { CryptMsgClose(hMsg); } return(hr); }
|