//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1997 - 1999 // // File: cscsp.cpp // //-------------------------------------------------------------------------- #include #pragma hdrstop #include #include "initcert.h" #include "cscsp.h" #include "csdisp.h" TCHAR const g_wszRegKeyCSP[] = wszREGKEYCSP; TCHAR const g_wszRegKeyEncryptionCSP[] = wszREGKEYENCRYPTIONCSP; TCHAR const g_wszRegProviderType[] = wszREGPROVIDERTYPE; TCHAR const g_wszRegProvider[] = wszREGPROVIDER; TCHAR const g_wszRegHashAlgorithm[] = wszHASHALGORITHM; TCHAR const g_wszRegEncryptionAlgorithm[] = wszENCRYPTIONALGORITHM; TCHAR const g_wszRegMachineKeyset[] = wszMACHINEKEYSET; TCHAR const g_wszRegKeySize[] = wszREGKEYSIZE; BOOL myCertSrvCryptAcquireContext( OUT HCRYPTPROV *phProv, IN WCHAR const *pwszContainer, IN WCHAR const *pwszProvider, IN DWORD dwProvType, IN DWORD dwFlags, IN BOOL fMachineKeyset) { HRESULT hr; if (fMachineKeyset) { dwFlags |= CRYPT_MACHINE_KEYSET; } if (!CryptAcquireContext( phProv, pwszContainer, pwszProvider, dwProvType, dwFlags)) { hr = myHLastError(); _JumpErrorStr2( hr, error, (CRYPT_MACHINE_KEYSET & dwFlags)? "CryptAcquireContext(Machine)" : "CryptAcquireContext(User)", pwszContainer, (CRYPT_DELETEKEYSET & dwFlags)? hr : S_OK); } hr = S_OK; error: if (S_OK != hr) { SetLastError(hr); } return(S_OK == hr); } HRESULT myGetCertSrvCSP( IN BOOL fEncryptionCSP, IN WCHAR const *pwszSanitizedCAName, OUT DWORD *pdwProvType, OUT WCHAR **ppwszProvName, OUT ALG_ID *pidAlg, OUT BOOL *pfMachineKeyset, OPTIONAL OUT DWORD *pdwKeySize) { HRESULT hr; HKEY hCertSrvCSPKey = NULL; DWORD dwValueType; DWORD dwValueSize; WCHAR *pwszPath = NULL; WCHAR *pwszProvName = NULL; WCHAR const *pwszRegKeyCSP; DWORD cwc; if (NULL != ppwszProvName) { *ppwszProvName = NULL; } if (NULL != pdwKeySize) { *pdwKeySize = 0; } if (NULL == pwszSanitizedCAName || NULL == pdwProvType || NULL == ppwszProvName || NULL == pidAlg || NULL == pfMachineKeyset) { hr = E_POINTER; _JumpError(hr, error, "NULL parm"); } pwszRegKeyCSP = fEncryptionCSP? g_wszRegKeyEncryptionCSP : g_wszRegKeyCSP; cwc = WSZARRAYSIZE(wszREGKEYCONFIGPATH_BS) + wcslen(pwszSanitizedCAName) + 1 + wcslen(pwszRegKeyCSP); pwszPath = (WCHAR *) LocalAlloc(LMEM_FIXED, (cwc + 1) * sizeof(WCHAR)); if (NULL == pwszPath) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } wcscpy(pwszPath, wszREGKEYCONFIGPATH_BS); wcscat(pwszPath, pwszSanitizedCAName); wcscat(pwszPath, L"\\"); wcscat(pwszPath, pwszRegKeyCSP); CSASSERT(cwc == wcslen(pwszPath)); hr = RegOpenKeyEx( HKEY_LOCAL_MACHINE, pwszPath, 0, KEY_ALL_ACCESS, &hCertSrvCSPKey); _JumpIfErrorStr2(hr, error, "RegOpenKeyEx", pwszPath, ERROR_FILE_NOT_FOUND); dwValueSize = 0; hr = RegQueryValueEx( hCertSrvCSPKey, g_wszRegProvider, 0, &dwValueType, NULL, &dwValueSize); _JumpIfError(hr, error, "RegQueryValueEx"); if (REG_SZ != dwValueType) { hr = E_INVALIDARG; _JumpError(hr, error, "Invalid reg type"); } pwszProvName = (WCHAR *) LocalAlloc( LMEM_FIXED, dwValueSize + sizeof(WCHAR)); if (NULL == pwszProvName) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } hr = RegQueryValueEx( hCertSrvCSPKey, g_wszRegProvider, 0, &dwValueType, (BYTE *) pwszProvName, &dwValueSize); _JumpIfError(hr, error, "RegQueryValueEx"); pwszProvName[dwValueSize / sizeof(WCHAR)] = L'\0'; dwValueSize = sizeof(*pdwProvType); hr = RegQueryValueEx(hCertSrvCSPKey, g_wszRegProviderType, 0, &dwValueType, (BYTE *) pdwProvType, &dwValueSize); _JumpIfError(hr, error, "RegQueryValueEx"); if (REG_DWORD != dwValueType) { hr = E_INVALIDARG; _JumpError(hr, error, "Invalid reg type"); } dwValueSize = sizeof(*pidAlg); hr = RegQueryValueEx( hCertSrvCSPKey, fEncryptionCSP? g_wszRegEncryptionAlgorithm : g_wszRegHashAlgorithm, 0, &dwValueType, (BYTE *) pidAlg, &dwValueSize); if (S_OK != hr && fEncryptionCSP) { _PrintErrorStr2( hr, "RegQueryValueEx", g_wszRegEncryptionAlgorithm, ERROR_FILE_NOT_FOUND); dwValueSize = sizeof(*pidAlg); hr = RegQueryValueEx( hCertSrvCSPKey, g_wszRegHashAlgorithm, 0, &dwValueType, (BYTE *) pidAlg, &dwValueSize); } _JumpIfError(hr, error, "RegQueryValueEx"); if (REG_DWORD != dwValueType) { hr = E_INVALIDARG; _JumpError(hr, error, "Invalid reg type"); } dwValueSize = sizeof(*pfMachineKeyset); hr = RegQueryValueEx(hCertSrvCSPKey, g_wszRegMachineKeyset, 0, &dwValueType, (BYTE *) pfMachineKeyset, &dwValueSize); _JumpIfError(hr, error, "RegQueryValueEx"); if (REG_DWORD != dwValueType) { hr = E_INVALIDARG; _JumpError(hr, error, "Invalid reg type"); } if (NULL != pdwKeySize) { dwValueSize = sizeof(*pdwKeySize); hr = RegQueryValueEx(hCertSrvCSPKey, g_wszRegKeySize, 0, &dwValueType, (BYTE *) pdwKeySize, &dwValueSize); _JumpIfError(hr, error, "RegQueryValueEx"); if (REG_DWORD != dwValueType) { hr = E_INVALIDARG; _JumpError(hr, error, "Invalid reg type"); } } *ppwszProvName = pwszProvName; pwszProvName = NULL; hr = S_OK; error: if (NULL != pwszProvName) { LocalFree(pwszProvName); } if (NULL != pwszPath) { LocalFree(pwszPath); } if (NULL != hCertSrvCSPKey) { RegCloseKey(hCertSrvCSPKey); } return(myHError(hr)); } //+------------------------------------------------------------------------ // // Function: myGetSigningOID( . . . . ) // // Synopsis: Determine algorithm identifer for cert creation // Arguments: csp_provider_type, hash_algorithm_id. // Returns: object identifier // //------------------------------------------------------------------------- HRESULT myGetSigningOID( OPTIONAL IN HCRYPTPROV hProv, // hProv OR pwszProvName & dwProvType OPTIONAL IN WCHAR const *pwszProvName, OPTIONAL IN DWORD dwProvType, IN ALG_ID idHashAlg, OUT CHAR **ppszAlgId) { HRESULT hr; PCCRYPT_OID_INFO pcOIDInfo; //don't free it ALG_ID aidAlgKey[] = {idHashAlg, 0}; HCRYPTPROV hProvT = NULL; int i; DWORD dwFlags; DWORD cbData; PROV_ENUMALGS enumalgs; BOOL fFoundSignID = FALSE; *ppszAlgId = NULL; if (NULL == hProv) { CSASSERT(NULL != pwszProvName); if (!myCertSrvCryptAcquireContext( &hProvT, NULL, pwszProvName, dwProvType, CRYPT_VERIFYCONTEXT, FALSE)) { hr = myHLastError(); _JumpErrorStr(hr, error, "myCertSrvCryptAcquireContext", pwszProvName); } hProv = hProvT; } // find public key id dwFlags = CRYPT_FIRST; for (i = 0; ; i++) { cbData = sizeof(enumalgs); if (!CryptGetProvParam( hProv, PP_ENUMALGS, (BYTE *) &enumalgs, &cbData, dwFlags)) { hr = myHLastError(); if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr) { // out of for loop break; } _JumpError(hr, error, "CryptGetProvParam"); } if (ALG_CLASS_SIGNATURE == GET_ALG_CLASS(enumalgs.aiAlgid)) { fFoundSignID = TRUE; aidAlgKey[1] = enumalgs.aiAlgid; break; } dwFlags = 0; } if (fFoundSignID) { pcOIDInfo = CryptFindOIDInfo( CRYPT_OID_INFO_SIGN_KEY, aidAlgKey, CRYPT_SIGN_ALG_OID_GROUP_ID); // only signing if (NULL == pcOIDInfo) { hr = E_INVALIDARG; _JumpError(hr, error, "unsupported signing algorithm"); } hr = myDupStringA(pcOIDInfo->pszOID, ppszAlgId); _JumpIfError(hr, error, "myDupStringA"); } hr = S_OK; error: if (NULL != hProvT) { CryptReleaseContext(hProvT, 0); } CSASSERT(S_OK == hr || FAILED(hr)); return(hr); } HRESULT myValidateKeyForSigning( IN HCRYPTPROV hProv, OPTIONAL IN CERT_PUBLIC_KEY_INFO const *pPublicKeyInfo, IN ALG_ID algId) { HRESULT hr; BYTE abRandom[64]; HCRYPTKEY hKey = NULL; HCRYPTHASH hHash = NULL; BYTE *pbSignature = NULL; DWORD cbSignature; // create a supported hash if (!CryptCreateHash(hProv, algId, 0, 0, &hHash)) { hr = myHLastError(); DBGPRINT((DBG_SS_ERROR, "algId = %x\n", algId)); _JumpError(hr, error, "CryptCreateHash"); } // create some random data if (!CryptGenRandom(hProv, ARRAYSIZE(abRandom), abRandom)) { hr = myHLastError(); _JumpError(hr, error, "CryptGenRandom"); } if (!CryptHashData(hHash, abRandom, ARRAYSIZE(abRandom), 0)) { hr = myHLastError(); _JumpError(hr, error, "CryptHashData"); } // sign the hash, get size first if (!CryptSignHash(hHash, AT_SIGNATURE, NULL, 0, NULL, &cbSignature)) { hr = myHLastError(); _JumpError(hr, error, "CryptSignHash"); } pbSignature = (BYTE *) LocalAlloc(LMEM_FIXED, cbSignature); if (NULL == pbSignature) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } if (!CryptSignHash(hHash, AT_SIGNATURE, NULL, 0, pbSignature, &cbSignature)) { hr = myHLastError(); _JumpError(hr, error, "CryptSignHash"); } if (NULL != pPublicKeyInfo) { // import public key into provider if (!CryptImportPublicKeyInfo( hProv, X509_ASN_ENCODING, const_cast(pPublicKeyInfo), &hKey)) { hr = myHLastError(); _JumpError(hr, error, "CryptImportPublicKeyInfo"); } } else { // get public key from container if (!CryptGetUserKey(hProv, AT_SIGNATURE, &hKey)) { hr = myHLastError(); _JumpError(hr, error, "CryptGetUserKey"); } } if (!CryptVerifySignature(hHash, pbSignature, cbSignature, hKey, NULL, 0)) { hr = myHLastError(); _JumpError(hr, error, "CryptVerifySignature"); } hr = S_OK; error: if (NULL != hHash) { CryptDestroyHash(hHash); } if (NULL != hKey) { CryptDestroyKey(hKey); } if (NULL != pbSignature) { LocalFree(pbSignature); } CSASSERT(S_OK == hr || FAILED(hr)); return(hr); } HRESULT myValidateKeyForEncrypting( IN HCRYPTPROV hProv, IN CERT_PUBLIC_KEY_INFO const *pPublicKeyInfo, IN ALG_ID algId) { HRESULT hr; HCRYPTKEY hKeyPub = NULL; HCRYPTKEY hKeySym = NULL; HCRYPTKEY hKeyPri = NULL; BYTE *pbKeySym = NULL; DWORD cbKeySym; BYTE abRandom[64]; BYTE *pbEncrypted = NULL; BYTE *pbDecrypted = NULL; DWORD cbEncrypted; DWORD cbDecrypted; // import public key into provider if (!CryptImportPublicKeyInfo( hProv, X509_ASN_ENCODING, const_cast(pPublicKeyInfo), &hKeyPub)) { hr = myHLastError(); _JumpError(hr, error, "CryptImportPublicKeyInfo"); } // Generate a default sized symmetric session key if (!CryptGenKey(hProv, algId, CRYPT_EXPORTABLE, &hKeySym)) { hr = myHLastError(); _JumpError(hr, error, "CryptGenKey"); } // create some random data if (!CryptGenRandom(hProv, ARRAYSIZE(abRandom), abRandom)) { hr = myHLastError(); _JumpError(hr, error, "CryptGenRandom"); } #if 1 DBGPRINT((DBG_SS_CERTLIBI, "Plain text size = %d\n", ARRAYSIZE(abRandom))); DBGDUMPHEX(( DBG_SS_CERTLIBI, DH_NOADDRESS | DH_NOTABPREFIX | 8, abRandom, ARRAYSIZE(abRandom))); #endif hr = myCryptEncrypt( hKeySym, abRandom, ARRAYSIZE(abRandom), &pbEncrypted, &cbEncrypted); _JumpIfError(hr, error, "myCryptEncrypt"); #if 1 DBGPRINT((DBG_SS_CERTLIBI, "Encrypted size = %d\n", cbEncrypted)); DBGDUMPHEX(( DBG_SS_CERTLIBI, DH_NOADDRESS | DH_NOTABPREFIX | 8, pbEncrypted, cbEncrypted)); #endif hr = myCryptExportKey(hKeySym, hKeyPub, SIMPLEBLOB, 0, &pbKeySym, &cbKeySym); _JumpIfError(hr, error, "myCryptExportKey"); CryptDestroyKey(hKeySym); hKeySym = NULL; #if 1 DBGPRINT((DBG_SS_CERTLIBI, "SIMPLEBLOB:\n")); DBGDUMPHEX(( DBG_SS_CERTLIBI, DH_NOADDRESS | DH_NOTABPREFIX | 8, pbKeySym, cbKeySym)); #endif // get private key from container and import session key blob if (!CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hKeyPri)) { hr = myHLastError(); _JumpError(hr, error, "CryptGetUserKey"); } if (!CryptImportKey( hProv, pbKeySym, cbKeySym, hKeyPri, CRYPT_EXPORTABLE, &hKeySym)) { hr = myHLastError(); _JumpError(hr, error, "CryptImportKey"); } hr = myCryptDecrypt( hKeySym, pbEncrypted, cbEncrypted, &pbDecrypted, &cbDecrypted); _JumpIfError(hr, error, "myCryptDecrypt"); #if 1 DBGPRINT((DBG_SS_CERTLIBI, "Decrypted size = %d\n", cbDecrypted)); DBGDUMPHEX(( DBG_SS_CERTLIBI, DH_NOADDRESS | DH_NOTABPREFIX | 8, pbDecrypted, cbDecrypted)); #endif if (ARRAYSIZE(abRandom) != cbDecrypted || 0 != memcmp(abRandom, pbDecrypted, ARRAYSIZE(abRandom))) { hr = NTE_BAD_KEY; _JumpIfError(hr, error, "Decrypted data mismatch"); } hr = S_OK; error: if (NULL != hKeyPub) { CryptDestroyKey(hKeyPub); } if (NULL != hKeySym) { CryptDestroyKey(hKeySym); } if (NULL != hKeyPri) { CryptDestroyKey(hKeyPri); } if (NULL != pbEncrypted) { LocalFree(pbEncrypted); } if (NULL != pbDecrypted) { LocalFree(pbDecrypted); } if (NULL != pbKeySym) { LocalFree(pbKeySym); } CSASSERT(S_OK == hr || FAILED(hr)); return(hr); } HRESULT myValidateHashForSigning( IN WCHAR const *pwszContainer, IN WCHAR const *pwszProvName, IN DWORD dwProvType, IN BOOL fMachineKeyset, IN OPTIONAL CERT_PUBLIC_KEY_INFO const *pPublicKeyInfo, IN ALG_ID algId) { HRESULT hr; HCRYPTPROV hProv = NULL; // get private key handler if (!myCertSrvCryptAcquireContext( &hProv, pwszContainer, pwszProvName, dwProvType, 0, fMachineKeyset)) { hr = myHLastError(); _JumpError(hr, error, "myCertSrvCryptAcquireContext"); } hr = myValidateKeyForSigning(hProv, pPublicKeyInfo, algId); _JumpIfError(hr, error, "myValidateKeyForSigning"); error: if (NULL != hProv) { CryptReleaseContext(hProv, 0); } CSASSERT(S_OK == hr || FAILED(hr)); return(hr); } HRESULT GenerateTemporaryContainerName( OUT WCHAR **ppwszKeyContainerName) { HRESULT hr; GUID guid; WCHAR awcbuf[MAX_PATH]; DWORD cb; DWORD cwc; myGenerateGuidSerialNumber(&guid); wcscpy(awcbuf, L"KeyVerification--"); cwc = wcslen(awcbuf); cb = sizeof(awcbuf) - cwc * sizeof(WCHAR); hr = MultiByteIntegerToWszBuf( FALSE, sizeof(guid), (BYTE const *) &guid, &cb, &awcbuf[cwc]); _JumpIfError(hr, error, "MultiByteIntegerToWszBuf"); hr = myDupString(awcbuf, ppwszKeyContainerName); _JumpIfError(hr, error, "myDupString"); error: return(hr); } VOID DeleteRSAKeyContainer( IN WCHAR const *pwszKeyContainerName, IN BOOL fMachineKeyset) { HCRYPTPROV hProv; DWORD dwFlags = CRYPT_DELETEKEYSET; if (fMachineKeyset) { dwFlags = CRYPT_MACHINE_KEYSET; } CryptAcquireContext( &hProv, pwszKeyContainerName, NULL, // pwszProvName PROV_RSA_FULL, dwFlags); } HRESULT myValidateKeyBlob( IN BYTE const *pbKey, IN DWORD cbKey, IN CERT_PUBLIC_KEY_INFO const *pPublicKeyInfo, IN BOOL fV1Cert, OPTIONAL OUT CRYPT_KEY_PROV_INFO *pkpi) { HRESULT hr; WCHAR *pwszKeyContainerName = NULL; HCRYPTPROV hProv = NULL; HCRYPTKEY hKey = NULL; CRYPT_KEY_PROV_INFO kpi; BOOL fMatchingKey; WCHAR wszPassword[MAX_PATH]; hr = GenerateTemporaryContainerName(&pwszKeyContainerName); _JumpIfError(hr, error, "GenerateTemporaryContainerName"); DeleteRSAKeyContainer(pwszKeyContainerName, FALSE); DBGPRINT((DBG_SS_CERTLIBI, "Key Container: %ws\n", pwszKeyContainerName)); if (!CryptAcquireContext( &hProv, pwszKeyContainerName, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) { hr = myHLastError(); _JumpError(hr, error, "CryptAcquireContext"); } if (!CryptImportKey( hProv, pbKey, cbKey, NULL, // hPubKey CRYPT_EXPORTABLE, &hKey)) { hr = myHLastError(); _JumpError(hr, error, "CryptImportKey"); } CryptDestroyKey(hKey); hKey = NULL; ZeroMemory(&kpi, sizeof(kpi)); kpi.pwszContainerName = pwszKeyContainerName; kpi.dwProvType = PROV_RSA_FULL; kpi.dwKeySpec = AT_KEYEXCHANGE; if (!CryptGetUserKey(hProv, kpi.dwKeySpec, &hKey)) { hr = myHLastError(); _PrintIfError2(hr, "CryptGetUserKey", hr); kpi.dwKeySpec = AT_SIGNATURE; if (!CryptGetUserKey(hProv, kpi.dwKeySpec, &hKey)) { hr = myHLastError(); _JumpIfError(hr, error, "CryptGetUserKey"); } } CryptDestroyKey(hKey); hKey = NULL; CryptReleaseContext(hProv, 0); hProv = NULL; if (!CryptAcquireContext( &hProv, pwszKeyContainerName, NULL, PROV_RSA_FULL, 0)) { hr = myHLastError(); _JumpError(hr, error, "CryptAcquireContext"); } if (AT_SIGNATURE == kpi.dwKeySpec) { hr = myValidateKeyForSigning(hProv, pPublicKeyInfo, CALG_SHA1); _PrintIfError(hr, "myValidateKeyForSigning"); } else { hr = myValidateKeyForEncrypting(hProv, pPublicKeyInfo, CALG_RC4); _PrintIfError(hr, "myValidateKeyForEncrypting"); } if (S_OK != hr) { _JumpError(hr, error, "Key Validation"); } hr = myVerifyPublicKey( NULL, // pCert fV1Cert, &kpi, // pKeyProvInfo pPublicKeyInfo, // pPublicKeyInfo &fMatchingKey); if (S_OK != hr) { _JumpError(hr, error, "myVerifyPublicKey"); } if (!fMatchingKey) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "Key doesn't match cert"); } if (NULL != pkpi) { *pkpi = kpi; pwszKeyContainerName = NULL; } error: if (NULL != hKey) { CryptDestroyKey(hKey); } if (NULL != hProv) { CryptReleaseContext(hProv, 0); } if (NULL != pwszKeyContainerName) { DeleteRSAKeyContainer(pwszKeyContainerName, FALSE); LocalFree(pwszKeyContainerName); } return(hr); } /* * myEnumProviders * * Purpose: * Enumerate the providers. * * Parameters: * IN dwIndex - Index to the providers to enumerate * IN pdwReserved - Reserved for future use * IN dwFlags - Flags parameter * OUT pdwProvType - The type of the provider * OUT ppwszProvName - Name of the enumerated provider */ HRESULT myEnumProviders( IN DWORD dwIndex, IN DWORD *pdwReserved, IN DWORD dwFlags, OUT DWORD *pdwProvType, OUT WCHAR **ppwszProvName) { HRESULT hr; char *pszProvName = NULL; DWORD cbProvName; *ppwszProvName = NULL; while (TRUE) { if (!CryptEnumProvidersA( dwIndex, pdwReserved, dwFlags, pdwProvType, pszProvName, &cbProvName)) { hr = myHLastError(); _JumpError2(hr, error, "CryptEnumProvidersA", hr); } if (NULL != pszProvName) { break; } // allocate ansi string buffer pszProvName = (char *) LocalAlloc(LMEM_FIXED, cbProvName); if (NULL == pszProvName) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } } if (!myConvertSzToWsz(ppwszProvName, pszProvName, -1)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "myConvertSzToWsz"); } hr = S_OK; error: if (NULL != pszProvName) { LocalFree(pszProvName); } return(hr); }