808 lines
24 KiB
C++
808 lines
24 KiB
C++
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
//
|
||
|
// Copyright (C) Microsoft Corporation, 1996 - 1999
|
||
|
//
|
||
|
// File: expapis.cpp
|
||
|
//
|
||
|
// Contents: Microsoft Internet Security Trust Provider
|
||
|
//
|
||
|
// Functions: FindCertsByIssuer
|
||
|
//
|
||
|
// History: 01-Jun-1997 pberkman created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
#include "global.hxx"
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
//
|
||
|
// The root of the certificate store that we manage.
|
||
|
//
|
||
|
#define HEAPALLOC(size) HeapAlloc ( GetProcessHeap(), 0, size )
|
||
|
#define HEAPFREE(data) HeapFree ( GetProcessHeap(), 0, data )
|
||
|
|
||
|
|
||
|
#define SZIE30CERTCLIENTAUTH "Software\\Microsoft\\Cryptography\\PersonalCertificates\\ClientAuth"
|
||
|
#define SZIE30TAGS "CertificateTags"
|
||
|
#define SZIE30AUXINFO "CertificateAuxiliaryInfo"
|
||
|
#define SZIE30CERTBUCKET "Certificates"
|
||
|
|
||
|
#define ALIGN_LEN(Len) ((Len + 7) & ~7)
|
||
|
|
||
|
#define IE30CONVERTEDSTORE "My"
|
||
|
|
||
|
static LPCSTR rgpszMyStore[] = {
|
||
|
"My"
|
||
|
};
|
||
|
#define NMYSTORES (sizeof(rgpszMyStore)/sizeof(rgpszMyStore[0]))
|
||
|
|
||
|
static const struct {
|
||
|
LPCSTR pszStore;
|
||
|
DWORD dwFlags;
|
||
|
} rgCaStoreInfo[] = {
|
||
|
"ROOT", CERT_SYSTEM_STORE_CURRENT_USER,
|
||
|
"CA", CERT_SYSTEM_STORE_CURRENT_USER,
|
||
|
"SPC", CERT_SYSTEM_STORE_LOCAL_MACHINE
|
||
|
};
|
||
|
#define NCASTORES (sizeof(rgCaStoreInfo)/sizeof(rgCaStoreInfo[0]))
|
||
|
|
||
|
#define MAX_CHAIN_LEN 16
|
||
|
typedef struct _CHAIN_INFO CHAIN_INFO, *PCHAIN_INFO;
|
||
|
struct _CHAIN_INFO {
|
||
|
DWORD cCert;
|
||
|
PCCERT_CONTEXT rgpCert[MAX_CHAIN_LEN];
|
||
|
DWORD cbKeyProvInfo; // aligned
|
||
|
DWORD cbCert; // aligned
|
||
|
PCHAIN_INFO pNext;
|
||
|
};
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
// AuthCert allocation and free functions
|
||
|
//--------------------------------------------------------------------------
|
||
|
static void *ACAlloc(
|
||
|
IN size_t cbBytes
|
||
|
)
|
||
|
{
|
||
|
void *pv;
|
||
|
pv = (void *)new BYTE[cbBytes];
|
||
|
if (pv == NULL)
|
||
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||
|
return pv;
|
||
|
}
|
||
|
static void ACFree(
|
||
|
IN void *pv
|
||
|
)
|
||
|
{
|
||
|
if (pv)
|
||
|
{
|
||
|
delete pv;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static HRESULT GetAndIe30ClientAuthCertificates(HCERTSTORE hStore)
|
||
|
// Check for and copy any existing certificates stored in Bob's
|
||
|
// certificate store.
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
LONG Status;
|
||
|
HKEY hKeyRoot = NULL;
|
||
|
HKEY hKeyBucket = NULL;
|
||
|
HKEY hKeyTags = NULL;
|
||
|
HKEY hKeyAux = NULL;
|
||
|
|
||
|
if (ERROR_SUCCESS != RegOpenKeyExA(
|
||
|
HKEY_CURRENT_USER,
|
||
|
SZIE30CERTCLIENTAUTH,
|
||
|
0, // dwReserved
|
||
|
KEY_READ,
|
||
|
&hKeyRoot
|
||
|
))
|
||
|
return S_OK;
|
||
|
|
||
|
// Copy any existing certificates
|
||
|
if (ERROR_SUCCESS == RegOpenKeyExA(
|
||
|
hKeyRoot,
|
||
|
SZIE30CERTBUCKET,
|
||
|
0, // dwReserved
|
||
|
KEY_READ,
|
||
|
&hKeyBucket
|
||
|
) &&
|
||
|
|
||
|
ERROR_SUCCESS == RegOpenKeyExA(
|
||
|
hKeyRoot,
|
||
|
SZIE30AUXINFO,
|
||
|
0, // dwReserved
|
||
|
KEY_READ,
|
||
|
&hKeyAux
|
||
|
) &&
|
||
|
|
||
|
ERROR_SUCCESS == RegOpenKeyExA(
|
||
|
hKeyRoot,
|
||
|
SZIE30TAGS,
|
||
|
0, // dwReserved
|
||
|
KEY_READ,
|
||
|
&hKeyTags
|
||
|
)) {
|
||
|
|
||
|
DWORD cValuesCert, cchMaxNameCert, cbMaxDataCert;
|
||
|
DWORD cValuesTag, cchMaxNameTag, cbMaxDataTag;
|
||
|
DWORD cValuesAux, cchMaxNameAux, cbMaxDataAux;
|
||
|
LPSTR szName = NULL;
|
||
|
BYTE *pbDataCert = NULL;
|
||
|
BYTE *pbDataAux = NULL;
|
||
|
BYTE *pbDataTag = NULL;
|
||
|
|
||
|
|
||
|
// see how many and how big the registry is
|
||
|
if (ERROR_SUCCESS != RegQueryInfoKey(
|
||
|
hKeyBucket,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
&cValuesCert,
|
||
|
&cchMaxNameCert,
|
||
|
&cbMaxDataCert,
|
||
|
NULL,
|
||
|
NULL
|
||
|
) ||
|
||
|
ERROR_SUCCESS != RegQueryInfoKey(
|
||
|
hKeyTags,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
&cValuesTag,
|
||
|
&cchMaxNameTag,
|
||
|
&cbMaxDataTag,
|
||
|
NULL,
|
||
|
NULL
|
||
|
) ||
|
||
|
ERROR_SUCCESS != RegQueryInfoKey(
|
||
|
hKeyAux,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
&cValuesAux,
|
||
|
&cchMaxNameAux,
|
||
|
&cbMaxDataAux,
|
||
|
NULL,
|
||
|
NULL
|
||
|
))
|
||
|
{
|
||
|
hr = SignError();
|
||
|
goto Return;
|
||
|
}
|
||
|
else {
|
||
|
// allocate the memory needed to read the reg
|
||
|
szName = (LPSTR) HEAPALLOC(cchMaxNameCert + 1);
|
||
|
pbDataCert = (BYTE *) HEAPALLOC(cbMaxDataCert);
|
||
|
pbDataTag = (BYTE *) HEAPALLOC(cbMaxDataTag);
|
||
|
pbDataAux = (BYTE *) HEAPALLOC(cbMaxDataAux);
|
||
|
|
||
|
if (NULL == szName ||
|
||
|
NULL == pbDataCert ||
|
||
|
NULL == pbDataAux ||
|
||
|
NULL == pbDataTag )
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
// enum the registry getting certs
|
||
|
for (DWORD i = 0; SUCCEEDED(hr) && i < cValuesCert; i++ ) {
|
||
|
|
||
|
DWORD dwType;
|
||
|
BYTE * pb;
|
||
|
CRYPT_KEY_PROV_INFO keyInfo;
|
||
|
DWORD cchName = cchMaxNameCert + 1;
|
||
|
DWORD cbDataCert = cbMaxDataCert;
|
||
|
DWORD cbDataTag = cbMaxDataTag;
|
||
|
DWORD cbDataAux = cbMaxDataAux;
|
||
|
|
||
|
PCCERT_CONTEXT pCertContxt = NULL;
|
||
|
|
||
|
// don't have to worry about errors, just skip
|
||
|
// sliently just be cause there is an internal
|
||
|
// error in the registry doesn't mean we should
|
||
|
// get all upset about it.
|
||
|
|
||
|
// get the cert
|
||
|
if (RegEnumValueA(
|
||
|
hKeyBucket,
|
||
|
i,
|
||
|
szName,
|
||
|
&cchName,
|
||
|
NULL,
|
||
|
&dwType,
|
||
|
pbDataCert,
|
||
|
&cbDataCert
|
||
|
) == ERROR_SUCCESS &&
|
||
|
|
||
|
dwType == REG_BINARY &&
|
||
|
|
||
|
// get the cert context
|
||
|
(pCertContxt = CertCreateCertificateContext(
|
||
|
X509_ASN_ENCODING,
|
||
|
pbDataCert,
|
||
|
cbDataCert)) != NULL &&
|
||
|
|
||
|
// get the tag
|
||
|
RegQueryValueExA(
|
||
|
hKeyTags,
|
||
|
szName,
|
||
|
NULL,
|
||
|
&dwType,
|
||
|
pbDataTag,
|
||
|
&cbDataTag) == ERROR_SUCCESS &&
|
||
|
|
||
|
// get the aux info
|
||
|
RegQueryValueExA(
|
||
|
hKeyAux,
|
||
|
(LPTSTR) pbDataTag,
|
||
|
NULL,
|
||
|
&dwType,
|
||
|
pbDataAux,
|
||
|
&cbDataAux) == ERROR_SUCCESS ) {
|
||
|
|
||
|
// aux info is
|
||
|
// wszPurpose
|
||
|
// wszProvider
|
||
|
// wszKeySet
|
||
|
// wszFilename
|
||
|
// wszCredentials
|
||
|
// dwProviderType
|
||
|
// dwKeySpec
|
||
|
|
||
|
pb = pbDataAux;
|
||
|
memset(&keyInfo, 0, sizeof(CRYPT_KEY_PROV_INFO));
|
||
|
|
||
|
// skip purpose, should be client auth
|
||
|
pb += (lstrlenW((LPWSTR) pb) + 1) * sizeof(WCHAR);
|
||
|
|
||
|
// get the provider
|
||
|
keyInfo.pwszProvName = (LPWSTR) pb;
|
||
|
pb += (lstrlenW((LPWSTR) pb) + 1) * sizeof(WCHAR);
|
||
|
|
||
|
// get the container name
|
||
|
keyInfo.pwszContainerName = (LPWSTR) pb;
|
||
|
pb += (lstrlenW((LPWSTR) pb) + 1) * sizeof(WCHAR);
|
||
|
|
||
|
// skip filename, should be '\0'
|
||
|
pb += (lstrlenW((LPWSTR) pb) + 1) * sizeof(WCHAR);
|
||
|
|
||
|
// skip credential, don't really know what it is?
|
||
|
pb += (lstrlenW((LPWSTR) pb) + 1) * sizeof(WCHAR);
|
||
|
|
||
|
// get the provider type
|
||
|
keyInfo.dwProvType = *((DWORD *) pb);
|
||
|
pb += sizeof(DWORD);
|
||
|
|
||
|
// get the key spec
|
||
|
keyInfo.dwKeySpec = *((DWORD *) pb);
|
||
|
|
||
|
// add the property to the certificate
|
||
|
if( !CertSetCertificateContextProperty(
|
||
|
pCertContxt,
|
||
|
CERT_KEY_PROV_INFO_PROP_ID,
|
||
|
0,
|
||
|
&keyInfo) ||
|
||
|
|
||
|
!CertAddCertificateContextToStore(
|
||
|
hStore,
|
||
|
pCertContxt,
|
||
|
CERT_STORE_ADD_USE_EXISTING,
|
||
|
NULL // ppStoreContext
|
||
|
)) {
|
||
|
|
||
|
MessageBox(
|
||
|
NULL,
|
||
|
"Copy Certificate Failed",
|
||
|
NULL,
|
||
|
MB_OK);
|
||
|
|
||
|
|
||
|
hr = SignError();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(pCertContxt != NULL)
|
||
|
CertFreeCertificateContext(pCertContxt);
|
||
|
}
|
||
|
|
||
|
if (szName)
|
||
|
HEAPFREE(szName);
|
||
|
if (pbDataCert)
|
||
|
HEAPFREE(pbDataCert);
|
||
|
if(pbDataAux)
|
||
|
HEAPFREE(pbDataAux);
|
||
|
if(pbDataTag)
|
||
|
HEAPFREE(pbDataTag);
|
||
|
}
|
||
|
|
||
|
Return:
|
||
|
|
||
|
if(hKeyRoot != NULL)
|
||
|
RegCloseKey(hKeyRoot);
|
||
|
if(hKeyBucket != NULL)
|
||
|
RegCloseKey(hKeyBucket);
|
||
|
if(hKeyTags != NULL)
|
||
|
RegCloseKey(hKeyTags);
|
||
|
if(hKeyAux != NULL)
|
||
|
RegCloseKey(hKeyAux);
|
||
|
if (FAILED(hr))
|
||
|
return hr;
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Return List is Null terminated
|
||
|
static HCERTSTORE * GetMyStoreList()
|
||
|
{
|
||
|
int i;
|
||
|
HCERTSTORE *phStoreList;
|
||
|
if (NULL == (phStoreList = (HCERTSTORE *) ACAlloc(
|
||
|
sizeof(HCERTSTORE) * (NMYSTORES + 1))))
|
||
|
return NULL;
|
||
|
memset(phStoreList, 0, sizeof(HCERTSTORE) * (NMYSTORES + 1));
|
||
|
for (i = 0; i < NMYSTORES; i++) {
|
||
|
if (NULL == (phStoreList[i] = CertOpenSystemStore(
|
||
|
NULL,
|
||
|
rgpszMyStore[i])))
|
||
|
goto ErrorReturn;
|
||
|
}
|
||
|
goto CommonReturn;
|
||
|
|
||
|
ErrorReturn:
|
||
|
for (i = 0; i < NMYSTORES; i++) {
|
||
|
if (phStoreList[i])
|
||
|
CertCloseStore(phStoreList[i], 0);
|
||
|
}
|
||
|
|
||
|
ACFree(phStoreList);
|
||
|
phStoreList = NULL;
|
||
|
|
||
|
CommonReturn:
|
||
|
return phStoreList;
|
||
|
}
|
||
|
|
||
|
static HCERTSTORE * GetCaStoreList()
|
||
|
{
|
||
|
int i;
|
||
|
int cStore;
|
||
|
HCERTSTORE *phStoreList;
|
||
|
if (NULL == (phStoreList = (HCERTSTORE *) ACAlloc(
|
||
|
sizeof(HCERTSTORE) * (NCASTORES + 1))))
|
||
|
return NULL;
|
||
|
memset(phStoreList, 0, sizeof(HCERTSTORE) * (NCASTORES + 1));
|
||
|
|
||
|
cStore = 0;
|
||
|
for (i = 0; i < NCASTORES; i++) {
|
||
|
DWORD dwFlags;
|
||
|
|
||
|
dwFlags = rgCaStoreInfo[i].dwFlags | CERT_STORE_READONLY_FLAG;
|
||
|
if (phStoreList[cStore] = CertOpenStore(
|
||
|
CERT_STORE_PROV_SYSTEM_A,
|
||
|
0, // dwEncodingType
|
||
|
0, // hCryptProv
|
||
|
dwFlags,
|
||
|
(const void *) rgCaStoreInfo[i].pszStore
|
||
|
))
|
||
|
cStore++;
|
||
|
}
|
||
|
return phStoreList;
|
||
|
}
|
||
|
|
||
|
// Find first Issuer match. Don't verify anything. Returns TRUE if an
|
||
|
// issuer was found. For a self-signed issuer returns TRUE with *ppIssuer
|
||
|
// set to NULL.
|
||
|
static BOOL GetIssuer(
|
||
|
IN PCCERT_CONTEXT pSubject,
|
||
|
IN HCERTSTORE *phCaStoreList,
|
||
|
OUT PCCERT_CONTEXT *ppIssuer
|
||
|
)
|
||
|
{
|
||
|
BOOL fResult = FALSE;
|
||
|
PCCERT_CONTEXT pIssuer = NULL;
|
||
|
HCERTSTORE hStore;
|
||
|
while (hStore = *phCaStoreList++) {
|
||
|
DWORD dwFlags = 0;
|
||
|
pIssuer = CertGetIssuerCertificateFromStore(
|
||
|
hStore,
|
||
|
pSubject,
|
||
|
NULL, // pPrevIssuer,
|
||
|
&dwFlags
|
||
|
);
|
||
|
if (pIssuer || GetLastError() == CRYPT_E_SELF_SIGNED) {
|
||
|
fResult = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*ppIssuer = pIssuer;
|
||
|
return fResult;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
// If issuer name matches any cert in the chain, return allocated
|
||
|
// chain info. Otherwise, return NULL.
|
||
|
//
|
||
|
// If pbEncodedIssuerName == NULL || cbEncodedIssuerName = 0, match any
|
||
|
// issuer.
|
||
|
//--------------------------------------------------------------------------
|
||
|
static PCHAIN_INFO CreateChainInfo(
|
||
|
IN PCCERT_CONTEXT pCert,
|
||
|
IN BYTE *pbEncodedIssuerName,
|
||
|
IN DWORD cbEncodedIssuerName,
|
||
|
IN HCERTSTORE *phCaStoreList,
|
||
|
IN HCERTSTORE *phMyStoreList
|
||
|
)
|
||
|
{
|
||
|
BOOL fIssuerMatch = FALSE;
|
||
|
DWORD cCert = 1;
|
||
|
DWORD cbCert = 0;
|
||
|
PCHAIN_INFO pChainInfo;
|
||
|
if (NULL == (pChainInfo = (PCHAIN_INFO) ACAlloc(sizeof(CHAIN_INFO))))
|
||
|
return NULL;
|
||
|
memset(pChainInfo, 0, sizeof(CHAIN_INFO));
|
||
|
pChainInfo->rgpCert[0] = CertDuplicateCertificateContext(pCert);
|
||
|
|
||
|
if (pbEncodedIssuerName == NULL)
|
||
|
cbEncodedIssuerName = 0;
|
||
|
|
||
|
while (pCert) {
|
||
|
PCCERT_CONTEXT pIssuer;
|
||
|
cbCert += ALIGN_LEN(pCert->cbCertEncoded);
|
||
|
if (!fIssuerMatch) {
|
||
|
if (cbEncodedIssuerName == 0 ||
|
||
|
(cbEncodedIssuerName == pCert->pCertInfo->Issuer.cbData &&
|
||
|
memcmp(pbEncodedIssuerName,
|
||
|
pCert->pCertInfo->Issuer.pbData,
|
||
|
cbEncodedIssuerName) == 0))
|
||
|
fIssuerMatch = TRUE;
|
||
|
}
|
||
|
if (GetIssuer(pCert, phCaStoreList, &pIssuer) ||
|
||
|
GetIssuer(pCert, phMyStoreList, &pIssuer)) {
|
||
|
pCert = pIssuer;
|
||
|
if (pCert) {
|
||
|
assert (cCert < MAX_CHAIN_LEN);
|
||
|
if (cCert < MAX_CHAIN_LEN)
|
||
|
pChainInfo->rgpCert[cCert++] = pCert;
|
||
|
else {
|
||
|
CertFreeCertificateContext(pCert);
|
||
|
pCert = NULL;
|
||
|
}
|
||
|
}
|
||
|
// else
|
||
|
// Self-signed
|
||
|
}
|
||
|
else
|
||
|
pCert = NULL;
|
||
|
}
|
||
|
|
||
|
if (fIssuerMatch) {
|
||
|
pChainInfo->cCert = cCert;
|
||
|
pChainInfo->cbCert = cbCert;
|
||
|
return pChainInfo;
|
||
|
} else {
|
||
|
while (cCert--)
|
||
|
CertFreeCertificateContext(pChainInfo->rgpCert[cCert]);
|
||
|
ACFree(pChainInfo);
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
// Check if the certificate has key provider information.
|
||
|
// If dwKeySpec != 0, also check that the provider's public key matches the
|
||
|
// public key in the certificate.
|
||
|
//--------------------------------------------------------------------------
|
||
|
static BOOL CheckKeyProvInfo(
|
||
|
IN PCCERT_CONTEXT pCert,
|
||
|
IN DWORD dwKeySpec,
|
||
|
OUT DWORD *pcbKeyProvInfo
|
||
|
)
|
||
|
{
|
||
|
BOOL fResult = FALSE;
|
||
|
HCRYPTPROV hCryptProv = 0;
|
||
|
PCRYPT_KEY_PROV_INFO pKeyProvInfo = NULL;
|
||
|
DWORD cbKeyProvInfo;
|
||
|
DWORD cbData;
|
||
|
PCERT_PUBLIC_KEY_INFO pPubKeyInfo = NULL;
|
||
|
DWORD cbPubKeyInfo;
|
||
|
|
||
|
cbKeyProvInfo = 0;
|
||
|
CertGetCertificateContextProperty(
|
||
|
pCert,
|
||
|
CERT_KEY_PROV_INFO_PROP_ID,
|
||
|
NULL, // pvData
|
||
|
&cbKeyProvInfo
|
||
|
);
|
||
|
if (cbKeyProvInfo) {
|
||
|
if (dwKeySpec == 0)
|
||
|
fResult = TRUE;
|
||
|
else {
|
||
|
DWORD dwIdx;
|
||
|
if (NULL == (pKeyProvInfo = (PCRYPT_KEY_PROV_INFO) ACAlloc(cbKeyProvInfo)))
|
||
|
goto CommonReturn;
|
||
|
if (!CertGetCertificateContextProperty(
|
||
|
pCert,
|
||
|
CERT_KEY_PROV_INFO_PROP_ID,
|
||
|
pKeyProvInfo,
|
||
|
&cbKeyProvInfo
|
||
|
)) goto CommonReturn;
|
||
|
if (!CryptAcquireContextU(
|
||
|
&hCryptProv,
|
||
|
pKeyProvInfo->pwszContainerName,
|
||
|
pKeyProvInfo->pwszProvName,
|
||
|
pKeyProvInfo->dwProvType,
|
||
|
pKeyProvInfo->dwFlags & ~CERT_SET_KEY_PROV_HANDLE_PROP_ID
|
||
|
)) {
|
||
|
hCryptProv = NULL;
|
||
|
goto CommonReturn;
|
||
|
}
|
||
|
for (dwIdx = 0; dwIdx < pKeyProvInfo->cProvParam; dwIdx++) {
|
||
|
PCRYPT_KEY_PROV_PARAM pKeyProvParam =
|
||
|
&pKeyProvInfo->rgProvParam[dwIdx];
|
||
|
if (!CryptSetProvParam(
|
||
|
hCryptProv,
|
||
|
pKeyProvParam->dwParam,
|
||
|
pKeyProvParam->pbData,
|
||
|
pKeyProvParam->dwFlags
|
||
|
)) goto CommonReturn;
|
||
|
}
|
||
|
|
||
|
// Get public key to compare certificate with
|
||
|
cbPubKeyInfo = 0;
|
||
|
CryptExportPublicKeyInfo(
|
||
|
hCryptProv,
|
||
|
dwKeySpec,
|
||
|
pCert->dwCertEncodingType,
|
||
|
NULL, // pPubKeyInfo
|
||
|
&cbPubKeyInfo
|
||
|
);
|
||
|
if (cbPubKeyInfo == 0) goto CommonReturn;
|
||
|
if (NULL == (pPubKeyInfo = (PCERT_PUBLIC_KEY_INFO) ACAlloc(
|
||
|
cbPubKeyInfo)))
|
||
|
goto CommonReturn;
|
||
|
if (!CryptExportPublicKeyInfo(
|
||
|
hCryptProv,
|
||
|
dwKeySpec,
|
||
|
pCert->dwCertEncodingType,
|
||
|
pPubKeyInfo,
|
||
|
&cbPubKeyInfo
|
||
|
)) goto CommonReturn;
|
||
|
fResult = CertComparePublicKeyInfo(
|
||
|
pCert->dwCertEncodingType,
|
||
|
&pCert->pCertInfo->SubjectPublicKeyInfo,
|
||
|
pPubKeyInfo);
|
||
|
}
|
||
|
}
|
||
|
CommonReturn:
|
||
|
if (hCryptProv) {
|
||
|
DWORD dwErr = GetLastError();
|
||
|
CryptReleaseContext(hCryptProv, 0);
|
||
|
SetLastError(dwErr);
|
||
|
}
|
||
|
if (pKeyProvInfo)
|
||
|
ACFree(pKeyProvInfo);
|
||
|
if (pPubKeyInfo)
|
||
|
ACFree(pPubKeyInfo);
|
||
|
*pcbKeyProvInfo = cbKeyProvInfo;
|
||
|
return fResult;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
// Find all certificate chains tying the given issuer name to any certificate
|
||
|
// that the current user has a private key for.
|
||
|
//
|
||
|
// If pbEncodedIssuerName == NULL || cbEncodedIssuerName = 0, match any
|
||
|
// issuer.
|
||
|
//--------------------------------------------------------------------------
|
||
|
HRESULT
|
||
|
WINAPI
|
||
|
FindCertsByIssuer(
|
||
|
OUT PCERT_CHAIN pCertChains,
|
||
|
IN OUT DWORD *pcbCertChains,
|
||
|
OUT DWORD *pcCertChains, // count of certificates chains returned
|
||
|
IN BYTE* pbEncodedIssuerName, // DER encoded issuer name
|
||
|
IN DWORD cbEncodedIssuerName, // count in bytes of encoded issuer name
|
||
|
IN LPCWSTR pwszPurpose, // "ClientAuth" or "CodeSigning"
|
||
|
IN DWORD dwKeySpec // only return signers supporting this
|
||
|
// keyspec
|
||
|
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
HCERTSTORE *phMyStoreList = NULL;
|
||
|
HCERTSTORE *phCaStoreList = NULL;
|
||
|
HCERTSTORE *phStore;
|
||
|
HCERTSTORE hStore;
|
||
|
|
||
|
DWORD cChain = 0;
|
||
|
DWORD cbChain;
|
||
|
DWORD cTotalCert = 0;
|
||
|
PCHAIN_INFO pChainInfoHead = NULL;
|
||
|
LONG cbExtra = 0;
|
||
|
|
||
|
// get the certs out of the IE30 tree and put it in ours
|
||
|
// open the IE30 store
|
||
|
|
||
|
if (NULL != (hStore = CertOpenSystemStore(
|
||
|
NULL,
|
||
|
IE30CONVERTEDSTORE))) {
|
||
|
|
||
|
// don't care about errors, and we don't
|
||
|
// want to delete the old store just yet.
|
||
|
GetAndIe30ClientAuthCertificates(hStore);
|
||
|
CertCloseStore(hStore, 0);
|
||
|
}
|
||
|
|
||
|
|
||
|
// copy the IE30 certs
|
||
|
|
||
|
|
||
|
if (NULL == (phMyStoreList = GetMyStoreList()))
|
||
|
goto ErrorReturn;
|
||
|
if (NULL == (phCaStoreList = GetCaStoreList()))
|
||
|
goto ErrorReturn;
|
||
|
|
||
|
// Iterate through all "My" cert stores to find certificates having a
|
||
|
// CRYPT_KEY_PROV_INFO property
|
||
|
phStore = phMyStoreList;
|
||
|
while (hStore = *phStore++) {
|
||
|
PCCERT_CONTEXT pCert = NULL;
|
||
|
while (pCert = CertEnumCertificatesInStore(hStore, pCert)) {
|
||
|
DWORD cbKeyProvInfo;
|
||
|
if (CheckKeyProvInfo(pCert, dwKeySpec, &cbKeyProvInfo)) {
|
||
|
// Create a cert chain and check for an issuer name match
|
||
|
// of any cert in the chain.
|
||
|
PCHAIN_INFO pChainInfo;
|
||
|
if (pChainInfo = CreateChainInfo(
|
||
|
pCert,
|
||
|
pbEncodedIssuerName,
|
||
|
cbEncodedIssuerName,
|
||
|
phCaStoreList,
|
||
|
phMyStoreList
|
||
|
)) {
|
||
|
// Add to list of chains
|
||
|
pChainInfo->pNext = pChainInfoHead;
|
||
|
pChainInfoHead = pChainInfo;
|
||
|
|
||
|
// Update bytes needed for KeyProvInfo
|
||
|
pChainInfo->cbKeyProvInfo = ALIGN_LEN(cbKeyProvInfo);
|
||
|
|
||
|
// Update totals
|
||
|
cbExtra += pChainInfo->cbKeyProvInfo + pChainInfo->cbCert;
|
||
|
cChain++;
|
||
|
cTotalCert += pChainInfo->cCert;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
cbChain = sizeof(CERT_CHAIN) * cChain +
|
||
|
sizeof(CERT_BLOB) * cTotalCert + cbExtra;
|
||
|
|
||
|
{
|
||
|
// Check and update output lengths and counts
|
||
|
DWORD cbIn;
|
||
|
|
||
|
if (cChain == 0) {
|
||
|
hr = CRYPT_E_NOT_FOUND;
|
||
|
goto HrError;
|
||
|
}
|
||
|
if (pCertChains == NULL)
|
||
|
*pcbCertChains = 0;
|
||
|
cbIn = *pcbCertChains;
|
||
|
*pcCertChains = cChain;
|
||
|
*pcbCertChains = cbChain;
|
||
|
|
||
|
if (cbIn == 0) {
|
||
|
hr = S_OK;
|
||
|
goto CommonReturn;
|
||
|
} else if (cbIn < cbChain) {
|
||
|
hr = HRESULT_FROM_WIN32(ERROR_BAD_LENGTH);
|
||
|
goto CommonReturn;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
{
|
||
|
// Copy cert chains to output
|
||
|
|
||
|
PCERT_CHAIN pOutChain;
|
||
|
PCERT_BLOB pCertBlob;
|
||
|
BYTE *pbExtra;
|
||
|
PCHAIN_INFO pChainInfo;
|
||
|
|
||
|
pOutChain = pCertChains;
|
||
|
pCertBlob = (PCERT_BLOB) (((BYTE *) pOutChain) +
|
||
|
sizeof(CERT_CHAIN) * cChain);
|
||
|
pbExtra = ((BYTE *) pCertBlob) + sizeof(CERT_BLOB) * cTotalCert;
|
||
|
pChainInfo = pChainInfoHead;
|
||
|
for ( ; pChainInfo != NULL;
|
||
|
pChainInfo = pChainInfo->pNext, pOutChain++) {
|
||
|
DWORD cb;
|
||
|
DWORD cCert = pChainInfo->cCert;
|
||
|
PCCERT_CONTEXT *ppCert = pChainInfo->rgpCert;
|
||
|
|
||
|
pOutChain->cCerts = cCert;
|
||
|
pOutChain->certs = pCertBlob;
|
||
|
cb = pChainInfo->cbKeyProvInfo;
|
||
|
cbExtra -= cb;
|
||
|
assert(cbExtra >= 0);
|
||
|
if (cbExtra < 0) goto UnexpectedError;
|
||
|
if (!CertGetCertificateContextProperty(
|
||
|
*ppCert,
|
||
|
CERT_KEY_PROV_INFO_PROP_ID,
|
||
|
pbExtra,
|
||
|
&cb
|
||
|
))
|
||
|
goto UnexpectedError;
|
||
|
pOutChain->keyLocatorInfo = * ((PCRYPT_KEY_PROV_INFO) pbExtra);
|
||
|
pbExtra += pChainInfo->cbKeyProvInfo;
|
||
|
|
||
|
for ( ; cCert > 0; cCert--, ppCert++, pCertBlob++) {
|
||
|
cb = (*ppCert)->cbCertEncoded;
|
||
|
cbExtra -= ALIGN_LEN(cb);
|
||
|
assert(cbExtra >= 0);
|
||
|
if (cbExtra < 0) goto UnexpectedError;
|
||
|
|
||
|
pCertBlob->cbData = cb;
|
||
|
pCertBlob->pbData = pbExtra;
|
||
|
memcpy(pbExtra, (*ppCert)->pbCertEncoded, cb);
|
||
|
pbExtra += ALIGN_LEN(cb);
|
||
|
}
|
||
|
}
|
||
|
assert(cbExtra == 0);
|
||
|
assert(pCertBlob == (PCERT_BLOB) ((BYTE *) pCertChains +
|
||
|
sizeof(CERT_CHAIN) * cChain +
|
||
|
sizeof(CERT_BLOB) * cTotalCert));
|
||
|
}
|
||
|
|
||
|
hr = S_OK;
|
||
|
goto CommonReturn;
|
||
|
|
||
|
UnexpectedError:
|
||
|
hr = E_UNEXPECTED;
|
||
|
goto HrError;
|
||
|
ErrorReturn:
|
||
|
hr = SignError();
|
||
|
HrError:
|
||
|
*pcbCertChains = 0;
|
||
|
*pcCertChains = 0;
|
||
|
CommonReturn:
|
||
|
while (pChainInfoHead) {
|
||
|
PCHAIN_INFO pChainInfo = pChainInfoHead;
|
||
|
DWORD cCert = pChainInfo->cCert;
|
||
|
while (cCert--)
|
||
|
CertFreeCertificateContext(pChainInfo->rgpCert[cCert]);
|
||
|
pChainInfoHead = pChainInfo->pNext;
|
||
|
ACFree(pChainInfo);
|
||
|
}
|
||
|
|
||
|
if (phMyStoreList) {
|
||
|
phStore = phMyStoreList;
|
||
|
while (hStore = *phStore++)
|
||
|
CertCloseStore(hStore, 0);
|
||
|
ACFree(phMyStoreList);
|
||
|
}
|
||
|
if (phCaStoreList) {
|
||
|
phStore = phCaStoreList;
|
||
|
while (hStore = *phStore++)
|
||
|
CertCloseStore(hStore, 0);
|
||
|
ACFree(phCaStoreList);
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|