//+------------------------------------------------------------------------- // // 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; }