windows-nt/Source/XPSP1/NT/ds/security/cryptoapi/pki/sp3crmsg/sp3crmsg.cpp

1018 lines
31 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1997 - 1999
//
// File: sp3crmsg.cpp
//
//--------------------------------------------------------------------------
//+-------------------------------------------------------------------------
// File: sp3crmsg.cpp
//
// Contents: Installable OID functions providing backwards compatiblity
// with the way the NT4.0 SP3 and IE 3.02 versions of crypt32.dll
// encrypted the symmetric key in a PKCS #7 EnvelopedData message.
//
// The SP3 version of crypt32.dll failed to byte reverse the
// encrypted symmetric key. It also added zero salt instead
// of no salt.
//
// Functions: DllMain
// DllRegisterServer
// DllUnregisterServer
// SP3ImportEncryptKey
// SP3GenEncryptKey
// SP3ExportEncryptKey
#ifdef CMS_PKCS7
// DllInstall
// CryptMsgDllGenContentEncryptKey
// CryptMsgDllExportKeyTrans
// CryptMsgDllImportKeyTrans
// NotImplCryptMsgDllImportKeyTrans
#endif // CMS_PKCS7
//--------------------------------------------------------------------------
#define CMS_PKCS7 1
#include <windows.h>
#include <wincrypt.h>
#include "sp3crmsg.h"
// memory management
#define SP3Alloc(cb) ((void*)LocalAlloc(LPTR, cb))
#define SP3Free(pv) (LocalFree((HLOCAL)pv))
// The Thread Local Storage (TLS) referenced by iSP3TLS has pointer of
// ((void *) 0x1) if SP3 compatible encryption is enabled. Otherwise, its 0.
static DWORD iSP3TLS = 0xFFFFFFFF;
#define SP3_TLS_POINTER ((void *) 0x1)
typedef struct _SIMPLEBLOBHEADER {
ALG_ID aiEncAlg;
} SIMPLEBLOBHEADER, *PSIMPLEBLOBHEADER;
typedef struct _OID_REG_ENTRY {
LPCSTR pszOID;
LPCSTR pszOverrideFuncName;
} OID_REG_ENTRY, *POID_REG_ENTRY;
//+-------------------------------------------------------------------------
// ImportEncryptKey OID Installable Functions
//--------------------------------------------------------------------------
static HCRYPTOIDFUNCSET hImportEncryptKeyFuncSet;
static PFN_CMSG_IMPORT_ENCRYPT_KEY pfnDefaultImportEncryptKey = NULL;
BOOL
WINAPI
SP3ImportEncryptKey(
IN HCRYPTPROV hCryptProv,
IN DWORD dwKeySpec,
IN PCRYPT_ALGORITHM_IDENTIFIER paiEncrypt,
IN PCRYPT_ALGORITHM_IDENTIFIER paiPubKey,
IN PBYTE pbEncodedKey,
IN DWORD cbEncodedKey,
OUT HCRYPTKEY *phEncryptKey);
static const CRYPT_OID_FUNC_ENTRY ImportEncryptKeyFuncTable[] = {
szOID_OIWSEC_desCBC, SP3ImportEncryptKey,
szOID_RSA_RC2CBC, SP3ImportEncryptKey,
szOID_RSA_RC4, SP3ImportEncryptKey
};
#define IMPORT_ENCRYPT_KEY_FUNC_COUNT (sizeof(ImportEncryptKeyFuncTable) / \
sizeof(ImportEncryptKeyFuncTable[0]))
static const OID_REG_ENTRY ImportEncryptKeyRegTable[] = {
szOID_OIWSEC_desCBC, "SP3ImportEncryptKey",
szOID_RSA_RC2CBC, "SP3ImportEncryptKey",
szOID_RSA_RC4, "SP3ImportEncryptKey"
};
#define IMPORT_ENCRYPT_KEY_REG_COUNT (sizeof(ImportEncryptKeyRegTable) / \
sizeof(ImportEncryptKeyRegTable[0]))
//+-------------------------------------------------------------------------
// GenEncryptKey OID Installable Functions
//--------------------------------------------------------------------------
static HCRYPTOIDFUNCSET hGenEncryptKeyFuncSet;
static PFN_CMSG_GEN_ENCRYPT_KEY pfnDefaultGenEncryptKey = NULL;
BOOL
WINAPI
SP3GenEncryptKey(
IN OUT HCRYPTPROV *phCryptProv,
IN PCRYPT_ALGORITHM_IDENTIFIER paiEncrypt,
IN PVOID pvEncryptAuxInfo,
IN PCERT_PUBLIC_KEY_INFO pPublicKeyInfo,
IN PFN_CMSG_ALLOC pfnAlloc,
OUT HCRYPTKEY *phEncryptKey,
OUT PBYTE *ppbEncryptParameters,
OUT PDWORD pcbEncryptParameters);
static const CRYPT_OID_FUNC_ENTRY GenEncryptKeyFuncTable[] = {
szOID_OIWSEC_desCBC, SP3GenEncryptKey,
szOID_RSA_RC2CBC, SP3GenEncryptKey,
szOID_RSA_RC4, SP3GenEncryptKey
};
#define GEN_ENCRYPT_KEY_FUNC_COUNT (sizeof(GenEncryptKeyFuncTable) / \
sizeof(GenEncryptKeyFuncTable[0]))
static const OID_REG_ENTRY GenEncryptKeyRegTable[] = {
szOID_OIWSEC_desCBC, "SP3GenEncryptKey",
szOID_RSA_RC2CBC, "SP3GenEncryptKey",
szOID_RSA_RC4, "SP3GenEncryptKey"
};
#define GEN_ENCRYPT_KEY_REG_COUNT (sizeof(GenEncryptKeyRegTable) / \
sizeof(GenEncryptKeyRegTable[0]))
//+-------------------------------------------------------------------------
// ExportEncryptKey OID Installable Functions
//--------------------------------------------------------------------------
static HCRYPTOIDFUNCSET hExportEncryptKeyFuncSet;
static PFN_CMSG_EXPORT_ENCRYPT_KEY pfnDefaultExportEncryptKey = NULL;
BOOL
WINAPI
SP3ExportEncryptKey(
IN HCRYPTPROV hCryptProv,
IN HCRYPTKEY hEncryptKey,
IN PCERT_PUBLIC_KEY_INFO pPublicKeyInfo,
OUT PBYTE pbData,
IN OUT PDWORD pcbData);
static const CRYPT_OID_FUNC_ENTRY ExportEncryptKeyFuncTable[] = {
szOID_RSA_RSA, SP3ExportEncryptKey
};
#define EXPORT_ENCRYPT_KEY_FUNC_COUNT (sizeof(ExportEncryptKeyFuncTable) / \
sizeof(ExportEncryptKeyFuncTable[0]))
static const OID_REG_ENTRY ExportEncryptKeyRegTable[] = {
szOID_RSA_RSA, "SP3ExportEncryptKey"
};
#define EXPORT_ENCRYPT_KEY_REG_COUNT (sizeof(ExportEncryptKeyRegTable) / \
sizeof(ExportEncryptKeyRegTable[0]))
static char szCrypt32[]="crypt32.dll";
// First post IE4.0 versions of crypt32.dll start with "5.101.1681.1"
static DWORD dwLowVersion = (1681 << 16) | 1;
static DWORD dwHighVersion = (5 << 16) | 101;
static BOOL IsPostIE4Crypt32()
{
BOOL fPostIE4 = FALSE; // default to IE4
DWORD dwHandle = 0;
DWORD cbInfo;
void *pvInfo = NULL;
VS_FIXEDFILEINFO *pFixedFileInfo = NULL; // not allocated
UINT ccFixedFileInfo = 0;
if (0 == (cbInfo = GetFileVersionInfoSizeA(szCrypt32, &dwHandle)))
goto ErrorReturn;
if (NULL == (pvInfo = SP3Alloc(cbInfo)))
goto ErrorReturn;
if (!GetFileVersionInfoA(
szCrypt32,
0, // dwHandle, ignored
cbInfo,
pvInfo
))
goto ErrorReturn;
if (!VerQueryValueA(
pvInfo,
"\\", // VS_FIXEDFILEINFO
(void **) &pFixedFileInfo,
&ccFixedFileInfo
))
goto ErrorReturn;
if (pFixedFileInfo->dwFileVersionMS > dwHighVersion ||
(pFixedFileInfo->dwFileVersionMS == dwHighVersion &&
pFixedFileInfo->dwFileVersionLS >= dwLowVersion))
fPostIE4 = TRUE;
CommonReturn:
if (pvInfo)
SP3Free(pvInfo);
return fPostIE4;
ErrorReturn:
goto CommonReturn;
}
static HRESULT HError()
{
DWORD dw = GetLastError();
HRESULT hr;
if ( dw <= 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;
}
STDAPI DllRegisterServer(void)
{
int i;
DWORD dwFlags = CRYPT_INSTALL_OID_FUNC_BEFORE_FLAG;
for (i = 0; i < IMPORT_ENCRYPT_KEY_REG_COUNT; i++) {
if (!CryptRegisterOIDFunction(
X509_ASN_ENCODING,
CMSG_OID_IMPORT_ENCRYPT_KEY_FUNC,
ImportEncryptKeyRegTable[i].pszOID,
L"sp3crmsg.dll",
ImportEncryptKeyRegTable[i].pszOverrideFuncName
))
return HError();
if (!CryptSetOIDFunctionValue(
X509_ASN_ENCODING,
CMSG_OID_IMPORT_ENCRYPT_KEY_FUNC,
ImportEncryptKeyRegTable[i].pszOID,
CRYPT_OID_REG_FLAGS_VALUE_NAME,
REG_DWORD,
(BYTE *) &dwFlags,
sizeof(dwFlags)
))
return HError();
}
for (i = 0; i < GEN_ENCRYPT_KEY_REG_COUNT; i++) {
if (!CryptRegisterOIDFunction(
X509_ASN_ENCODING,
CMSG_OID_GEN_ENCRYPT_KEY_FUNC,
GenEncryptKeyRegTable[i].pszOID,
L"sp3crmsg.dll",
GenEncryptKeyRegTable[i].pszOverrideFuncName
))
return HError();
if (!CryptSetOIDFunctionValue(
X509_ASN_ENCODING,
CMSG_OID_GEN_ENCRYPT_KEY_FUNC,
GenEncryptKeyRegTable[i].pszOID,
CRYPT_OID_REG_FLAGS_VALUE_NAME,
REG_DWORD,
(BYTE *) &dwFlags,
sizeof(dwFlags)
))
return HError();
}
for (i = 0; i < EXPORT_ENCRYPT_KEY_REG_COUNT; i++) {
if (!CryptRegisterOIDFunction(
X509_ASN_ENCODING,
CMSG_OID_EXPORT_ENCRYPT_KEY_FUNC,
ExportEncryptKeyRegTable[i].pszOID,
L"sp3crmsg.dll",
ExportEncryptKeyRegTable[i].pszOverrideFuncName
))
return HError();
if (!CryptSetOIDFunctionValue(
X509_ASN_ENCODING,
CMSG_OID_EXPORT_ENCRYPT_KEY_FUNC,
ExportEncryptKeyRegTable[i].pszOID,
CRYPT_OID_REG_FLAGS_VALUE_NAME,
REG_DWORD,
(BYTE *) &dwFlags,
sizeof(dwFlags)
))
return HError();
}
return S_OK;
}
STDAPI DllUnregisterServer(void)
{
HRESULT hr = S_OK;
int i;
for (i = 0; i < IMPORT_ENCRYPT_KEY_REG_COUNT; i++) {
if (!CryptUnregisterOIDFunction(
X509_ASN_ENCODING,
CMSG_OID_IMPORT_ENCRYPT_KEY_FUNC,
ImportEncryptKeyRegTable[i].pszOID
)) {
if (ERROR_FILE_NOT_FOUND != GetLastError())
hr = HError();
}
}
for (i = 0; i < GEN_ENCRYPT_KEY_REG_COUNT; i++) {
if (!CryptUnregisterOIDFunction(
X509_ASN_ENCODING,
CMSG_OID_GEN_ENCRYPT_KEY_FUNC,
GenEncryptKeyRegTable[i].pszOID
)) {
if (ERROR_FILE_NOT_FOUND != GetLastError())
hr = HError();
}
}
for (i = 0; i < EXPORT_ENCRYPT_KEY_REG_COUNT; i++) {
if (!CryptUnregisterOIDFunction(
X509_ASN_ENCODING,
CMSG_OID_EXPORT_ENCRYPT_KEY_FUNC,
ExportEncryptKeyRegTable[i].pszOID
)) {
if (ERROR_FILE_NOT_FOUND != GetLastError())
hr = HError();
}
}
#ifdef CMS_PKCS7
if (!CryptUnregisterOIDFunction(
X509_ASN_ENCODING,
CMSG_OID_GEN_CONTENT_ENCRYPT_KEY_FUNC,
szOID_RSA_RC2CBC
)) {
if (ERROR_FILE_NOT_FOUND != GetLastError())
hr = HError();
}
if (!CryptUnregisterOIDFunction(
X509_ASN_ENCODING,
CMSG_OID_EXPORT_KEY_TRANS_FUNC,
szOID_RSA_RSA
)) {
if (ERROR_FILE_NOT_FOUND != GetLastError())
hr = HError();
}
if (!CryptUnregisterOIDFunction(
X509_ASN_ENCODING,
CMSG_OID_IMPORT_KEY_TRANS_FUNC,
szOID_RSA_RSA "!" szOID_RSA_RC2CBC
)) {
if (ERROR_FILE_NOT_FOUND != GetLastError())
hr = HError();
}
if (!CryptUnregisterOIDFunction(
X509_ASN_ENCODING,
CMSG_OID_IMPORT_KEY_TRANS_FUNC,
szOID_RSA_RC2CBC
)) {
if (ERROR_FILE_NOT_FOUND != GetLastError())
hr = HError();
}
#endif // CMS_PKCS7
return hr;
}
#ifdef CMS_PKCS7
//+---------------------------------------------------------------------------
//
// Function: DllInstall
//
// Synopsis: dll installation entry point
//
//----------------------------------------------------------------------------
STDAPI DllInstall (BOOL fRegister, LPCSTR pszCommand)
{
if (!fRegister)
return DllUnregisterServer();
if (!CryptRegisterOIDFunction(
X509_ASN_ENCODING,
CMSG_OID_GEN_CONTENT_ENCRYPT_KEY_FUNC,
szOID_RSA_RC2CBC,
L"sp3crmsg.dll",
NULL // pszOverrideFuncName
))
return HError();
if (!CryptRegisterOIDFunction(
X509_ASN_ENCODING,
CMSG_OID_EXPORT_KEY_TRANS_FUNC,
szOID_RSA_RSA,
L"sp3crmsg.dll",
NULL // pszOverrideFuncName
))
return HError();
if (!CryptRegisterOIDFunction(
X509_ASN_ENCODING,
CMSG_OID_IMPORT_KEY_TRANS_FUNC,
szOID_RSA_RSA "!" szOID_RSA_RC2CBC,
L"sp3crmsg.dll",
"NotImplCryptMsgDllImportKeyTrans"
))
return HError();
if (!CryptRegisterOIDFunction(
X509_ASN_ENCODING,
CMSG_OID_IMPORT_KEY_TRANS_FUNC,
szOID_RSA_RC2CBC,
L"sp3crmsg.dll",
NULL // pszOverrideFuncName
))
return HError();
return S_OK;
}
#endif // CMS_PKCS7
//+-------------------------------------------------------------------------
// Function: DllMain
//
// Synopsis: Process/Thread attach/detach
//
// At process attach install the SP3 compatible version of
// CryptMsgDllImportEncryptKey, CryptMsgDllGenEncryptKey and
// CryptMsgDllExportEncryptKey.
//--------------------------------------------------------------------------
BOOL
WINAPI
DllMain(
HMODULE hInst,
ULONG ulReason,
LPVOID lpReserved)
{
BOOL fResult;
HCRYPTOIDFUNCADDR hFuncAddr;
switch (ulReason) {
case DLL_PROCESS_ATTACH:
#if 0
// Post IE 4.0 releases of crypt32.dll already have the SP3
// backwards compatible fix.
if (IsPostIE4Crypt32())
return TRUE;
#endif
if (NULL == (hImportEncryptKeyFuncSet = CryptInitOIDFunctionSet(
CMSG_OID_IMPORT_ENCRYPT_KEY_FUNC,
0)))
goto ErrorReturn;
if (NULL == (hGenEncryptKeyFuncSet = CryptInitOIDFunctionSet(
CMSG_OID_GEN_ENCRYPT_KEY_FUNC,
0)))
goto ErrorReturn;
if (NULL == (hExportEncryptKeyFuncSet = CryptInitOIDFunctionSet(
CMSG_OID_EXPORT_ENCRYPT_KEY_FUNC,
0)))
goto ErrorReturn;
// Get the default import encrypt key function which we will call if
// unable to do a successful import without byte reversing the
// encrypted symmetric key.
if (CryptGetOIDFunctionAddress(
hImportEncryptKeyFuncSet,
X509_ASN_ENCODING,
szOID_RSA_RC2CBC,
CRYPT_GET_INSTALLED_OID_FUNC_FLAG,
(void **) &pfnDefaultImportEncryptKey,
&hFuncAddr))
CryptFreeOIDFunctionAddress(hFuncAddr, 0);
#if 0
if (!CryptInstallOIDFunctionAddress(
hInst,
X509_ASN_ENCODING,
CMSG_OID_IMPORT_ENCRYPT_KEY_FUNC,
IMPORT_ENCRYPT_KEY_FUNC_COUNT,
ImportEncryptKeyFuncTable,
CRYPT_INSTALL_OID_FUNC_BEFORE_FLAG // dwFlags
))
goto ErrorReturn;
#endif
// Get the default gen and export encrypt key functions which we will
// call if pvEncryptionAuxInfo points to a
// CMSG_SP3_COMPATIBLE_AUX_INFO data structure.
if (CryptGetOIDFunctionAddress(
hGenEncryptKeyFuncSet,
X509_ASN_ENCODING,
szOID_RSA_RC2CBC,
CRYPT_GET_INSTALLED_OID_FUNC_FLAG,
(void **) &pfnDefaultGenEncryptKey,
&hFuncAddr))
CryptFreeOIDFunctionAddress(hFuncAddr, 0);
if (CryptGetOIDFunctionAddress(
hExportEncryptKeyFuncSet,
X509_ASN_ENCODING,
szOID_RSA_RSA,
CRYPT_GET_INSTALLED_OID_FUNC_FLAG,
(void **) &pfnDefaultExportEncryptKey,
&hFuncAddr))
CryptFreeOIDFunctionAddress(hFuncAddr, 0);
#if 0
if (!CryptInstallOIDFunctionAddress(
hInst,
X509_ASN_ENCODING,
CMSG_OID_GEN_ENCRYPT_KEY_FUNC,
GEN_ENCRYPT_KEY_FUNC_COUNT,
GenEncryptKeyFuncTable,
CRYPT_INSTALL_OID_FUNC_BEFORE_FLAG // dwFlags
))
goto ErrorReturn;
if (!CryptInstallOIDFunctionAddress(
hInst,
X509_ASN_ENCODING,
CMSG_OID_EXPORT_ENCRYPT_KEY_FUNC,
EXPORT_ENCRYPT_KEY_FUNC_COUNT,
ExportEncryptKeyFuncTable,
CRYPT_INSTALL_OID_FUNC_BEFORE_FLAG // dwFlags
))
goto ErrorReturn;
#endif
// Allocate TLS which contains a pointer of ((void *) 0x1) for SP3
// compatible encryption. This pointer will be passed from
// SP3GenEncryptKey() to SP3ExportEncryptKey().
//
// If not SP3 encryption, the pointer is NULL.
if ((iSP3TLS = TlsAlloc()) == 0xFFFFFFFF)
goto ErrorReturn;
break;
case DLL_PROCESS_DETACH:
if (iSP3TLS != 0xFFFFFFFF) {
TlsFree(iSP3TLS);
iSP3TLS = 0xFFFFFFFF;
}
break;
case DLL_THREAD_DETACH:
default:
break;
}
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
}
//+-------------------------------------------------------------------------
// SP3 import of the encryption key.
//
// The SP3 version of crypt32.dll didn't include any parameters for the
// encryption algorithm. Later versions of crypt32.dll do. Therefore, we only
// need to attempt to import the key without byte reversal if there aren't
// any parameters present.
//--------------------------------------------------------------------------
BOOL
WINAPI
SP3ImportEncryptKey(
IN HCRYPTPROV hCryptProv,
IN DWORD dwKeySpec,
IN PCRYPT_ALGORITHM_IDENTIFIER paiEncrypt,
IN PCRYPT_ALGORITHM_IDENTIFIER paiPubKey,
IN PBYTE pbEncodedKey,
IN DWORD cbEncodedKey,
OUT HCRYPTKEY *phEncryptKey
)
{
BOOL fResult;
HCRYPTKEY hEncryptKey = 0;
HCRYPTKEY hUserKey = 0;
DWORD dwAlgIdEncrypt;
DWORD dwAlgIdPubKey;
PBYTE pbCspKey = NULL;
DWORD cbCspKey;
PUBLICKEYSTRUC *ppks;
PSIMPLEBLOBHEADER psbh;
PCCRYPT_OID_INFO pOIDInfo;
// Check if more than just the NULL parameters
if (2 < paiEncrypt->Parameters.cbData) {
fResult = FALSE;
goto DefaultImport;
}
// Map the ASN algorithm identifier to the CSP ALG_ID.
if (NULL == (pOIDInfo = CryptFindOIDInfo(
CRYPT_OID_INFO_OID_KEY,
paiEncrypt->pszObjId,
CRYPT_ENCRYPT_ALG_OID_GROUP_ID)))
goto GetEncryptAlgidError;
dwAlgIdEncrypt = pOIDInfo->Algid;
// Create the CSP encrypted symmetric key structure WITHOUT BYTE REVERSAL.
dwAlgIdPubKey = CALG_RSA_KEYX;
cbCspKey = cbEncodedKey + sizeof(PUBLICKEYSTRUC) + sizeof(SIMPLEBLOBHEADER);
if (NULL == (pbCspKey = (PBYTE)SP3Alloc( cbCspKey)))
goto OutOfMemory;
ppks = (PUBLICKEYSTRUC *)pbCspKey;
ppks->bType = SIMPLEBLOB;
ppks->bVersion = CUR_BLOB_VERSION;
ppks->reserved = 0;
ppks->aiKeyAlg = dwAlgIdEncrypt;
psbh = (PSIMPLEBLOBHEADER)(ppks + 1);
psbh->aiEncAlg = dwAlgIdPubKey;
// NO BYTE REVERSAL as done in SP3.
memcpy( (PBYTE)(psbh+1), pbEncodedKey, cbEncodedKey);
if (0 != dwKeySpec) {
// Get private key to use.
if (!CryptGetUserKey(
hCryptProv,
dwKeySpec,
&hUserKey)) {
hUserKey = 0;
goto GetUserKeyFailed;
}
}
// Try importing as an NT4.0 SP3 encypted key that wasn't byte
// reversed and with zero salt.
fResult = CryptImportKey(
hCryptProv,
pbCspKey,
cbCspKey,
hUserKey,
0, // dwFlags
&hEncryptKey);
if (!fResult && hUserKey) {
// Try without using the specified user key.
fResult = CryptImportKey(
hCryptProv,
pbCspKey,
cbCspKey,
0, // hUserKey
0, // dwFlags
&hEncryptKey);
}
if (!fResult)
goto ImportKeyFailed;
fResult = TRUE;
CommonReturn:
if (pbCspKey)
SP3Free(pbCspKey);
if (hUserKey) {
DWORD dwError = GetLastError();
CryptDestroyKey(hUserKey);
SetLastError(dwError);
}
DefaultImport:
if (!fResult && pfnDefaultImportEncryptKey)
// Try importing using the default
return pfnDefaultImportEncryptKey(
hCryptProv,
dwKeySpec,
paiEncrypt,
paiPubKey,
pbEncodedKey,
cbEncodedKey,
phEncryptKey);
else {
*phEncryptKey = hEncryptKey;
return fResult;
}
GetEncryptAlgidError:
OutOfMemory:
GetUserKeyFailed:
ImportKeyFailed:
hEncryptKey = 0;
fResult = FALSE;
goto CommonReturn;
}
//+-------------------------------------------------------------------------
// SP3 generation of the encryption key.
//
// The SP3 version of crypt32.dll didn't include the IV octet string for the
// encryption algorithm. Also, the encryption key had zero salt instead
// of no salt.
//
// For SP3 compatible generation, the caller must pass in a non-NULL
// hCryptProv and set pvEncryptAuxInfo to point to a
// CMSG_SP3_COMPATIBLE_AUX_INFO data structure with the
// CMSG_SP3_COMPATIBLE_ENCRYPT_FLAG set.
//--------------------------------------------------------------------------
BOOL
WINAPI
SP3GenEncryptKey(
IN OUT HCRYPTPROV *phCryptProv,
IN PCRYPT_ALGORITHM_IDENTIFIER paiEncrypt,
IN PVOID pvEncryptAuxInfo,
IN PCERT_PUBLIC_KEY_INFO pPublicKeyInfo,
IN PFN_CMSG_ALLOC pfnAlloc,
OUT HCRYPTKEY *phEncryptKey,
OUT PBYTE *ppbEncryptParameters,
OUT PDWORD pcbEncryptParameters
)
{
HCRYPTPROV hCryptProv;
PCMSG_SP3_COMPATIBLE_AUX_INFO pSP3AuxInfo =
(PCMSG_SP3_COMPATIBLE_AUX_INFO) pvEncryptAuxInfo;
PCCRYPT_OID_INFO pOIDInfo;
DWORD dwAlgIdEncrypt;
hCryptProv = *phCryptProv;
if (0 == hCryptProv || NULL == pSP3AuxInfo ||
sizeof(CMSG_SP3_COMPATIBLE_AUX_INFO) > pSP3AuxInfo->cbSize ||
0 == (pSP3AuxInfo->dwFlags & CMSG_SP3_COMPATIBLE_ENCRYPT_FLAG)) {
// Let SP3ExportEncryptKey() know this will be a default export
TlsSetValue(iSP3TLS, NULL);
if (pfnDefaultGenEncryptKey)
// Generate using the default
return pfnDefaultGenEncryptKey(
phCryptProv,
paiEncrypt,
pvEncryptAuxInfo,
pPublicKeyInfo,
pfnAlloc,
phEncryptKey,
ppbEncryptParameters,
pcbEncryptParameters
);
else {
// We don't have a default
*phEncryptKey = 0;
SetLastError((DWORD) E_UNEXPECTED);
return FALSE;
}
}
// Let SP3ExportEncryptKey() know this will be a SP3 compatible export.
TlsSetValue(iSP3TLS, SP3_TLS_POINTER);
// Map the ASN algorithm identifier to the CSP ALG_ID.
if (NULL == (pOIDInfo = CryptFindOIDInfo(
CRYPT_OID_INFO_OID_KEY,
paiEncrypt->pszObjId,
CRYPT_ENCRYPT_ALG_OID_GROUP_ID))) {
*phEncryptKey = 0;
return FALSE;
}
dwAlgIdEncrypt = pOIDInfo->Algid;
// Since CRYPT_NO_SALT flag isn't set, uses zero salt
if (!CryptGenKey(
hCryptProv,
dwAlgIdEncrypt,
CRYPT_EXPORTABLE,
phEncryptKey)) {
*phEncryptKey = 0;
return FALSE;
}
return TRUE;
}
//+-------------------------------------------------------------------------
// SP3 export of the encryption key.
//
// The SP3 version of crypt32.dll encoded the encrypted symmetric key as
// little endian instead of as big endian.
//--------------------------------------------------------------------------
BOOL
WINAPI
SP3ExportEncryptKey(
IN HCRYPTPROV hCryptProv,
IN HCRYPTKEY hEncryptKey,
IN PCERT_PUBLIC_KEY_INFO pPublicKeyInfo,
OUT PBYTE pbData,
IN OUT PDWORD pcbData
)
{
BOOL fResult;
DWORD dwError = ERROR_SUCCESS;
HCRYPTKEY hPubKey = NULL;
PBYTE pb = NULL;
DWORD cb;
if (SP3_TLS_POINTER != TlsGetValue(iSP3TLS)) {
if (pfnDefaultExportEncryptKey)
// Export using the default function
return pfnDefaultExportEncryptKey(
hCryptProv,
hEncryptKey,
pPublicKeyInfo,
pbData,
pcbData
);
else {
// We don't have a default
*pcbData = 0;
SetLastError((DWORD) E_UNEXPECTED);
return FALSE;
}
}
// SP3 compatible export and encode
if (!CryptImportPublicKeyInfo(
hCryptProv,
X509_ASN_ENCODING,
pPublicKeyInfo,
&hPubKey))
goto ImportKeyError;
if (!CryptExportKey(
hEncryptKey,
hPubKey,
SIMPLEBLOB,
0, // dwFlags
NULL,
&cb))
goto ExportKeySizeError;
if (NULL == (pb = (PBYTE) SP3Alloc(cb)))
goto ExportKeyAllocError;
if (!CryptExportKey(
hEncryptKey,
hPubKey,
SIMPLEBLOB,
0, // dwFlags
pb,
&cb))
goto ExportKeyError;
cb -= sizeof(PUBLICKEYSTRUC) + sizeof(SIMPLEBLOBHEADER);
fResult = TRUE;
if (pbData) {
if (*pcbData < cb) {
SetLastError((DWORD) ERROR_MORE_DATA);
fResult = FALSE;
} else if (0 < cb) {
// Don't byte reverse
memcpy(pbData,
pb + (sizeof(PUBLICKEYSTRUC) + sizeof(SIMPLEBLOBHEADER)), cb);
}
}
CommonReturn:
*pcbData = cb;
if (pb)
SP3Free(pb);
if (hPubKey)
CryptDestroyKey(hPubKey);
SetLastError(dwError);
return fResult;
ImportKeyError:
ExportKeySizeError:
ExportKeyAllocError:
ExportKeyError:
dwError = GetLastError();
cb = 0;
fResult = FALSE;
goto CommonReturn;
}
#ifdef CMS_PKCS7
BOOL
WINAPI
CryptMsgDllGenContentEncryptKey(
IN OUT PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo,
IN DWORD dwFlags,
IN OPTIONAL void *pvReserved
)
{
BOOL fResult;
HCRYPTOIDFUNCSET hGenContentFuncSet;
HCRYPTOIDFUNCADDR hFuncAddr;
PFN_CMSG_GEN_CONTENT_ENCRYPT_KEY pfnDefaultGenContent;
if (NULL == (hGenContentFuncSet = CryptInitOIDFunctionSet(
CMSG_OID_GEN_CONTENT_ENCRYPT_KEY_FUNC, 0)))
return FALSE;
// Get the default gen content encrypt key function which we will call
if (!CryptGetOIDFunctionAddress(
hGenContentFuncSet,
X509_ASN_ENCODING,
CMSG_DEFAULT_INSTALLABLE_FUNC_OID,
CRYPT_GET_INSTALLED_OID_FUNC_FLAG,
(void **) &pfnDefaultGenContent,
&hFuncAddr))
return FALSE;
fResult = pfnDefaultGenContent(
pContentEncryptInfo,
dwFlags,
pvReserved
);
CryptFreeOIDFunctionAddress(hFuncAddr, 0);
return fResult;
}
BOOL
WINAPI
CryptMsgDllExportKeyTrans(
IN PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo,
IN PCMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO pKeyTransEncodeInfo,
IN OUT PCMSG_KEY_TRANS_ENCRYPT_INFO pKeyTransEncryptInfo,
IN DWORD dwFlags,
IN OPTIONAL void *pvReserved
)
{
BOOL fResult;
HCRYPTOIDFUNCSET hExportKeyTransFuncSet;
HCRYPTOIDFUNCADDR hFuncAddr;
PFN_CMSG_EXPORT_KEY_TRANS pfnDefaultExportKeyTrans;
if (NULL == (hExportKeyTransFuncSet = CryptInitOIDFunctionSet(
CMSG_OID_EXPORT_KEY_TRANS_FUNC, 0)))
return FALSE;
// Get the default export key trans function which we will call
if (!CryptGetOIDFunctionAddress(
hExportKeyTransFuncSet,
X509_ASN_ENCODING,
CMSG_DEFAULT_INSTALLABLE_FUNC_OID,
CRYPT_GET_INSTALLED_OID_FUNC_FLAG,
(void **) &pfnDefaultExportKeyTrans,
&hFuncAddr))
return FALSE;
fResult = pfnDefaultExportKeyTrans(
pContentEncryptInfo,
pKeyTransEncodeInfo,
pKeyTransEncryptInfo,
dwFlags,
pvReserved
);
CryptFreeOIDFunctionAddress(hFuncAddr, 0);
return fResult;
}
BOOL
WINAPI
CryptMsgDllImportKeyTrans(
IN PCRYPT_ALGORITHM_IDENTIFIER pContentEncryptionAlgorithm,
IN PCMSG_CTRL_KEY_TRANS_DECRYPT_PARA pKeyTransDecryptPara,
IN DWORD dwFlags,
IN OPTIONAL void *pvReserved,
OUT HCRYPTKEY *phContentEncryptKey
)
{
BOOL fResult;
HCRYPTOIDFUNCSET hImportKeyTransFuncSet;
HCRYPTOIDFUNCADDR hFuncAddr;
PFN_CMSG_IMPORT_KEY_TRANS pfnDefaultImportKeyTrans;
if (NULL == (hImportKeyTransFuncSet = CryptInitOIDFunctionSet(
CMSG_OID_IMPORT_KEY_TRANS_FUNC, 0)))
return FALSE;
// Get the default import key trans function which we will call
if (!CryptGetOIDFunctionAddress(
hImportKeyTransFuncSet,
X509_ASN_ENCODING,
CMSG_DEFAULT_INSTALLABLE_FUNC_OID,
CRYPT_GET_INSTALLED_OID_FUNC_FLAG,
(void **) &pfnDefaultImportKeyTrans,
&hFuncAddr))
return FALSE;
fResult = pfnDefaultImportKeyTrans(
pContentEncryptionAlgorithm,
pKeyTransDecryptPara,
dwFlags,
pvReserved,
phContentEncryptKey
);
CryptFreeOIDFunctionAddress(hFuncAddr, 0);
return fResult;
}
BOOL
WINAPI
NotImplCryptMsgDllImportKeyTrans(
IN PCRYPT_ALGORITHM_IDENTIFIER pContentEncryptionAlgorithm,
IN PCMSG_CTRL_KEY_TRANS_DECRYPT_PARA pKeyTransDecryptPara,
IN DWORD dwFlags,
IN OPTIONAL void *pvReserved,
OUT HCRYPTKEY *phContentEncryptKey
)
{
SetLastError((DWORD) E_NOTIMPL);
return FALSE;
}
#endif // CMS_PKCS7