929 lines
20 KiB
C++
929 lines
20 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1997 - 1999
|
|
//
|
|
// File: cscsp.cpp
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include <pch.cpp>
|
|
|
|
#pragma hdrstop
|
|
|
|
#include <tchar.h>
|
|
#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<CERT_PUBLIC_KEY_INFO *>(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<CERT_PUBLIC_KEY_INFO *>(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);
|
|
}
|