//+-------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1996 - 1999 // // File: cryptpick.cpp // // Contents: Cert Server wrapper routines // //--------------------------------------------------------------------------- #include #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(&CertSelect.szTitle)); if (S_OK != hr) { CSASSERT(NULL == CertSelect.szTitle); _PrintError(hr, "myLoadRCString(Title)"); } hr = myLoadRCString( hInstance, idSubTitle, const_cast(&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(CertSelect.szTitle)); } if (NULL != CertSelect.szDisplayString) { LocalFree(const_cast(CertSelect.szDisplayString)); } if (NULL != CertSelect.rghDisplayStores) { LocalFree(CertSelect.rghDisplayStores); } return(hr); }