windows-nt/Source/XPSP1/NT/ds/security/cryptoapi/pkitrust/initpki/mvcerts.cpp
2020-09-26 16:20:57 +08:00

649 lines
24 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1997 - 1999
//
// File: mvcerts.cpp
//
//--------------------------------------------------------------------------
#include "global.hxx"
static HRESULT HError ()
{
DWORD dw = GetLastError ();
HRESULT hr;
if ( dw <= (DWORD) 0xFFFF )
hr = HRESULT_FROM_WIN32 ( dw );
else
hr = dw;
if ( ! FAILED ( hr ) )
{
// somebody failed a call without properly setting an error condition
hr = E_UNEXPECTED;
}
return hr;
}
//
// The root of the certificate store that we manage.
//
#define SZIE30CERTROOT "Software\\Microsoft\\Cryptography\\CertificateStore"
#define SZIE30CERTPARENT "Software\\Microsoft\\Cryptography"
#define SZIE30CERTSTORE "CertificateStore"
#define SZIE30CERTBUCKET "Certificates"
#define SZIE30INDEXISSUER "IndexByIssuerName"
#define SZIE30INDEXISSUERSER "IndexByIssuerNameAndSerialNumber"
#define SZIE30INDEXSUBJECT "IndexBySubjectName"
#define SZIE30INDEXKEY "IndexBySubjectPublicKey"
#define SZIE30CERTCLIENTAUTH "Software\\Microsoft\\Cryptography\\PersonalCertificates\\ClientAuth"
#define SZIE30TAGS "CertificateTags"
#define SZIE30AUXINFO "CertificateAuxiliaryInfo"
#define IE30CONVERTEDSTORE "My"
HRESULT PurgeDuplicateCertificate(HCERTSTORE hStore, PCCERT_CONTEXT pCert)
{
HRESULT hr = S_OK;
PCCERT_CONTEXT pExistingCert = NULL;
BOOL fRes = FALSE;
// Check for existing certificates.
pExistingCert = CertGetSubjectCertificateFromStore(hStore,
X509_ASN_ENCODING,
pCert->pCertInfo);
if (pExistingCert)
{
if (CompareFileTime(&pExistingCert->pCertInfo->NotBefore,
&pCert->pCertInfo->NotBefore) <= 0) {
fRes = CertDeleteCertificateFromStore(pExistingCert); // Delete existing
pExistingCert = NULL;
if (!(fRes))
{
goto CertDupError;
}
}
else
{
hr = S_FALSE;
}
}
CommonReturn:
if (pExistingCert)
{
CertFreeCertificateContext(pExistingCert);
}
return hr;
ErrorReturn:
SetLastError((DWORD)hr);
goto CommonReturn;
SET_HRESULT_EX(DBG_SS, CertDupError, GetLastError());
}
HRESULT MoveSpcCerts(BOOL fDelete, HCERTSTORE hStore)
// Check for and copy any existing certificates stored in Bob's
// certificate store. Also, delete Bob's certificate keys from the registry.
{
HRESULT hr = S_OK;
LONG Status;
HKEY hKeyRoot = NULL;
HKEY hKeyParent = NULL;
HKEY hKeyBucket = NULL;
LPSTR pszName = NULL;
BYTE *pbData = NULL;
PKITRY {
if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE,
SZIE30CERTROOT,
0, // dwReserved
KEY_READ,
&hKeyRoot))
PKITHROW(S_OK);
// Copy any existing certificates
if (ERROR_SUCCESS != RegOpenKeyEx(hKeyRoot,
SZIE30CERTBUCKET,
0, // dwReserved
KEY_READ,
&hKeyBucket))
PKITHROW(HError());
DWORD cValues, cchMaxName, cbMaxData;
// see how many and how big the registry is
if (ERROR_SUCCESS != RegQueryInfoKey(hKeyBucket,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
&cValues,
&cchMaxName,
&cbMaxData,
NULL,
NULL
))
PKITHROW(HError());
// allocate the memory needed to read the reg
pszName = (LPSTR) LocalAlloc(LMEM_ZEROINIT, cchMaxName + 1);
pbData = (BYTE *) LocalAlloc(LMEM_ZEROINIT, cbMaxData);
if (NULL == pszName || NULL == pbData)
PKITHROW(E_OUTOFMEMORY);
// enum the registry getting certs
for (DWORD i = 0; i < cValues; i++ ) {
DWORD dwType;
DWORD cchName = cchMaxName + 1;
DWORD cbData = cbMaxData;
PCCERT_CONTEXT pCert = NULL;
if (ERROR_SUCCESS != RegEnumValueA(hKeyBucket,
i,
pszName,
&cchName,
NULL,
&dwType,
pbData,
&cbData)) {
if (SUCCEEDED(hr))
hr = HError();
} else if (cchName) {
if((pCert = CertCreateCertificateContext(X509_ASN_ENCODING,
pbData,
cbData)) == NULL) {
hr = HError();
}
else {
HRESULT hr2 = PurgeDuplicateCertificate(hStore, pCert);
if(hr2 == S_OK) {
if(!CertAddCertificateContextToStore(hStore,
pCert,
CERT_STORE_ADD_USE_EXISTING,
NULL // ppStoreContext
)) {
/*MessageBox(NULL, "Copy Certificate Failed", NULL,
MB_OK);*/
if(SUCCEEDED(hr))
hr = HError();
}
}
}
if(pCert)
CertFreeCertificateContext(pCert);
/*
if (!CertAddEncodedCertificateToStore(hStore,
X509_ASN_ENCODING,
pbData,
cbData,
CERT_STORE_ADD_USE_EXISTING,
NULL)) { // ppCertContext
MessageBox(NULL, "Copy Certificate Failed", NULL,
MB_OK);
if (SUCCEEDED(hr))
hr = HError();
*/
}
}
}
PKICATCH(err) {
hr = err.pkiError;
} PKIEND;
if (pszName)
LocalFree(pszName);
if (pbData)
LocalFree(pbData);
if (hKeyBucket)
RegCloseKey(hKeyBucket);
if (hKeyRoot)
RegCloseKey(hKeyRoot);
if(SUCCEEDED(hr) && fDelete) {
Status = ERROR_SUCCESS;
while (Status == ERROR_SUCCESS) {
// Re-open registry with write/delete access
if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE,
SZIE30CERTROOT,
0, // dwReserved
KEY_ALL_ACCESS,
&hKeyRoot))
return HError();
// Delete all of the store's subkeys including the certificates
CHAR szSubKey[MAX_PATH+1];
if (ERROR_SUCCESS == (Status = RegEnumKey(hKeyRoot,
0, // iSubKey
szSubKey,
MAX_PATH + 1
)))
Status = RegDeleteKey(hKeyRoot, szSubKey);
RegCloseKey(hKeyRoot);
}
// Open the store's parent registry so we can delete the store
if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE,
SZIE30CERTPARENT,
0, // dwReserved
KEY_ALL_ACCESS,
&hKeyParent))
return HError();
if (ERROR_SUCCESS != RegDeleteKey(hKeyParent, SZIE30CERTSTORE))
hr = HError();
RegCloseKey(hKeyParent);
}
return hr;
}
BOOL TestIE30Store(HKEY hRegRoot, LPCSTR psLoc)
{
HRESULT hr = S_FALSE;
HKEY hKeyRoot = NULL;
HKEY hKeyBucket = NULL;
char pbValueName[MAX_PATH];
DWORD cbValueName = MAX_PATH;
DWORD cSubKeys;
DWORD dwType;
// __asm int 3
PKITRY {
if (ERROR_SUCCESS != RegOpenKeyExA(hRegRoot,
psLoc,
0, // dwReserved
KEY_READ,
&hKeyRoot))
PKITHROW(S_FALSE);
if (ERROR_SUCCESS != RegOpenKeyExA(hKeyRoot,
SZIE30CERTBUCKET,
0, // dwReserved
KEY_READ,
&hKeyBucket))
PKITHROW(S_FALSE);
DWORD cValues, cchMaxName, cbMaxData;
// see how many and how big the registry is
if (ERROR_SUCCESS != RegQueryInfoKey(hKeyBucket,
NULL, // lpszClasss
NULL, // lpcchClass
NULL, // lpdwReserved
&cSubKeys,
NULL, // lpcchMaxSubkey
NULL, // lpcchMaxClass
&cValues,
&cchMaxName,
&cbMaxData,
NULL,
NULL
))
PKITHROW(HError());
if(cchMaxName < 40 && cSubKeys == 0)
hr = S_OK;
}
PKICATCH(err) {
hr = err.pkiError;
} PKIEND
if(hKeyRoot != NULL)
RegCloseKey(hKeyRoot);
if(hKeyBucket != NULL)
RegCloseKey(hKeyBucket);
return hr == S_OK ? TRUE : FALSE;
}
HRESULT TransferIE30Certificates(HKEY hRegRoot, LPCSTR psLoc, HCERTSTORE hStore, BOOL fDelete)
// 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(hRegRoot,
psLoc,
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 *pbLoadCert = NULL;
BYTE *pbFixedCert = 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 = HError();
else {
// allocate the memory needed to read the reg
szName = (LPSTR) LocalAlloc(LMEM_ZEROINIT, cchMaxNameCert + 1);
pbDataCert = (BYTE *) LocalAlloc(LMEM_ZEROINIT, cbMaxDataCert);
pbDataTag = (BYTE *) LocalAlloc(LMEM_ZEROINIT, cbMaxDataTag);
pbDataAux = (BYTE *) LocalAlloc(LMEM_ZEROINIT, 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 cbLoadCert = 0;
DWORD cbFixedCert = 0;
DWORD cbDataTag = cbMaxDataTag;
DWORD cbDataAux = cbMaxDataAux;
PCCERT_CONTEXT pCertContxt = NULL;
HRESULT status = S_OK;
// 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) {
if(Fix7FCert(cbDataCert,
pbDataCert,
&cbFixedCert,
&pbFixedCert) &&
cbFixedCert != 0) {
pbLoadCert = pbFixedCert;
cbLoadCert = cbFixedCert;
}
else {
pbLoadCert = pbDataCert;
cbLoadCert = cbDataCert;
}
// get the cert context
if((pCertContxt = CertCreateCertificateContext(X509_ASN_ENCODING,
pbLoadCert,
cbLoadCert)) != NULL) {
// See if it has a tag and aux info.
// get the tag
if(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))
status = S_FALSE;
}
if(status == S_OK) {
HRESULT hr2 = PurgeDuplicateCertificate(hStore, pCertContxt);
if(hr2 == S_OK) {
if(!CertAddCertificateContextToStore(hStore,
pCertContxt,
CERT_STORE_ADD_USE_EXISTING,
NULL // ppStoreContext
)) {
/*MessageBox(NULL,
"Copy Certificate Failed",
NULL,
MB_OK);*/
hr = HError();
}
}
}
}
}
if(pCertContxt != NULL)
CertFreeCertificateContext(pCertContxt);
if(pbFixedCert) {
LocalFree(pbFixedCert);
pbFixedCert = NULL;
}
}
if (szName)
LocalFree(szName);
if (pbDataCert)
LocalFree(pbDataCert);
if(pbDataAux)
LocalFree(pbDataAux);
if(pbDataTag)
LocalFree(pbDataTag);
}
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;
if(SUCCEEDED(hr) && fDelete) {
// Re-open registry with write/delete access
if (ERROR_SUCCESS != RegOpenKeyEx(hRegRoot,
psLoc,
0, // dwRes erved
KEY_ALL_ACCESS,
&hKeyRoot))
return HError();
Status = RegDeleteKey(hKeyRoot, SZIE30CERTBUCKET);
Status = RegDeleteKey(hKeyRoot, SZIE30INDEXISSUER);
Status = RegDeleteKey(hKeyRoot, SZIE30INDEXISSUERSER);
Status = RegDeleteKey(hKeyRoot, SZIE30INDEXSUBJECT);
Status = RegDeleteKey(hKeyRoot, SZIE30INDEXKEY);
Status = RegDeleteKey(hKeyRoot, SZIE30TAGS);
RegCloseKey(hKeyRoot);
}
return hr;
}
HRESULT MoveCertificates(BOOL fDelete)
{
HRESULT hr = S_OK;
HRESULT hr2 = S_OK;
HCERTSTORE hSpcStore = NULL;
HCERTSTORE hStore = NULL;
HCRYPTPROV hCrypt = NULL;
//__asm int 3
PKITRY {
/*
if (!CryptAcquireContext(&hCrypt, NULL, MS_DEF_PROV, PROV_RSA_FULL, 0))
PKITHROW(HError());
*/
hSpcStore = CertOpenSystemStore( NULL, TEXT("SPC") );
if(!hSpcStore)
PKITHROW(HError());
hr = MoveSpcCerts(fDelete, hSpcStore);
hStore = CertOpenSystemStore(NULL, TEXT(IE30CONVERTEDSTORE));
if(!hStore)
PKITHROW(HError());
hr2 = TransferIE30Certificates(HKEY_CURRENT_USER, SZIE30CERTCLIENTAUTH, hStore, fDelete);
}
PKICATCH(err) {
hr = err.pkiError;
} PKIEND;
if(SUCCEEDED(hr)) hr = hr2;
if(hSpcStore)
CertCloseStore( hSpcStore, 0 );
if(hStore)
CertCloseStore(hStore, 0);
if(hCrypt)
CryptReleaseContext(hCrypt, 0);
return hr;
}