From 67a0432e6d2780fd8032b2437ada80363615de8e Mon Sep 17 00:00:00 2001 From: Alexander Morozov Date: Wed, 18 Aug 2010 18:50:11 +0400 Subject: [PATCH] crypt32: Add support for PFN_CMSG_GEN_CONTENT_ENCRYPT_KEY and PFN_CMSG_EXPORT_KEY_TRANS (eterbug #5694). --- dlls/crypt32/msg.c | 260 ++++++++++++++++++++++++++++++++++++++++----- include/wincrypt.h | 37 +++++++ 2 files changed, 271 insertions(+), 26 deletions(-) diff --git a/dlls/crypt32/msg.c b/dlls/crypt32/msg.c index 7d19f4049c..22c616ee9a 100644 --- a/dlls/crypt32/msg.c +++ b/dlls/crypt32/msg.c @@ -1517,51 +1517,90 @@ static BOOL CRYPT_ConstructAlgorithmId(CRYPT_ALGORITHM_IDENTIFIER *out, return FALSE; } -static BOOL CRecipientInfo_Construct(CMSG_KEY_TRANS_RECIPIENT_INFO *info, - const CERT_INFO *cert, HCRYPTPROV prov, HCRYPTKEY key) +static BOOL CRYPT_ConstructBitBlob(CRYPT_BIT_BLOB *out, const CRYPT_BIT_BLOB *in) { + out->cbData = in->cbData; + out->cUnusedBits = in->cUnusedBits; + if (out->cbData) + { + out->pbData = CryptMemAlloc(out->cbData); + if (out->pbData) + memcpy(out->pbData, in->pbData, out->cbData); + else + return FALSE; + } + else + out->pbData = NULL; + return TRUE; +} + +static BOOL CRYPT_GenKey(CMSG_CONTENT_ENCRYPT_INFO *info, ALG_ID algID) +{ + static HCRYPTOIDFUNCSET set = NULL; + PFN_CMSG_GEN_CONTENT_ENCRYPT_KEY genKeyFunc = NULL; + HCRYPTOIDFUNCADDR hFunc; + BOOL ret; + + if (!set) + set = CryptInitOIDFunctionSet(CMSG_OID_GEN_CONTENT_ENCRYPT_KEY_FUNC, 0); + CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, + info->ContentEncryptionAlgorithm.pszObjId, 0, (void **)&genKeyFunc, &hFunc); + if (genKeyFunc) + { + ret = genKeyFunc(info, 0, NULL); + CryptFreeOIDFunctionAddress(hFunc, 0); + } + else + ret = CryptGenKey(info->hCryptProv, algID, CRYPT_EXPORTABLE, + &info->hContentEncryptKey); + return ret; +} + +static BOOL WINAPI CRYPT_ExportKeyTrans( + PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo, + PCMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO pKeyTransEncodeInfo, + PCMSG_KEY_TRANS_ENCRYPT_INFO pKeyTransEncryptInfo, + DWORD dwFlags, void *pvReserved) +{ + CERT_PUBLIC_KEY_INFO keyInfo; HCRYPTKEY expKey; - BOOL ret = TRUE; + BOOL ret; - info->dwVersion = CMSG_KEY_TRANS_PKCS_1_5_VERSION; - info->RecipientId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER; - ret = CRYPT_ConstructBlob(&info->RecipientId.u.IssuerSerialNumber.Issuer, - &cert->Issuer); + ret = CRYPT_ConstructAlgorithmId(&keyInfo.Algorithm, + &pKeyTransEncodeInfo->KeyEncryptionAlgorithm); if (ret) - ret = CRYPT_ConstructBlob( - &info->RecipientId.u.IssuerSerialNumber.SerialNumber, - &cert->SerialNumber); - if (ret) - ret = CRYPT_ConstructAlgorithmId(&info->KeyEncryptionAlgorithm, - &cert->SubjectPublicKeyInfo.Algorithm); - info->EncryptedKey.cbData = 0; - info->EncryptedKey.pbData = NULL; + CRYPT_ConstructBitBlob(&keyInfo.PublicKey, + &pKeyTransEncodeInfo->RecipientPublicKey); if (ret) - ret = CryptImportPublicKeyInfo(prov, X509_ASN_ENCODING, - (PCERT_PUBLIC_KEY_INFO)&cert->SubjectPublicKeyInfo, &expKey); + ret = CryptImportPublicKeyInfo(pKeyTransEncodeInfo->hCryptProv, + X509_ASN_ENCODING, &keyInfo, &expKey); if (ret) { BYTE *keyBlob; DWORD size; - ret = CryptExportKey(key, expKey, SIMPLEBLOB, 0, NULL, &size); + ret = CryptExportKey(pContentEncryptInfo->hContentEncryptKey, expKey, + SIMPLEBLOB, 0, NULL, &size); keyBlob = CryptMemAlloc(size); if (keyBlob) { - ret = CryptExportKey(key, expKey, SIMPLEBLOB, 0, keyBlob, &size); + ret = CryptExportKey(pContentEncryptInfo->hContentEncryptKey, + expKey, SIMPLEBLOB, 0, keyBlob, &size); if (ret) { DWORD head = sizeof(BLOBHEADER) + sizeof(ALG_ID); - info->EncryptedKey.pbData = CryptMemAlloc(size - head); - if (info->EncryptedKey.pbData) + pKeyTransEncryptInfo->EncryptedKey.pbData = + CryptMemAlloc(size - head); + if (pKeyTransEncryptInfo->EncryptedKey.pbData) { DWORD i, k = 0; - info->EncryptedKey.cbData = size - head; + pKeyTransEncryptInfo->EncryptedKey.cbData = size - head; for (i = size - 1; i >= head; --i, ++k) - info->EncryptedKey.pbData[k] = keyBlob[i]; + pKeyTransEncryptInfo->EncryptedKey.pbData[k] = + keyBlob[i]; } else ret = FALSE; @@ -1572,6 +1611,158 @@ static BOOL CRecipientInfo_Construct(CMSG_KEY_TRANS_RECIPIENT_INFO *info, ret = FALSE; CryptDestroyKey(expKey); } + + CryptMemFree(keyInfo.Algorithm.pszObjId); + CryptMemFree(keyInfo.Algorithm.Parameters.pbData); + return ret; +} + +static BOOL CRYPT_ExportEncryptedKey(CMSG_CONTENT_ENCRYPT_INFO *info, DWORD i, + CRYPT_DATA_BLOB *key) +{ + static HCRYPTOIDFUNCSET set = NULL; + PFN_CMSG_EXPORT_KEY_TRANS exportKeyFunc = NULL; + HCRYPTOIDFUNCADDR hFunc = NULL; + CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO *encodeInfo = + info->rgCmsRecipients[i].u.pKeyTrans; + CMSG_KEY_TRANS_ENCRYPT_INFO encryptInfo; + BOOL ret; + + memset(&encryptInfo, 0, sizeof(encryptInfo)); + encryptInfo.cbSize = sizeof(encryptInfo); + encryptInfo.dwRecipientIndex = i; + ret = CRYPT_ConstructAlgorithmId(&encryptInfo.KeyEncryptionAlgorithm, + &encodeInfo->KeyEncryptionAlgorithm); + + if (!set) + set = CryptInitOIDFunctionSet(CMSG_OID_EXPORT_KEY_TRANS_FUNC, 0); + CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, + encryptInfo.KeyEncryptionAlgorithm.pszObjId, 0, (void **)&exportKeyFunc, + &hFunc); + if (!exportKeyFunc) + exportKeyFunc = CRYPT_ExportKeyTrans; + if (ret) + { + ret = exportKeyFunc(info, encodeInfo, &encryptInfo, 0, NULL); + if (ret) + { + key->cbData = encryptInfo.EncryptedKey.cbData; + key->pbData = encryptInfo.EncryptedKey.pbData; + } + } + if (hFunc) + CryptFreeOIDFunctionAddress(hFunc, 0); + + CryptMemFree(encryptInfo.KeyEncryptionAlgorithm.pszObjId); + CryptMemFree(encryptInfo.KeyEncryptionAlgorithm.Parameters.pbData); + return ret; +} + +static BOOL CContentEncryptInfo_Construct(CMSG_CONTENT_ENCRYPT_INFO *info, + const CMSG_ENVELOPED_ENCODE_INFO_WITH_CMS *in, HCRYPTPROV prov) +{ + BOOL ret; + + info->cbSize = sizeof(CMSG_CONTENT_ENCRYPT_INFO); + info->hCryptProv = prov; + ret = CRYPT_ConstructAlgorithmId(&info->ContentEncryptionAlgorithm, + &in->ContentEncryptionAlgorithm); + info->pvEncryptionAuxInfo = in->pvEncryptionAuxInfo; + info->cRecipients = in->cRecipients; + if (ret) + { + info->rgCmsRecipients = CryptMemAlloc(in->cRecipients * + sizeof(CMSG_RECIPIENT_ENCODE_INFO)); + if (info->rgCmsRecipients) + { + DWORD i; + + for (i = 0; ret && i < in->cRecipients; ++i) + { + CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO *encodeInfo; + CERT_INFO *cert = in->rgpRecipientCert[i]; + + info->rgCmsRecipients[i].dwRecipientChoice = + CMSG_KEY_TRANS_RECIPIENT; + encodeInfo = CryptMemAlloc(sizeof(*encodeInfo)); + info->rgCmsRecipients[i].u.pKeyTrans = encodeInfo; + if (encodeInfo) + { + encodeInfo->cbSize = sizeof(*encodeInfo); + ret = CRYPT_ConstructAlgorithmId( + &encodeInfo->KeyEncryptionAlgorithm, + &cert->SubjectPublicKeyInfo.Algorithm); + encodeInfo->pvKeyEncryptionAuxInfo = NULL; + encodeInfo->hCryptProv = prov; + if (ret) + ret = CRYPT_ConstructBitBlob( + &encodeInfo->RecipientPublicKey, + &cert->SubjectPublicKeyInfo.PublicKey); + if (ret) + ret = CRYPT_ConstructBlob( + &encodeInfo->RecipientId.u.IssuerSerialNumber.Issuer, + &cert->Issuer); + if (ret) + ret = CRYPT_ConstructBlob( + &encodeInfo->RecipientId.u.IssuerSerialNumber.SerialNumber, + &cert->SerialNumber); + } + else + ret = FALSE; + } + } + else + ret = FALSE; + } + info->pfnAlloc = CryptMemAlloc; + info->pfnFree = CryptMemFree; + return ret; +} + +static void CContentEncryptInfo_Free(CMSG_CONTENT_ENCRYPT_INFO *info) +{ + CryptMemFree(info->ContentEncryptionAlgorithm.pszObjId); + CryptMemFree(info->ContentEncryptionAlgorithm.Parameters.pbData); + if (info->rgCmsRecipients) + { + DWORD i; + + for (i = 0; i < info->cRecipients; ++i) + { + CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO *encodeInfo = + info->rgCmsRecipients[i].u.pKeyTrans; + + CryptMemFree(encodeInfo->KeyEncryptionAlgorithm.pszObjId); + CryptMemFree(encodeInfo->KeyEncryptionAlgorithm.Parameters.pbData); + CryptMemFree(encodeInfo->RecipientPublicKey.pbData); + CryptMemFree( + encodeInfo->RecipientId.u.IssuerSerialNumber.Issuer.pbData); + CryptMemFree( + encodeInfo->RecipientId.u.IssuerSerialNumber.SerialNumber.pbData); + CryptMemFree(encodeInfo); + } + CryptMemFree(info->rgCmsRecipients); + } +} + +static BOOL CRecipientInfo_Construct(CMSG_KEY_TRANS_RECIPIENT_INFO *info, + const CERT_INFO *cert, CRYPT_DATA_BLOB *key) +{ + BOOL ret; + + info->dwVersion = CMSG_KEY_TRANS_PKCS_1_5_VERSION; + info->RecipientId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER; + ret = CRYPT_ConstructBlob(&info->RecipientId.u.IssuerSerialNumber.Issuer, + &cert->Issuer); + if (ret) + ret = CRYPT_ConstructBlob( + &info->RecipientId.u.IssuerSerialNumber.SerialNumber, + &cert->SerialNumber); + if (ret) + ret = CRYPT_ConstructAlgorithmId(&info->KeyEncryptionAlgorithm, + &cert->SubjectPublicKeyInfo.Algorithm); + info->EncryptedKey.cbData = key->cbData; + info->EncryptedKey.pbData = key->pbData; return ret; } @@ -1768,6 +1959,7 @@ static HCRYPTMSG CEnvelopedEncodeMsg_Open(DWORD dwFlags, msg = CryptMemAlloc(sizeof(CEnvelopedEncodeMsg)); if (msg) { + CMSG_CONTENT_ENCRYPT_INFO encryptInfo; BOOL ret; DWORD i; @@ -1784,11 +1976,27 @@ static HCRYPTMSG CEnvelopedEncodeMsg_Open(DWORD dwFlags, sizeof(CMSG_KEY_TRANS_RECIPIENT_INFO)); if (!msg->recipientInfo) ret = FALSE; + memset(&encryptInfo, 0, sizeof(encryptInfo)); if (ret) - ret = CryptGenKey(prov, algID, CRYPT_EXPORTABLE, &msg->key); + { + ret = CContentEncryptInfo_Construct(&encryptInfo, info, prov); + if (ret) + { + ret = CRYPT_GenKey(&encryptInfo, algID); + if (ret) + msg->key = encryptInfo.hContentEncryptKey; + } + } for (i = 0; ret && i < msg->cRecipientInfo; ++i) - ret = CRecipientInfo_Construct(&msg->recipientInfo[i], - info->rgpRecipientCert[i], prov, msg->key); + { + CRYPT_DATA_BLOB encryptedKey; + + ret = CRYPT_ExportEncryptedKey(&encryptInfo, i, &encryptedKey); + if (ret) + ret = CRecipientInfo_Construct(&msg->recipientInfo[i], + info->rgpRecipientCert[i], &encryptedKey); + } + CContentEncryptInfo_Free(&encryptInfo); if (!ret) { CryptMsgClose(msg); diff --git a/include/wincrypt.h b/include/wincrypt.h index af2ddcbb7b..92a11ec0cc 100644 --- a/include/wincrypt.h +++ b/include/wincrypt.h @@ -2274,6 +2274,8 @@ static const WCHAR CERT_TRUST_PUB_AUTHENTICODE_FLAGS_VALUE_NAME[] = #define CRYPT_OID_CONVERT_PUBLIC_KEY_INFO_FUNC "CryptDllConvertPublicKeyInfo" #define URL_OID_GET_OBJECT_URL_FUNC "UrlDllGetObjectUrl" #define TIME_VALID_OID_GET_OBJECT_FUNC "TimeValidDllGetObject" +#define CMSG_OID_GEN_CONTENT_ENCRYPT_KEY_FUNC "CryptMsgDllGenContentEncryptKey" +#define CMSG_OID_EXPORT_KEY_TRANS_FUNC "CryptMsgDllExportKeyTrans" #define CRYPT_OID_REGPATH "Software\\Microsoft\\Cryptography\\OID" #define CRYPT_OID_REG_ENCODING_TYPE_PREFIX "EncodingType " @@ -3773,6 +3775,41 @@ typedef struct _CMSG_CMS_RECIPIENT_INFO { #define CMSG_KEY_AGREE_VERSION CMSG_ENVELOPED_RECIPIENT_V3 #define CMSG_MAIL_LIST_VERSION CMSG_ENVELOPED_RECIPIENT_V4 +typedef void * (WINAPI *PFN_CMSG_ALLOC)(size_t cb); +typedef void (WINAPI *PFN_CMSG_FREE)(void *pv); + +typedef struct _CMSG_CONTENT_ENCRYPT_INFO { + DWORD cbSize; + HCRYPTPROV hCryptProv; + CRYPT_ALGORITHM_IDENTIFIER ContentEncryptionAlgorithm; + void *pvEncryptionAuxInfo; + DWORD cRecipients; + PCMSG_RECIPIENT_ENCODE_INFO rgCmsRecipients; + PFN_CMSG_ALLOC pfnAlloc; + PFN_CMSG_FREE pfnFree; + DWORD dwEncryptFlags; + HCRYPTKEY hContentEncryptKey; + DWORD dwFlags; +} CMSG_CONTENT_ENCRYPT_INFO, *PCMSG_CONTENT_ENCRYPT_INFO; + +typedef struct _CMSG_KEY_TRANS_ENCRYPT_INFO { + DWORD cbSize; + DWORD dwRecipientIndex; + CRYPT_ALGORITHM_IDENTIFIER KeyEncryptionAlgorithm; + CRYPT_DATA_BLOB EncryptedKey; + DWORD dwFlags; +} CMSG_KEY_TRANS_ENCRYPT_INFO, *PCMSG_KEY_TRANS_ENCRYPT_INFO; + +typedef BOOL (WINAPI *PFN_CMSG_GEN_CONTENT_ENCRYPT_KEY)( + PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo, DWORD dwFlags, + void *pvReserved); + +typedef BOOL (WINAPI *PFN_CMSG_EXPORT_KEY_TRANS)( + PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo, + PCMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO pKeyTransEncodeInfo, + PCMSG_KEY_TRANS_ENCRYPT_INFO pKeyTransEncryptInfo, + DWORD dwFlags, void *pvReserved); + /* CryptMsgGetAndVerifySigner flags */ #define CMSG_TRUSTED_SIGNER_FLAG 0x1 #define CMSG_SIGNER_ONLY_FLAG 0x2 -- 2.33.8