crypt32: Add support for PFN_CMSG_GEN_CONTENT_ENCRYPT_KEY and PFN_CMSG_EXPORT_KEY_TRA...
authorAlexander Morozov <amorozov@etersoft.ru>
Wed, 18 Aug 2010 14:50:11 +0000 (18:50 +0400)
committerAlexander Morozov <amorozov@etersoft.ru>
Wed, 18 Aug 2010 14:50:11 +0000 (18:50 +0400)
dlls/crypt32/msg.c
include/wincrypt.h

index 7d19f4049ca2850b09c5b1d685703773fb1d4c2b..22c616ee9a1fb265bc3617b1f729c89424a06e4f 100644 (file)
@@ -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);
index 04323171ccc9d2557453fc120eac9b25a36eae91..7ae4c5d90417898d7a53dc615a22a33f584a555f 100644 (file)
@@ -2261,6 +2261,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 "
@@ -3769,6 +3771,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