|
|
//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: cryptpick.cpp
//
// Contents: Cert Server wrapper routines
//
//---------------------------------------------------------------------------
#include <pch.cpp>
#pragma hdrstop
#include "cainfop.h"
#include "csdisp.h"
#include "csldap.h"
#include "tfc.h"
#include "clibres.h"
#define CUCS_SOURCEMASK (CUCS_MACHINESTORE | CUCS_USERSTORE | CUCS_DSSTORE)
#define CUCS_TYPEMASK (CUCS_MYSTORE | \
CUCS_CASTORE | \ CUCS_KRASTORE | \ CUCS_ROOTSTORE)
#define CUCS_VALIDMASK (CUCS_SOURCEMASK | \
CUCS_TYPEMASK | \ CUCS_ARCHIVED | \ CUCS_USAGEREQUIRED | \ CUCS_SILENT | \ CUCS_PRIVATEKEYREQUIRED)
// My, CA, KRA and Root stores -- in HKLM, HKCU and the DS
#define CDISPLAYSTOREMAX (4 * 3)
typedef struct _STOREMAP { DWORD dwFlags; WCHAR const *pwszStoreName; WCHAR const *pwszDSTemplate; } STOREMAP;
STOREMAP s_aStoreMap[] = { { CUCS_MYSTORE, wszMY_CERTSTORE, NULL }, { CUCS_CASTORE, wszCA_CERTSTORE, wszDSAIAQUERYTEMPLATE }, { CUCS_KRASTORE, wszKRA_CERTSTORE, wszDSKRAQUERYTEMPLATE }, { CUCS_ROOTSTORE, wszROOT_CERTSTORE, NULL }, { 0x0, NULL, NULL }, };
HRESULT FormatDSStoreName( IN OUT BSTR *pstrDomainDN, IN OUT BSTR *pstrConfigDN, IN WCHAR const *pwszTemplate, OUT WCHAR **ppwszOut) { HRESULT hr; LDAP *pld = NULL;
if (NULL == *pstrConfigDN) // first call
{ hr = myRobustLdapBind(&pld, FALSE); _JumpIfError(hr, error, "myRobustLdapBind");
// Renewal domain and config containers (%5, %6)
hr = myGetAuthoritativeDomainDn(pld, pstrDomainDN, pstrConfigDN); _JumpIfError(hr, error, "myGetAuthoritativeDomainDn"); } hr = myFormatCertsrvStringArray( FALSE, // fURL
L"", // pwszServerName_p1_2
L"", // pwszSanitizedName_p3_7
0, // iCert_p4
*pstrDomainDN, // pwszDomainDN_p5
*pstrConfigDN, // pwszConfigDN_p6
0, // iCRL_p8
FALSE, // fDeltaCRL_p9
FALSE, // fDSAttrib_p10_11
1, // cStrings
(LPCWSTR *) &pwszTemplate, // apwszStringsIn
ppwszOut); // apwszStringsOut
_JumpIfError(hr, error, "myFormatCertsrvStringArray");
error: if (NULL != pld) { ldap_unbind(pld); } return(hr); }
HRESULT myOpenCertStores( IN DWORD dwFlags, // CUCS_*
OUT DWORD *pcStore, OUT HCERTSTORE **prghStore) { HRESULT hr; HRESULT hr2; HCERTSTORE *rghStore = NULL; DWORD cStore = 0; STOREMAP *psm; DWORD OpenFlags; BSTR strDomainDN = NULL; BSTR strConfigDN = NULL; WCHAR *pwszDSStore = NULL;
*pcStore = 0; *prghStore = NULL; rghStore = (HCERTSTORE *) LocalAlloc( LMEM_FIXED, CDISPLAYSTOREMAX * sizeof(HCERTSTORE)); if (NULL == rghStore) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc(rghStore)"); } OpenFlags = CERT_STORE_READONLY_FLAG | CERT_STORE_SET_LOCALIZED_NAME_FLAG; if (CUCS_ARCHIVED & dwFlags) { OpenFlags |= CERT_STORE_ENUM_ARCHIVED_FLAG; }
hr2 = S_OK; if ((CUCS_SOURCEMASK | CUCS_TYPEMASK) & dwFlags) { if (~CUCS_VALIDMASK & dwFlags) { hr = E_INVALIDARG; _JumpError(hr, error, "dwFlags"); } if (0 == (CUCS_SOURCEMASK & dwFlags)) { dwFlags |= CUCS_SOURCEMASK; // source default: all cert store sources
} if (0 == (CUCS_TYPEMASK & dwFlags)) { dwFlags |= CUCS_MYSTORE; // type default: use my store
}
for (psm = s_aStoreMap; NULL != psm->pwszStoreName; psm++) { if (dwFlags & psm->dwFlags) { HCERTSTORE hStore;
if (CUCS_MACHINESTORE & dwFlags) { hStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_W, X509_ASN_ENCODING, NULL, CERT_SYSTEM_STORE_LOCAL_MACHINE | OpenFlags, psm->pwszStoreName); if (NULL == hStore) { hr = myHLastError(); _PrintErrorStr(hr, "CertOpenStore LocalMachine", psm->pwszStoreName); if (S_OK == hr2) { hr2 = hr; } } else { DBGPRINT(( DBG_SS_CERTLIBI, "CertOpenStore LocalMachine(%ws, HKLM)[%u]\n", psm->pwszStoreName, cStore)); rghStore[cStore++] = hStore; } } if (CUCS_USERSTORE & dwFlags) { hStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_W, X509_ASN_ENCODING, NULL, CERT_SYSTEM_STORE_CURRENT_USER | OpenFlags, psm->pwszStoreName); if (NULL == hStore) { hr = myHLastError(); _PrintErrorStr(hr, "CertOpenStore User", psm->pwszStoreName); if (S_OK == hr2) { hr2 = hr; } } else { DBGPRINT(( DBG_SS_CERTLIBI, "CertOpenStore User(%ws, HKCU)[%u]\n", psm->pwszStoreName, cStore)); rghStore[cStore++] = hStore; } } if ((CUCS_DSSTORE & dwFlags) && NULL != psm->pwszDSTemplate) { CString strStoreFriendlyName; int idResource;
switch(psm->dwFlags) { case CUCS_CASTORE: idResource = IDS_STORENAME_DS_AIA; break;
case CUCS_KRASTORE: idResource = IDS_STORENAME_DS_KRA; break;
default: CSASSERT(("Invalid cert store name")); } strStoreFriendlyName.LoadString(idResource);
if (NULL != pwszDSStore) { LocalFree(pwszDSStore); pwszDSStore = NULL; }
hr = FormatDSStoreName( &strDomainDN, &strConfigDN, psm->pwszDSTemplate, &pwszDSStore); if (S_OK != hr) { _PrintError(hr, "FormatDSStoreName"); } else { hStore = CertOpenStore( CERT_STORE_PROV_LDAP_W, X509_ASN_ENCODING, NULL, OpenFlags, pwszDSStore); if (NULL == hStore) { hr = myHLastError(); _PrintErrorStr(hr, "CertOpenStore LDAP", pwszDSStore); if (S_OK == hr2) { hr2 = hr; } } else { CRYPT_DATA_BLOB cdb;
cdb.pbData = (BYTE*)strStoreFriendlyName.GetBuffer(); cdb.cbData = sizeof(WCHAR)* (wcslen(strStoreFriendlyName.GetBuffer())+1); if (!CertSetStoreProperty( hStore, CERT_STORE_LOCALIZED_NAME_PROP_ID, 0, (const void *) &cdb)) { hr = myHLastError(); _PrintErrorStr(hr, "CertSetStoreProp LDAP", pwszDSStore); hr = S_OK; }
DBGPRINT(( DBG_SS_CERTLIBI, "CertOpenStore LDAP(%ws)[%u]\n", pwszDSStore, cStore)); rghStore[cStore++] = hStore; }
} } } } } hr = hr2;
if (0 == cStore) { if (hr == S_OK) hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); _JumpError(hr, error, "no Cert Store"); } CSASSERT(CDISPLAYSTOREMAX >= cStore); *pcStore = cStore; *prghStore = rghStore; rghStore = NULL;
// successfully opened some stores
hr = S_OK;
error: if (NULL != strDomainDN) { SysFreeString(strDomainDN); } if (NULL != strConfigDN) { SysFreeString(strConfigDN); } if (NULL != pwszDSStore) { LocalFree(pwszDSStore); } if (NULL != rghStore) { myCloseCertStores(cStore, rghStore); } return(hr); }
VOID myCloseCertStores( IN DWORD cStore, IN HCERTSTORE *rghStore) { DWORD i;
if (NULL != rghStore) { for (i = cStore; i < cStore; i++) { if (NULL != rghStore[i]) { CertCloseStore(rghStore[i], CERT_CLOSE_STORE_CHECK_FLAG); } } LocalFree(rghStore); } }
// Search for and load the cryptographic provider and private key.
HRESULT myLoadPrivateKey( IN CERT_PUBLIC_KEY_INFO const *pPubKeyInfo, IN DWORD dwFlags, // CUCS_*
OUT HCRYPTPROV *phProv, OUT DWORD *pdwKeySpec, OUT BOOL *pfCallerFreeProv) { HRESULT hr; HCERTSTORE *rghStore = NULL; DWORD cStore;
hr = myOpenCertStores(dwFlags, &cStore, &rghStore); _JumpIfError(hr, error, "myOpenCertStores");
hr = myLoadPrivateKeyFromCertStores( pPubKeyInfo, cStore, rghStore, phProv, pdwKeySpec, pfCallerFreeProv); _JumpIfError(hr, error, "myLoadPrivateKeyFromCertStores");
error: if (NULL != rghStore) { myCloseCertStores(cStore, rghStore); } return(hr); }
HRESULT myLoadPrivateKeyFromCertStores( IN CERT_PUBLIC_KEY_INFO const *pPubKeyInfo, IN DWORD cStore, IN HCERTSTORE *rghStore, OUT HCRYPTPROV *phProv, OUT DWORD *pdwKeySpec, OUT BOOL *pfCallerFreeProv) { HRESULT hr; DWORD i; CERT_CONTEXT const *pcc = NULL;
// for each cert store
// for each cert in store with matching public key (lookup by public key)
// call CryptAcquireCertificatePrivateKey
// if succeeds, exit w/S_OK
hr = S_OK; for (i = 0; i < cStore; i++) { HCERTSTORE hStore = rghStore[i];
while (TRUE) { pcc = CertFindCertificateInStore( hStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_PUBLIC_KEY, pPubKeyInfo, pcc); if (NULL == pcc) { break; } if (!CryptAcquireCertificatePrivateKey( pcc, CRYPT_ACQUIRE_COMPARE_KEY_FLAG, NULL, // pvReserved
phProv, pdwKeySpec, pfCallerFreeProv)) { hr = myHLastError(); _PrintError(hr, "CryptAcquireCertificatePrivateKey"); continue; } hr = S_OK; goto error; } } if (S_OK == hr) { hr = CRYPT_E_NOT_FOUND; } _JumpError(hr, error, "CertFindCertificateInStore");
error: if (NULL != pcc) { CertFreeCertificateContext(pcc); pcc = NULL; } return(hr); }
HRESULT myMakeSerialBstr( IN WCHAR const *pwszSerialNumber, OUT BSTR *pstrSerialNumber) { HRESULT hr = E_OUTOFMEMORY; WCHAR *pwszDup = NULL; WCHAR const *pwszSrc; WCHAR *pwszDst;
pwszDup = (WCHAR *) LocalAlloc( LMEM_FIXED, (wcslen(pwszSerialNumber) + 2) * sizeof(*pwszDup)); if (NULL == pwszDup) { _JumpError(hr, error, "LocalAlloc"); }
pwszSrc = pwszSerialNumber; *pwszDup = L'0'; // allow possible leading zero
pwszDst = &pwszDup[1];
while (L'\0' != *pwszSrc) { WCHAR wc = *pwszSrc++;
if (iswspace(wc)) { continue; } if (L'A' <= wc && L'F' >= wc) { wc += L'a' - L'A'; } if ((L'a' > wc || L'f' < wc) && (L'0' > wc || L'9' < wc)) { hr = E_INVALIDARG; _JumpErrorStr2(hr, error, "myMakeSerialBstr", pwszSerialNumber, hr); } *pwszDst++ = wc; } *pwszDst = L'\0'; pwszSrc = pwszDup; // point at possible extra leading zero
if (1 & (pwszDst - pwszSrc)) { pwszSrc++; // keep the length even
} while (L'0' == pwszSrc[0] && L'0' == pwszSrc[1] && L'\0' != pwszSrc[2]) { pwszSrc += 2; // skip pairs of leading zeros
}
if (!myConvertWszToBstr(pstrSerialNumber, pwszSrc, MAXDWORD)) { _JumpError(hr, error, "myConvertWszToBstr"); } hr = S_OK;
error: if (NULL != pwszDup) { LocalFree(pwszDup); } return(hr); }
HRESULT myNameBlobMatch( IN CERT_NAME_BLOB const *pSubject, IN WCHAR const *pwszCertName, IN BOOL fAllowMissingCN, OUT BOOL *pfMatch) { HRESULT hr; BOOL fFoundCN = FALSE; BOOL fMatchCN = FALSE; CERT_NAME_INFO *pNameInfo = NULL; DWORD cbNameInfo; DWORD i;
if (!myDecodeName( X509_ASN_ENCODING, X509_UNICODE_NAME, pSubject->pbData, pSubject->cbData, CERTLIB_USE_LOCALALLOC, &pNameInfo, &cbNameInfo)) { hr = myHLastError(); _JumpError(hr, error, "myDecodeName"); }
for (i = 0; i < pNameInfo->cRDN; i++) { CERT_RDN const *prdn; DWORD j;
prdn = &pNameInfo->rgRDN[i];
for (j = 0; j < prdn->cRDNAttr; j++) { CERT_RDN_ATTR const *prdna;
prdna = &prdn->rgRDNAttr[j];
if (0 == strcmp(szOID_COMMON_NAME, prdna->pszObjId) && NULL != prdna->Value.pbData) { fFoundCN = TRUE; if (0 == lstrcmpi( pwszCertName, (WCHAR const *) prdna->Value.pbData)) { fMatchCN = TRUE; break; } } } } hr = S_OK;
error: if (NULL != pNameInfo) { LocalFree(pNameInfo); } *pfMatch = fMatchCN || (fAllowMissingCN && !fFoundCN); return(hr); }
HRESULT mySerialNumberMatch( IN CRYPT_INTEGER_BLOB const *pSerialNumber, IN WCHAR const *pwszSerialNumber, OUT BOOL *pfMatch) { HRESULT hr; BSTR strSerialNumber = NULL; BOOL fMatch = FALSE;
hr = MultiByteIntegerToBstr( FALSE, pSerialNumber->cbData, pSerialNumber->pbData, &strSerialNumber); _JumpIfError(hr, error, "MultiByteIntegerToBstr");
if (0 == lstrcmpi(pwszSerialNumber, strSerialNumber)) { fMatch = TRUE; } CSASSERT(S_OK == hr);
error: if (NULL != strSerialNumber) { SysFreeString(strSerialNumber); } *pfMatch = fMatch; return(hr); }
HRESULT myCertHashMatch( IN CERT_CONTEXT const *pCert, IN DWORD cb, IN BYTE const *pb, OUT BOOL *pfMatch) { HRESULT hr; BOOL fMatch = FALSE; BYTE abHash[CBMAX_CRYPT_HASH_LEN]; DWORD cbHash;
//wprintf(L"IN: ");
//DumpHex(DH_NOADDRESS | DH_NOTABPREFIX | DH_NOASCIIHEX | 1, pb, cb);
cbHash = sizeof(abHash); if (!CertGetCertificateContextProperty( pCert, CERT_SHA1_HASH_PROP_ID, abHash, &cbHash)) { hr = myHLastError(); _JumpError(hr, error, "CertGetCertificateContextProperty"); } //wprintf(L"CH: ");
//DumpHex(DH_NOADDRESS | DH_NOTABPREFIX | DH_NOASCIIHEX | 1, abHash, cbHash);
if (cbHash == cb && 0 == memcmp(abHash, pb, cb)) { fMatch = TRUE; hr = S_OK; goto error; }
cbHash = sizeof(abHash); if (!CertGetCertificateContextProperty( pCert, CERT_KEY_IDENTIFIER_PROP_ID, abHash, &cbHash)) { hr = myHLastError(); _PrintError(hr, "CertGetCertificateContextProperty(KeyId)"); } else { //wprintf(L"KH: ");
//DumpHex(DH_NOADDRESS | DH_NOTABPREFIX | DH_NOASCIIHEX | 1, abHash, cbHash);
if (cbHash == cb && 0 == memcmp(abHash, pb, cb)) { fMatch = TRUE; hr = S_OK; goto error; } } hr = S_OK;
error: *pfMatch = fMatch; return(hr); }
HRESULT myCertMatch( IN CERT_CONTEXT const *pCert, IN WCHAR const *pwszCertName, IN BOOL fAllowMissingCN, OPTIONAL IN BYTE const *pbHash, IN DWORD cbHash, OPTIONAL IN WCHAR const *pwszSerialNumber, OUT BOOL *pfMatch) { HRESULT hr; BOOL fMatch = FALSE; if (NULL != pbHash) { hr = myCertHashMatch(pCert, cbHash, pbHash, &fMatch); _JumpIfError(hr, error, "myCertHashMatch"); } if (!fMatch && NULL != pwszSerialNumber) { hr = mySerialNumberMatch( &pCert->pCertInfo->SerialNumber, pwszSerialNumber, &fMatch); _JumpIfError(hr, error, "mySerialNumberMatch"); } if (!fMatch) { hr = myNameBlobMatch( &pCert->pCertInfo->Subject, pwszCertName, fAllowMissingCN, &fMatch); _JumpIfError(hr, error, "myNameBlobMatch"); } hr = S_OK;
error: *pfMatch = fMatch; return(hr); }
HRESULT myCertMatchEKUOrApplicationPolicies( IN CERT_CONTEXT const *pCert, IN DWORD cpszObjId, IN CHAR const * const *apszObjId, IN BOOL fUsageRequired, OUT BOOL *pfMatch) { HRESULT hr; CERT_ENHKEY_USAGE *pKeyUsage = NULL; DWORD cbKeyUsage = 0; BOOL fMatch = FALSE; DWORD i; DWORD j; while (TRUE) { // get enhanced key usage OIDs
if (!CertGetEnhancedKeyUsage( pCert, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, pKeyUsage, &cbKeyUsage)) { // accept match if EKU extension not found
hr = myHLastError(); if (!fUsageRequired && CRYPT_E_NOT_FOUND == hr) { fMatch = TRUE; } _PrintError2(hr, "CertGetEnhancedKeyUsage", CRYPT_E_NOT_FOUND); hr = S_OK; goto error; } if (NULL != pKeyUsage) { break; // EKU extension fetched; break out of while loop
} pKeyUsage = (CERT_ENHKEY_USAGE *) LocalAlloc(LMEM_FIXED, cbKeyUsage); if (NULL == pKeyUsage) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "out of memory"); } }
if (NULL != pKeyUsage) { if (0 == pKeyUsage->cUsageIdentifier) { hr = myHLastError(); // set by CertGetEnhancedKeyUsage
if (S_OK != hr) { fMatch = TRUE; } } else { for (i = 0; i < pKeyUsage->cUsageIdentifier; i++) { if (fMatch) { break; } for (j = 0; j < cpszObjId; j++) { if (0 == strcmp( pKeyUsage->rgpszUsageIdentifier[i], apszObjId[j])) { fMatch = TRUE; // found matching EKU OID
break; } } } } } hr = S_OK;
error: *pfMatch = fMatch; if (NULL != pKeyUsage) { LocalFree(pKeyUsage); } return(hr); }
HRESULT myCRLHashMatch( IN CRL_CONTEXT const *pCRL, IN DWORD cb, IN BYTE const *pb, OUT BOOL *pfMatch) { HRESULT hr; BOOL fMatch = FALSE; BYTE abHash[CBMAX_CRYPT_HASH_LEN]; DWORD cbHash;
cbHash = sizeof(abHash); if (!CertGetCRLContextProperty( pCRL, CERT_SHA1_HASH_PROP_ID, abHash, &cbHash)) { hr = myHLastError(); _JumpError(hr, error, "CertGetCRLContextProperty"); } if (cbHash == cb && 0 == memcmp(abHash, pb, cb)) { fMatch = TRUE; } hr = S_OK;
error: *pfMatch = fMatch; return(hr); }
HRESULT myCRLMatch( IN CRL_CONTEXT const *pCRL, IN WCHAR const *pwszCRLName, IN BOOL fAllowMissingCN, OPTIONAL IN BYTE const *pbHash, IN DWORD cbHash, OUT BOOL *pfMatch) { HRESULT hr; BOOL fMatch = FALSE; if (NULL != pbHash) { hr = myCRLHashMatch(pCRL, cbHash, pbHash, &fMatch); _JumpIfError(hr, error, "myCRLHashMatch"); } if (!fMatch) { hr = myNameBlobMatch( &pCRL->pCrlInfo->Issuer, pwszCRLName, fAllowMissingCN, &fMatch); _JumpIfError(hr, error, "myNameBlobMatch"); } hr = S_OK;
error: *pfMatch = fMatch; return(hr); }
HRESULT myCTLHashMatch( IN CTL_CONTEXT const *pCTL, IN DWORD cb, IN BYTE const *pb, OUT BOOL *pfMatch) { HRESULT hr; BOOL fMatch = FALSE; BYTE abHash[CBMAX_CRYPT_HASH_LEN]; DWORD cbHash;
cbHash = sizeof(abHash); if (!CertGetCTLContextProperty( pCTL, CERT_SHA1_HASH_PROP_ID, abHash, &cbHash)) { hr = myHLastError(); _JumpError(hr, error, "CertGetCTLContextProperty"); } if (cbHash == cb && 0 == memcmp(abHash, pb, cb)) { fMatch = TRUE; } hr = S_OK;
error: *pfMatch = fMatch; return(hr); }
HRESULT myCTLMatch( IN CTL_CONTEXT const *pCTL, OPTIONAL IN BYTE const *pbHash, IN DWORD cbHash, OUT BOOL *pfMatch) { HRESULT hr; BOOL fMatch = FALSE; if (NULL != pbHash) { hr = myCTLHashMatch(pCTL, cbHash, pbHash, &fMatch); _JumpIfError(hr, error, "myCTLHashMatch"); } hr = S_OK;
error: *pfMatch = fMatch; return(hr); }
typedef struct _CERTFILTERCALLBACKDATA { DWORD dwFlags; // CUCS_*
DWORD cpszObjId; CHAR const * const *apszObjId; WCHAR const *pwszCommonName; BYTE *pbHash; DWORD cbHash; BSTR strSerialNumber; HRESULT hr; HCERTSTORE hMemStore; } CERTFILTERCALLBACKDATA;
BOOL WINAPI CertificateFilterProc( PCCERT_CONTEXT pCertContext, BOOL *pfInitialSelectedCert, void *pvCallbackData) { HRESULT hr; BOOL fMatch; CERTFILTERCALLBACKDATA *pCallbackData = (CERTFILTERCALLBACKDATA *) pvCallbackData; CERT_NAME_INFO *pNameInfo = NULL; DWORD cbNameInfo; DWORD i; WCHAR *pwszSubject = NULL;
CSASSERT(NULL != pCertContext);
*pfInitialSelectedCert = FALSE; hr = myCertNameToStr( X509_ASN_ENCODING, &pCertContext->pCertInfo->Subject, CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG | CERT_NAME_STR_NO_QUOTING_FLAG, &pwszSubject); _PrintIfError(hr, "myCertNameToStr"); if (NULL != pCallbackData->apszObjId) { hr = myCertMatchEKUOrApplicationPolicies( pCertContext, pCallbackData->cpszObjId, pCallbackData->apszObjId, CUCS_USAGEREQUIRED & pCallbackData->dwFlags, &fMatch); _JumpIfError(hr, error, "myCertMatchEKUOrApplicationPolicies");
if (!fMatch) { _PrintErrorStr(CRYPT_E_NOT_FOUND, "no matching EKU", pwszSubject); hr = S_OK; goto error; } }
// The CommonName filter serves three purposes: 1: a common name, 2: the
// sha-1 hash of the cert, 3: the sha-1 hash of the public key (or the
// Subject Key Id extension), 4: the serial number of the cert. If any one
// of these match, the cert is accepted.
if (NULL != pCallbackData->pwszCommonName) { hr = myCertMatch( pCertContext, pCallbackData->pwszCommonName, FALSE, // fAllowMissingCN
pCallbackData->pbHash, pCallbackData->cbHash, pCallbackData->strSerialNumber, &fMatch); _JumpIfError(hr, error, "myCertMatch");
if (!fMatch) { _PrintErrorStr2( CRYPT_E_NOT_FOUND, "no matching CN/Hash/Serial", pwszSubject, CRYPT_E_NOT_FOUND); hr = S_OK; goto error; } }
if (CUCS_PRIVATEKEYREQUIRED & pCallbackData->dwFlags) { DWORD cb; if (!CertGetCertificateContextProperty( pCertContext, CERT_KEY_PROV_INFO_PROP_ID, NULL, &cb)) { _PrintErrorStr(CRYPT_E_NOT_FOUND, "no KeyProvInfo", pwszSubject); fMatch = FALSE; hr = S_OK; goto error; } }
fMatch = TRUE; // Attempt to add to the temporary store; if it fails then it already
// exists so we don't want it displayed.
if (!CertAddCertificateLinkToStore( pCallbackData->hMemStore, pCertContext, CERT_STORE_ADD_NEW, NULL)) { fMatch = FALSE; hr = myHLastError(); _PrintErrorStr(hr, "CertAddCertificateLinkToStore Dup", pwszSubject); hr = S_OK; goto error; } hr = S_OK;
error: if (S_OK == pCallbackData->hr || (fMatch && S_FALSE == pCallbackData->hr)) { pCallbackData->hr = hr; // keep the first HRESULT
} if (NULL != pwszSubject) { LocalFree(pwszSubject); } if (NULL != pNameInfo) { LocalFree(pNameInfo); } return(fMatch); }
HRESULT myGetKRACertificateFromPicker( OPTIONAL IN HINSTANCE hInstance, OPTIONAL IN HWND hwndParent, OPTIONAL IN int idTitle, OPTIONAL IN int idSubTitle, OPTIONAL IN WCHAR const *pwszCommonName, IN BOOL fUseDS, IN BOOL fSilent, OUT CERT_CONTEXT const **ppCert) { HRESULT hr; CHAR const *pszObjId = szOID_KP_KEY_RECOVERY_AGENT;
hr = myGetCertificateFromPicker( hInstance, hwndParent, idTitle, idSubTitle, CUCS_MYSTORE | CUCS_KRASTORE | CUCS_CASTORE | CUCS_MACHINESTORE | CUCS_USERSTORE | CUCS_USAGEREQUIRED | (fUseDS? CUCS_DSSTORE : 0) | (fSilent? CUCS_SILENT : 0), pwszCommonName, 0, // cStore
NULL, // rghStore
1, // cpszObjId
&pszObjId, ppCert); _JumpIfError(hr, error, "myGetCertificateFromPicker");
error: return(hr); }
HRESULT myGetERACertificateFromPicker( OPTIONAL IN HINSTANCE hInstance, OPTIONAL IN HWND hwndParent, OPTIONAL IN int idTitle, OPTIONAL IN int idSubTitle, OPTIONAL IN WCHAR const *pwszCommonName, IN BOOL fSilent, OUT CERT_CONTEXT const **ppCert) { HRESULT hr; CHAR const * const apszObjId[2] = { szOID_ENROLLMENT_AGENT, szOID_KP_QUALIFIED_SUBORDINATION, };
hr = myGetCertificateFromPicker( hInstance, hwndParent, idTitle, idSubTitle, CUCS_MYSTORE | CUCS_PRIVATEKEYREQUIRED | //CUCS_USAGEREQUIRED |
(fSilent? CUCS_SILENT : 0), pwszCommonName, 0, // cStore
NULL, // rghStore
ARRAYSIZE(apszObjId), // cpszObjId
apszObjId, ppCert); _JumpIfError(hr, error, "myGetCertificateFromPicker");
error: return(hr); }
HRESULT mySelectCertificateFromStore( IN OUT CRYPTUI_SELECTCERTIFICATE_STRUCT *pCertSelect, IN HCERTSTORE hStore, IN OUT CERT_CONTEXT const **ppCertRet) { HRESULT hr; CERT_CONTEXT const *pCertRet = *ppCertRet; CERT_CONTEXT const *pCert = NULL; BOOL fInitialSelectedCert = FALSE;
while (TRUE) { pCert = CertEnumCertificatesInStore(hStore, pCert); if (NULL == pCert) { break; } if ((*pCertSelect->pFilterCallback)( pCert, &fInitialSelectedCert, pCertSelect->pvCallbackData)) { if (NULL != pCertRet) { hr = CRYPT_E_EXISTS; _JumpError(hr, error, "more than one cert matches"); } pCertRet = CertDuplicateCertificateContext(pCert); if (NULL == pCertRet) { hr = CRYPT_E_NOT_FOUND; _JumpError(hr, error, "CertDuplicateCertificateContext"); } } } hr = S_OK;
error: if (NULL != pCert) { CertFreeCertificateContext(pCert); } *ppCertRet = pCertRet; return(hr); }
CERT_CONTEXT const * mySelectCertificate( IN OUT CRYPTUI_SELECTCERTIFICATE_STRUCT *pCertSelect) { HRESULT hr; CERT_CONTEXT const *pCert = NULL; DWORD i;
if (NULL == pCertSelect->rghDisplayStores || 0 == pCertSelect->cDisplayStores) { hr = CRYPT_E_NOT_FOUND; _JumpError(hr, error, "no Cert Stores"); } for (i = 0; i < pCertSelect->cDisplayStores; i++) { hr = mySelectCertificateFromStore( pCertSelect, pCertSelect->rghDisplayStores[i], &pCert); _JumpIfError(hr, error, "mySelectCertificateFromStore"); } hr = S_OK;
error: if (S_OK != hr) { if (NULL != pCert) { CertFreeCertificateContext(pCert); pCert = NULL; } SetLastError(hr); } return(pCert); }
HRESULT myGetCertificateFromPicker( OPTIONAL IN HINSTANCE hInstance, OPTIONAL IN HWND hwndParent, OPTIONAL IN int idTitle, OPTIONAL IN int idSubTitle, IN DWORD dwFlags, // CUCS_*
OPTIONAL IN WCHAR const *pwszCommonName, OPTIONAL IN DWORD cStore, OPTIONAL IN HCERTSTORE *rghStore, IN DWORD cpszObjId, OPTIONAL IN CHAR const * const *apszObjId, OUT CERT_CONTEXT const **ppCert) { HRESULT hr; HCERTSTORE *rghStoreOpened = NULL; DWORD cStoreOpened; CERTFILTERCALLBACKDATA callbackData; CRYPTUI_SELECTCERTIFICATE_STRUCT CertSelect;
ZeroMemory(&callbackData, sizeof(callbackData)); ZeroMemory(&CertSelect, sizeof(CertSelect));
// custom titles
if (NULL != hInstance) { // try to load title from resource
hr = myLoadRCString( hInstance, idTitle, const_cast<WCHAR **>(&CertSelect.szTitle)); if (S_OK != hr) { CSASSERT(NULL == CertSelect.szTitle); _PrintError(hr, "myLoadRCString(Title)"); } hr = myLoadRCString( hInstance, idSubTitle, const_cast<WCHAR **>(&CertSelect.szDisplayString)); if (S_OK != hr) { CSASSERT(NULL == CertSelect.szDisplayString); _PrintError(hr, "myLoadRCString(Title)"); } }
if (NULL == rghStore) { cStore = 0; } cStoreOpened = 0; if ((CUCS_SOURCEMASK | CUCS_TYPEMASK) & dwFlags) { CWaitCursor cwait;
hr = myOpenCertStores(dwFlags, &cStoreOpened, &rghStoreOpened); _PrintIfError(hr, "myOpenCertStores"); } CertSelect.cDisplayStores = cStore + cStoreOpened; if (0 == CertSelect.cDisplayStores) { hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); _JumpError(hr, error, "no Cert Store"); } CertSelect.rghDisplayStores = (HCERTSTORE *) LocalAlloc( LMEM_FIXED, CertSelect.cDisplayStores * sizeof(HCERTSTORE)); if (NULL == CertSelect.rghDisplayStores) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc(CertSelect.rghDisplayStores)"); }
if (0 != cStore) { CopyMemory( &CertSelect.rghDisplayStores[0], rghStore, cStore * sizeof(rghStore[0])); } if (0 != cStoreOpened) { CopyMemory( &CertSelect.rghDisplayStores[cStore], rghStoreOpened, cStoreOpened * sizeof(rghStore[0])); }
// temporary store where the callback will store links to found certs
// so it can check for duplicates
callbackData.hMemStore = CertOpenStore( CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, NULL, CERT_STORE_CREATE_NEW_FLAG, NULL); if (NULL == callbackData.hMemStore) { hr = myHLastError(); _JumpError(hr, error, "can't create memory store"); }
CertSelect.dwSize = sizeof(CertSelect); CertSelect.hwndParent = hwndParent; //CertSelect.dwFlags = 0; // single selection
//CertSelect.dwDontUseColumn = 0; // display all column
CertSelect.pFilterCallback = CertificateFilterProc; // assign callback
//CertSelect.pDisplayCallback = NULL; // use default cert view dlg
callbackData.dwFlags = dwFlags; callbackData.cpszObjId = cpszObjId; callbackData.apszObjId = apszObjId; callbackData.pwszCommonName = pwszCommonName; if (NULL != pwszCommonName) { hr = WszToMultiByteInteger( TRUE, pwszCommonName, &callbackData.cbHash, &callbackData.pbHash); _PrintIfError2(hr, "WszToMultiByteInteger", hr);
hr = myMakeSerialBstr(pwszCommonName, &callbackData.strSerialNumber); _PrintIfError2(hr, "myMakeSerialBstr", hr); } callbackData.hr = S_FALSE; CertSelect.pvCallbackData = &callbackData; // pass filter info as data
//CertSelect.cStores = 0; // no additional stores for chain verify
//CertSelect.rghStores = NULL; // no additional stores for chain verify
//CertSelect.cPropSheetPages = 0; // no custom cert view pages
//CertSelect.rgPropSheetPages = NULL; // no custom cert view pages
//CertSelect.hSelectedCertStore = NULL; // single selection
if (CUCS_SILENT & dwFlags) { *ppCert = mySelectCertificate(&CertSelect); if (NULL == *ppCert) { hr = myHLastError(); _JumpError(hr, error, "mySelectCertificate"); } } else { *ppCert = CryptUIDlgSelectCertificate(&CertSelect); }
// check for error in selection dialog
hr = callbackData.hr; if (S_FALSE == hr) { hr = CRYPT_E_NOT_FOUND; } _JumpIfError(hr, error, "CryptUIDlgSelectCertificate");
error: if (NULL != rghStoreOpened) { myCloseCertStores(cStoreOpened, rghStoreOpened); } if (NULL != callbackData.hMemStore) { CertCloseStore(callbackData.hMemStore, 0); } if (NULL != callbackData.strSerialNumber) { SysFreeString(callbackData.strSerialNumber); } if (NULL != callbackData.pbHash) { LocalFree(callbackData.pbHash); } if (NULL != CertSelect.szTitle) { LocalFree(const_cast<WCHAR *>(CertSelect.szTitle)); } if (NULL != CertSelect.szDisplayString) { LocalFree(const_cast<WCHAR *>(CertSelect.szDisplayString)); } if (NULL != CertSelect.rghDisplayStores) { LocalFree(CertSelect.rghDisplayStores); } return(hr); }
|