[Wine-devel] Eter's patch is applied to winehq repo 12/02/10

builder на builder.office.etersoft.ru builder на builder.office.etersoft.ru
Чт Дек 2 22:20:40 MSK 2010


New Etersoft's patches since last build time:
commit 6ad5416f32dae5e436a55d1a6fac871d533abf30
Author: Alexander Morozov <amorozov на etersoft.ru>

    crypt32: Implement getting content of an enveloped message.

commit 03e94320c21cabf503a2eae2175d6a1989aebdcc
Author: Alexander Morozov <amorozov на etersoft.ru>

    crypt32: Implement updating enveloped messages.

commit c3a2f7a3d1e6c98e2ee97cede11fbefa4a40b053
Author: Alexander Morozov <amorozov на etersoft.ru>

    crypt32: Save some info needed for creating enveloped messages.

commit 1de62294899212f7e6d26cff235246f3c8013085
Author: Alexander Morozov <amorozov на etersoft.ru>

    wincrypt.h: Define some enveloped message callback functions.

---

commit 6ad5416f32dae5e436a55d1a6fac871d533abf30
Author: Alexander Morozov <amorozov на etersoft.ru>
Date:   Wed Dec 1 14:40:27 2010 +0300

    crypt32: Implement getting content of an enveloped message.

diff --git a/dlls/crypt32/crypt32_private.h b/dlls/crypt32/crypt32_private.h
index 36ee3e2..a4b9aff 100644
--- a/dlls/crypt32/crypt32_private.h
+++ b/dlls/crypt32/crypt32_private.h
@@ -82,6 +82,24 @@ typedef struct _CRYPT_DIGESTED_DATA
 BOOL CRYPT_AsnEncodePKCSDigestedData(const CRYPT_DIGESTED_DATA *digestedData,
  void *pvData, DWORD *pcbData);
 
+typedef struct _CRYPT_ENCRYPTED_CONTENT_INFO
+{
+    LPSTR                      contentType;
+    CRYPT_ALGORITHM_IDENTIFIER contentEncryptionAlgorithm;
+    CRYPT_DATA_BLOB            encryptedContent;
+} CRYPT_ENCRYPTED_CONTENT_INFO;
+
+typedef struct _CRYPT_ENVELOPED_DATA
+{
+    DWORD                          version;
+    DWORD                          cRecipientInfo;
+    PCMSG_KEY_TRANS_RECIPIENT_INFO rgRecipientInfo;
+    CRYPT_ENCRYPTED_CONTENT_INFO   encryptedContentInfo;
+} CRYPT_ENVELOPED_DATA;
+
+BOOL CRYPT_AsnEncodePKCSEnvelopedData(const CRYPT_ENVELOPED_DATA *envelopedData,
+ void *pvData, DWORD *pcbData);
+
 typedef struct _CRYPT_SIGNED_INFO
 {
     DWORD                 version;
diff --git a/dlls/crypt32/encode.c b/dlls/crypt32/encode.c
index 3beab84..5d6affe 100644
--- a/dlls/crypt32/encode.c
+++ b/dlls/crypt32/encode.c
@@ -4293,6 +4293,61 @@ BOOL CRYPT_AsnEncodeCMSSignedInfo(CRYPT_SIGNED_INFO *signedInfo, void *pvData,
     return ret;
 }
 
+static BOOL WINAPI CRYPT_AsnEncodeRecipientInfo(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
+ PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
+{
+    const CMSG_KEY_TRANS_RECIPIENT_INFO *info = pvStructInfo;
+    struct AsnEncodeSequenceItem items[] = {
+     { &info->dwVersion, CRYPT_AsnEncodeInt, 0 },
+     { &info->RecipientId.u.IssuerSerialNumber,
+       CRYPT_AsnEncodeIssuerSerialNumber, 0 },
+     { &info->KeyEncryptionAlgorithm,
+       CRYPT_AsnEncodeAlgorithmIdWithNullParams, 0 },
+     { &info->EncryptedKey, CRYPT_AsnEncodeOctets, 0 },
+    };
+
+    return CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
+     sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
+     pcbEncoded);
+}
+
+static BOOL WINAPI CRYPT_AsnEncodeEncryptedContentInfo(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
+ PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
+{
+    const CRYPT_ENCRYPTED_CONTENT_INFO *info = pvStructInfo;
+    struct AsnEncodeTagSwappedItem swapped = { ASN_CONTEXT | 0,
+     &info->encryptedContent, CRYPT_AsnEncodeOctets };
+    struct AsnEncodeSequenceItem items[] = {
+     { info->contentType, CRYPT_AsnEncodeOid, 0 },
+     { &info->contentEncryptionAlgorithm,
+       CRYPT_AsnEncodeAlgorithmIdWithNullParams, 0 },
+     { &swapped, CRYPT_AsnEncodeSwapTag, 0 },
+    };
+
+    return CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
+     sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
+     pcbEncoded);
+}
+
+BOOL CRYPT_AsnEncodePKCSEnvelopedData(const CRYPT_ENVELOPED_DATA *envelopedData,
+ void *pvData, DWORD *pcbData)
+{
+    struct DERSetDescriptor recipientInfosSet = { envelopedData->cRecipientInfo,
+     envelopedData->rgRecipientInfo, sizeof(CMSG_KEY_TRANS_RECIPIENT_INFO), 0,
+     CRYPT_AsnEncodeRecipientInfo };
+    struct AsnEncodeSequenceItem items[] = {
+     { &envelopedData->version, CRYPT_AsnEncodeInt, 0 },
+     { &recipientInfosSet, CRYPT_DEREncodeItemsAsSet, 0 },
+     { &envelopedData->encryptedContentInfo,
+       CRYPT_AsnEncodeEncryptedContentInfo, 0 },
+    };
+
+    return CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items,
+     sizeof(items) / sizeof(items[0]), 0, NULL, pvData, pcbData);
+}
+
 static CryptEncodeObjectExFunc CRYPT_GetBuiltinEncoder(DWORD dwCertEncodingType,
  LPCSTR lpszStructType)
 {
diff --git a/dlls/crypt32/msg.c b/dlls/crypt32/msg.c
index 2b93a5b..f083c53 100644
--- a/dlls/crypt32/msg.c
+++ b/dlls/crypt32/msg.c
@@ -1785,9 +1785,58 @@ static void CEnvelopedEncodeMsg_Close(HCRYPTMSG hCryptMsg)
 static BOOL CEnvelopedEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
  DWORD dwIndex, void *pvData, DWORD *pcbData)
 {
-    FIXME("(%p, %d, %d, %p, %p): stub\n", hCryptMsg, dwParamType, dwIndex,
-     pvData, pcbData);
-    return FALSE;
+    CEnvelopedEncodeMsg *msg = hCryptMsg;
+    BOOL ret = FALSE;
+
+    switch (dwParamType)
+    {
+    case CMSG_BARE_CONTENT_PARAM:
+        if (msg->base.streamed)
+            SetLastError(E_INVALIDARG);
+        else
+        {
+            char oid_rsa_data[] = szOID_RSA_data;
+            CRYPT_ENVELOPED_DATA envelopedData = {
+             CMSG_ENVELOPED_DATA_PKCS_1_5_VERSION, msg->cRecipientInfo,
+             msg->recipientInfo, { oid_rsa_data, msg->algo, msg->data }
+            };
+
+            ret = CRYPT_AsnEncodePKCSEnvelopedData(&envelopedData, pvData,
+             pcbData);
+        }
+        break;
+    case CMSG_CONTENT_PARAM:
+    {
+        CRYPT_CONTENT_INFO info;
+
+        ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0, NULL,
+         &info.Content.cbData);
+        if (ret)
+        {
+            info.Content.pbData = CryptMemAlloc(info.Content.cbData);
+            if (info.Content.pbData)
+            {
+                ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0,
+                 info.Content.pbData, &info.Content.cbData);
+                if (ret)
+                {
+                    char oid_rsa_enveloped[] = szOID_RSA_envelopedData;
+
+                    info.pszObjId = oid_rsa_enveloped;
+                    ret = CryptEncodeObjectEx(X509_ASN_ENCODING,
+                     PKCS_CONTENT_INFO, &info, 0, NULL, pvData, pcbData);
+                }
+                CryptMemFree(info.Content.pbData);
+            }
+            else
+                ret = FALSE;
+        }
+        break;
+    }
+    default:
+        SetLastError(CRYPT_E_INVALID_MSG_TYPE);
+    }
+    return ret;
 }
 
 static BOOL CEnvelopedEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
diff --git a/dlls/crypt32/tests/msg.c b/dlls/crypt32/tests/msg.c
index 9ffae52..e32690b 100644
--- a/dlls/crypt32/tests/msg.c
+++ b/dlls/crypt32/tests/msg.c
@@ -2248,11 +2248,9 @@ static void test_enveloped_msg_encoding(void)
      "CryptMsgOpenToEncode failed: %08x\n", GetLastError());
     if (msg)
     {
-        todo_wine
         check_param("enveloped empty bare content", msg,
          CMSG_BARE_CONTENT_PARAM, envelopedEmptyBareContent,
          sizeof(envelopedEmptyBareContent));
-        todo_wine
         check_param("enveloped empty content", msg, CMSG_CONTENT_PARAM,
          envelopedEmptyContent, sizeof(envelopedEmptyContent));
         CryptMsgClose(msg);

commit 03e94320c21cabf503a2eae2175d6a1989aebdcc
Author: Alexander Morozov <amorozov на etersoft.ru>
Date:   Wed Dec 1 14:36:02 2010 +0300

    crypt32: Implement updating enveloped messages.

diff --git a/dlls/crypt32/msg.c b/dlls/crypt32/msg.c
index 1ca4d0e..2b93a5b 100644
--- a/dlls/crypt32/msg.c
+++ b/dlls/crypt32/msg.c
@@ -1793,8 +1793,70 @@ static BOOL CEnvelopedEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
 static BOOL CEnvelopedEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
  DWORD cbData, BOOL fFinal)
 {
-    FIXME("(%p, %p, %d, %d): stub\n", hCryptMsg, pbData, cbData, fFinal);
-    return FALSE;
+    CEnvelopedEncodeMsg *msg = hCryptMsg;
+    BOOL ret = FALSE;
+
+    if (msg->base.state == MsgStateFinalized)
+        SetLastError(CRYPT_E_MSG_ERROR);
+    else if (msg->base.streamed)
+    {
+        FIXME("streamed stub\n");
+        msg->base.state = fFinal ? MsgStateFinalized : MsgStateUpdated;
+        ret = TRUE;
+    }
+    else
+    {
+        if (!fFinal)
+        {
+            if (msg->base.open_flags & CMSG_DETACHED_FLAG)
+                SetLastError(E_INVALIDARG);
+            else
+                SetLastError(CRYPT_E_MSG_ERROR);
+        }
+        else
+        {
+            if (cbData)
+            {
+                DWORD dataLen = cbData;
+
+                msg->data.cbData = cbData;
+                msg->data.pbData = CryptMemAlloc(cbData);
+                if (msg->data.pbData)
+                {
+                    memcpy(msg->data.pbData, pbData, cbData);
+                    ret = CryptEncrypt(msg->key, 0, TRUE, 0, msg->data.pbData,
+                     &dataLen, msg->data.cbData);
+                    msg->data.cbData = dataLen;
+                    if (dataLen > cbData)
+                    {
+                        msg->data.pbData = CryptMemRealloc(msg->data.pbData,
+                         dataLen);
+                        if (msg->data.pbData)
+                        {
+                            dataLen = cbData;
+                            ret = CryptEncrypt(msg->key, 0, TRUE, 0,
+                             msg->data.pbData, &dataLen, msg->data.cbData);
+                        }
+                        else
+                            ret = FALSE;
+                    }
+                    if (!ret)
+                        CryptMemFree(msg->data.pbData);
+                }
+                else
+                    ret = FALSE;
+                if (!ret)
+                {
+                    msg->data.cbData = 0;
+                    msg->data.pbData = NULL;
+                }
+            }
+            else
+                ret = TRUE;
+            msg->base.state = MsgStateFinalized;
+        }
+    }
+    return ret;
 }
 
 static HCRYPTMSG CEnvelopedEncodeMsg_Open(DWORD dwFlags,
diff --git a/dlls/crypt32/tests/msg.c b/dlls/crypt32/tests/msg.c
index fb7a7c2..9ffae52 100644
--- a/dlls/crypt32/tests/msg.c
+++ b/dlls/crypt32/tests/msg.c
@@ -2118,16 +2118,13 @@ static void test_enveloped_msg_update(void)
     {
         SetLastError(0xdeadbeef);
         ret = CryptMsgUpdate(msg, NULL, 0, FALSE);
-        todo_wine
         ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
          "expected CRYPT_E_MSG_ERROR, got %08x\n", GetLastError());
         SetLastError(0xdeadbeef);
         ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
-        todo_wine
         ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError());
         SetLastError(0xdeadbeef);
         ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
-        todo_wine
         ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
          "expected CRYPT_E_MSG_ERROR, got %08x\n", GetLastError());
         CryptMsgClose(msg);
@@ -2142,18 +2139,15 @@ static void test_enveloped_msg_update(void)
     {
         SetLastError(0xdeadbeef);
         ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
-        todo_wine
         ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
          "expected CRYPT_E_MSG_ERROR, got %08x\n", GetLastError());
         SetLastError(0xdeadbeef);
         ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
-        todo_wine
         ok(ret ||
          broken(!ret && GetLastError() == NTE_PERM), /* some NT4 */
          "CryptMsgUpdate failed: %08x\n", GetLastError());
         SetLastError(0xdeadbeef);
         ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
-        todo_wine
         ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
          "expected CRYPT_E_MSG_ERROR, got %08x\n", GetLastError());
         CryptMsgClose(msg);
@@ -2168,12 +2162,10 @@ static void test_enveloped_msg_update(void)
     {
         SetLastError(0xdeadbeef);
         ret = CryptMsgUpdate(msg, NULL, 0, FALSE);
-        todo_wine
         ok(!ret && GetLastError() == E_INVALIDARG,
          "expected E_INVALIDARG, got %08x\n", GetLastError());
         SetLastError(0xdeadbeef);
         ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
-        todo_wine
         ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError());
         CryptMsgClose(msg);
     }
@@ -2187,12 +2179,10 @@ static void test_enveloped_msg_update(void)
     {
         SetLastError(0xdeadbeef);
         ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
-        todo_wine
         ok(!ret && GetLastError() == E_INVALIDARG,
          "expected E_INVALIDARG, got %08x\n", GetLastError());
         SetLastError(0xdeadbeef);
         ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
-        todo_wine
         ok(ret ||
          broken(!ret && GetLastError() == NTE_PERM), /* some NT4 */
          "CryptMsgUpdate failed: %08x\n", GetLastError());
@@ -2208,11 +2198,9 @@ static void test_enveloped_msg_update(void)
     {
         SetLastError(0xdeadbeef);
         ret = CryptMsgUpdate(msg, NULL, 0, FALSE);
-        todo_wine
         ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError());
         SetLastError(0xdeadbeef);
         ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
-        todo_wine
         ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError());
         CryptMsgClose(msg);
     }
@@ -2226,11 +2214,9 @@ static void test_enveloped_msg_update(void)
     {
         SetLastError(0xdeadbeef);
         ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
-        todo_wine
         ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError());
         SetLastError(0xdeadbeef);
         ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
-        todo_wine
         ok(ret ||
          broken(!ret && GetLastError() == NTE_PERM), /* some NT4 */
          "CryptMsgUpdate failed: %08x\n", GetLastError());

commit c3a2f7a3d1e6c98e2ee97cede11fbefa4a40b053
Author: Alexander Morozov <amorozov на etersoft.ru>
Date:   Wed Dec 1 14:26:17 2010 +0300

    crypt32: Save some info needed for creating enveloped messages.

diff --git a/dlls/crypt32/msg.c b/dlls/crypt32/msg.c
index b31562b..1ca4d0e 100644
--- a/dlls/crypt32/msg.c
+++ b/dlls/crypt32/msg.c
@@ -1483,15 +1483,303 @@ typedef struct _CMSG_ENVELOPED_ENCODE_INFO_WITH_CMS
 typedef struct _CEnvelopedEncodeMsg
 {
     CryptMsgBase                   base;
+    CRYPT_ALGORITHM_IDENTIFIER     algo;
     HCRYPTPROV                     prov;
+    HCRYPTKEY                      key;
+    DWORD                          cRecipientInfo;
+    CMSG_KEY_TRANS_RECIPIENT_INFO *recipientInfo;
+    CRYPT_DATA_BLOB                data;
 } CEnvelopedEncodeMsg;
 
+static BOOL CRYPT_ConstructAlgorithmId(CRYPT_ALGORITHM_IDENTIFIER *out,
+ const CRYPT_ALGORITHM_IDENTIFIER *in)
+{
+    out->pszObjId = CryptMemAlloc(strlen(in->pszObjId) + 1);
+    if (out->pszObjId)
+    {
+        strcpy(out->pszObjId, in->pszObjId);
+        return CRYPT_ConstructBlob(&out->Parameters, &in->Parameters);
+    }
+    else
+        return FALSE;
+}
+
+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;
+
+    ret = CRYPT_ConstructAlgorithmId(&keyInfo.Algorithm,
+        &pKeyTransEncodeInfo->KeyEncryptionAlgorithm);
+    if (ret)
+        CRYPT_ConstructBitBlob(&keyInfo.PublicKey,
+         &pKeyTransEncodeInfo->RecipientPublicKey);
+
+    if (ret)
+        ret = CryptImportPublicKeyInfo(pKeyTransEncodeInfo->hCryptProv,
+         X509_ASN_ENCODING, &keyInfo, &expKey);
+    if (ret)
+    {
+        BYTE *keyBlob;
+        DWORD size;
+
+        ret = CryptExportKey(pContentEncryptInfo->hContentEncryptKey, expKey,
+         SIMPLEBLOB, 0, NULL, &size);
+        keyBlob = CryptMemAlloc(size);
+        if (keyBlob)
+        {
+            ret = CryptExportKey(pContentEncryptInfo->hContentEncryptKey,
+             expKey, SIMPLEBLOB, 0, keyBlob, &size);
+            if (ret)
+            {
+                DWORD head = sizeof(BLOBHEADER) + sizeof(ALG_ID);
+
+                pKeyTransEncryptInfo->EncryptedKey.pbData =
+                 CryptMemAlloc(size - head);
+                if (pKeyTransEncryptInfo->EncryptedKey.pbData)
+                {
+                    DWORD i, k = 0;
+
+                    pKeyTransEncryptInfo->EncryptedKey.cbData = size - head;
+                    for (i = size - 1; i >= head; --i, ++k)
+                        pKeyTransEncryptInfo->EncryptedKey.pbData[k] =
+                         keyBlob[i];
+                }
+                else
+                    ret = FALSE;
+            }
+            CryptMemFree(keyBlob);
+        }
+        else
+            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;
+}
+
+static void CRecipientInfo_Free(CMSG_KEY_TRANS_RECIPIENT_INFO *info)
+{
+    CryptMemFree(info->RecipientId.u.IssuerSerialNumber.Issuer.pbData);
+    CryptMemFree(info->RecipientId.u.IssuerSerialNumber.SerialNumber.pbData);
+    CryptMemFree(info->KeyEncryptionAlgorithm.pszObjId);
+    CryptMemFree(info->KeyEncryptionAlgorithm.Parameters.pbData);
+    CryptMemFree(info->EncryptedKey.pbData);
+}
+
 static void CEnvelopedEncodeMsg_Close(HCRYPTMSG hCryptMsg)
 {
     CEnvelopedEncodeMsg *msg = hCryptMsg;
 
+    CryptMemFree(msg->algo.pszObjId);
+    CryptMemFree(msg->algo.Parameters.pbData);
     if (msg->base.open_flags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG)
         CryptReleaseContext(msg->prov, 0);
+    CryptDestroyKey(msg->key);
+    if (msg->recipientInfo)
+    {
+        DWORD i;
+
+        for (i = 0; i < msg->cRecipientInfo; ++i)
+            CRecipientInfo_Free(&msg->recipientInfo[i]);
+        CryptMemFree(msg->recipientInfo);
+    }
+    CryptMemFree(msg->data.pbData);
 }
 
 static BOOL CEnvelopedEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
@@ -1546,10 +1834,48 @@ static HCRYPTMSG CEnvelopedEncodeMsg_Open(DWORD dwFlags,
     msg = CryptMemAlloc(sizeof(CEnvelopedEncodeMsg));
     if (msg)
     {
+        CRYPT_DATA_BLOB encryptedKey = { 0, NULL };
+        CMSG_CONTENT_ENCRYPT_INFO encryptInfo;
+        BOOL ret;
+        DWORD i;
+
         CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo,
          CEnvelopedEncodeMsg_Close, CEnvelopedEncodeMsg_GetParam,
          CEnvelopedEncodeMsg_Update, CRYPT_DefaultMsgControl);
+        ret = CRYPT_ConstructAlgorithmId(&msg->algo,
+         &info->ContentEncryptionAlgorithm);
         msg->prov = prov;
+        msg->data.cbData = 0;
+        msg->data.pbData = NULL;
+        msg->cRecipientInfo = info->cRecipients;
+        msg->recipientInfo = CryptMemAlloc(info->cRecipients *
+         sizeof(CMSG_KEY_TRANS_RECIPIENT_INFO));
+        if (!msg->recipientInfo)
+            ret = FALSE;
+        memset(&encryptInfo, 0, sizeof(encryptInfo));
+        if (ret)
+        {
+            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 = CRYPT_ExportEncryptedKey(&encryptInfo, i, &encryptedKey);
+            if (ret)
+                ret = CRecipientInfo_Construct(&msg->recipientInfo[i],
+                 info->rgpRecipientCert[i], &encryptedKey);
+        }
+        CContentEncryptInfo_Free(&encryptInfo);
+        if (!ret)
+        {
+            CryptMsgClose(msg);
+            msg = NULL;
+        }
     }
     if (!msg && (dwFlags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG))
         CryptReleaseContext(prov, 0);

commit 1de62294899212f7e6d26cff235246f3c8013085
Author: Alexander Morozov <amorozov на etersoft.ru>
Date:   Wed Dec 1 13:55:56 2010 +0300

    wincrypt.h: Define some enveloped message callback functions.

diff --git a/include/wincrypt.h b/include/wincrypt.h
index c813738..7d5a87c 100644
--- a/include/wincrypt.h
+++ b/include/wincrypt.h
@@ -2279,6 +2279,8 @@ static const WCHAR CERT_TRUST_PUB_AUTHENTICODE_FLAGS_VALUE_NAME[] =
  "CertDllVerifyCertificateChainPolicy"
 #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 "
@@ -3778,6 +3780,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


Подробная информация о списке рассылки Wine-devel