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

builder на builder.office.etersoft.ru builder на builder.office.etersoft.ru
Пт Дек 17 21:20:46 MSK 2010


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

    crypt32: Implement getting content and some parameters from a decoded enveloped message.

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

    crypt32: Implement decoding enveloped messages.

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

    wincrypt.h: Define PFN_CMSG_IMPORT_KEY_TRANS callback function.

---

commit f44ae748c0015c144f6a08702cda9b5f3b2bed8b
Author: Alexander Morozov <amorozov на etersoft.ru>
Date:   Wed Dec 15 17:51:37 2010 +0300

    crypt32: Implement getting content and some parameters from a decoded enveloped message.

diff --git a/dlls/crypt32/msg.c b/dlls/crypt32/msg.c
index d85d2a0..b083d26 100644
--- a/dlls/crypt32/msg.c
+++ b/dlls/crypt32/msg.c
@@ -2881,6 +2881,89 @@ static BOOL CRYPT_CopySignerCertInfo(void *pvData, DWORD *pcbData,
     return ret;
 }
 
+static BOOL CRYPT_CopyRecipientInfo(void *pvData, DWORD *pcbData,
+ const CERT_ISSUER_SERIAL_NUMBER *in)
+{
+    DWORD size = sizeof(CERT_INFO);
+    BOOL ret;
+
+    TRACE("(%p, %d, %p)\n", pvData, pvData ? *pcbData : 0, in);
+
+    size += in->SerialNumber.cbData;
+    size += in->Issuer.cbData;
+    if (!pvData)
+    {
+        *pcbData = size;
+        ret = TRUE;
+    }
+    else if (*pcbData < size)
+    {
+        *pcbData = size;
+        SetLastError(ERROR_MORE_DATA);
+        ret = FALSE;
+    }
+    else
+    {
+        LPBYTE nextData = (BYTE *)pvData + sizeof(CERT_INFO);
+        CERT_INFO *out = pvData;
+
+        CRYPT_CopyBlob(&out->SerialNumber, &in->SerialNumber, &nextData);
+        CRYPT_CopyBlob(&out->Issuer, &in->Issuer, &nextData);
+        ret = TRUE;
+    }
+    TRACE("returning %d\n", ret);
+    return ret;
+}
+
+static BOOL CDecodeEnvelopedMsg_GetParam(CDecodeMsg *msg, DWORD dwParamType,
+ DWORD dwIndex, void *pvData, DWORD *pcbData)
+{
+    BOOL ret = FALSE;
+
+    switch (dwParamType)
+    {
+    case CMSG_TYPE_PARAM:
+        ret = CRYPT_CopyParam(pvData, pcbData, &msg->type, sizeof(msg->type));
+        break;
+    case CMSG_CONTENT_PARAM:
+        if (msg->u.enveloped_data.data)
+            ret = CRYPT_CopyParam(pvData, pcbData,
+             msg->u.enveloped_data.content.pbData,
+             msg->u.enveloped_data.content.cbData);
+        else
+            SetLastError(CRYPT_E_INVALID_MSG_TYPE);
+        break;
+    case CMSG_RECIPIENT_COUNT_PARAM:
+        if (msg->u.enveloped_data.data)
+            ret = CRYPT_CopyParam(pvData, pcbData,
+             &msg->u.enveloped_data.data->cRecipientInfo, sizeof(DWORD));
+        else
+            SetLastError(CRYPT_E_INVALID_MSG_TYPE);
+        break;
+    case CMSG_RECIPIENT_INFO_PARAM:
+        if (msg->u.enveloped_data.data)
+        {
+            if (dwIndex < msg->u.enveloped_data.data->cRecipientInfo)
+            {
+                PCMSG_KEY_TRANS_RECIPIENT_INFO recipientInfo =
+                 &msg->u.enveloped_data.data->rgRecipientInfo[dwIndex];
+
+                ret = CRYPT_CopyRecipientInfo(pvData, pcbData,
+                 &recipientInfo->RecipientId.u.IssuerSerialNumber);
+            }
+            else
+                SetLastError(CRYPT_E_INVALID_INDEX);
+        }
+        else
+            SetLastError(CRYPT_E_INVALID_MSG_TYPE);
+        break;
+    default:
+        FIXME("unimplemented for %d\n", dwParamType);
+        SetLastError(CRYPT_E_INVALID_MSG_TYPE);
+    }
+    return ret;
+}
+
 static BOOL CDecodeSignedMsg_GetParam(CDecodeMsg *msg, DWORD dwParamType,
  DWORD dwIndex, void *pvData, DWORD *pcbData)
 {
@@ -3073,6 +3156,10 @@ static BOOL CDecodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
         ret = CDecodeHashMsg_GetParam(msg, dwParamType, dwIndex, pvData,
          pcbData);
         break;
+    case CMSG_ENVELOPED:
+        ret = CDecodeEnvelopedMsg_GetParam(msg, dwParamType, dwIndex, pvData,
+         pcbData);
+        break;
     case CMSG_SIGNED:
         ret = CDecodeSignedMsg_GetParam(msg, dwParamType, dwIndex, pvData,
          pcbData);
diff --git a/dlls/crypt32/tests/msg.c b/dlls/crypt32/tests/msg.c
index 20ad5c9..77b468c 100644
--- a/dlls/crypt32/tests/msg.c
+++ b/dlls/crypt32/tests/msg.c
@@ -3057,7 +3057,6 @@ static void test_decode_msg_get_param(void)
      NULL);
     CryptMsgUpdate(msg, envelopedEmptyBareContent,
      sizeof(envelopedEmptyBareContent), TRUE);
-    todo_wine
     check_param("enveloped empty bare content", msg, CMSG_CONTENT_PARAM, NULL,
      0);
     CryptMsgClose(msg);
@@ -3065,7 +3064,6 @@ static void test_decode_msg_get_param(void)
     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
     CryptMsgUpdate(msg, envelopedEmptyContent, sizeof(envelopedEmptyContent),
      TRUE);
-    todo_wine
     check_param("enveloped empty content", msg, CMSG_CONTENT_PARAM, NULL, 0);
     CryptMsgClose(msg);
 
@@ -3080,7 +3078,6 @@ static void test_decode_msg_get_param(void)
 
     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
     CryptMsgUpdate(msg, envelopedMessage, sizeof(envelopedMessage), TRUE);
-    todo_wine
     check_param("enveloped message before decrypting", msg, CMSG_CONTENT_PARAM,
      envelopedMessage + sizeof(envelopedMessage) - 4, 4);
     if (key)
@@ -3094,7 +3091,6 @@ static void test_decode_msg_get_param(void)
         ret = CryptMsgControl(msg, 0, CMSG_CTRL_DECRYPT, &decryptPara);
         ok(!ret && GetLastError() == CRYPT_E_ALREADY_DECRYPTED,
          "expected CRYPT_E_ALREADY_DECRYPTED, got %08x\n", GetLastError());
-        todo_wine
         check_param("enveloped message", msg, CMSG_CONTENT_PARAM, msgData,
          sizeof(msgData));
     }
@@ -3106,7 +3102,6 @@ static void test_decode_msg_get_param(void)
      NULL);
     CryptMsgUpdate(msg, envelopedBareMessage, sizeof(envelopedBareMessage),
      TRUE);
-    todo_wine
     check_param("enveloped bare message before decrypting", msg,
      CMSG_CONTENT_PARAM, envelopedBareMessage +
      sizeof(envelopedBareMessage) - 4, 4);
@@ -3116,7 +3111,6 @@ static void test_decode_msg_get_param(void)
         SetLastError(0xdeadbeef);
         ret = CryptMsgControl(msg, 0, CMSG_CTRL_DECRYPT, &decryptPara);
         ok(ret, "CryptMsgControl failed: %08x\n", GetLastError());
-        todo_wine
         check_param("enveloped bare message", msg, CMSG_CONTENT_PARAM, msgData,
          sizeof(msgData));
     }
@@ -3132,21 +3126,17 @@ static void test_decode_msg_get_param(void)
     CryptMsgUpdate(msg, envelopedMessageWith3Recps,
      sizeof(envelopedMessageWith3Recps), TRUE);
     value = 3;
-    todo_wine
     check_param("recipient count", msg, CMSG_RECIPIENT_COUNT_PARAM,
      (const BYTE *)&value, sizeof(value));
     size = 0;
     SetLastError(0xdeadbeef);
     ret = CryptMsgGetParam(msg, CMSG_RECIPIENT_INFO_PARAM, 3, NULL, &size);
-    todo_wine
     ok(!ret && GetLastError() == CRYPT_E_INVALID_INDEX,
      "expected CRYPT_E_INVALID_INDEX, got %08x\n", GetLastError());
     size = 0;
     SetLastError(0xdeadbeef);
     ret = CryptMsgGetParam(msg, CMSG_RECIPIENT_INFO_PARAM, 2, NULL, &size);
-    todo_wine
     ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
-    todo_wine
     ok(size >= 142, "unexpected size: %u\n", size);
     if (ret)
         buf = CryptMemAlloc(size);
@@ -3158,18 +3148,13 @@ static void test_decode_msg_get_param(void)
 
         SetLastError(0xdeadbeef);
         ret = CryptMsgGetParam(msg, CMSG_RECIPIENT_INFO_PARAM, 2, buf, &size);
-        todo_wine
         ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
-        todo_wine
         ok(certInfo->SerialNumber.cbData == sizeof(serialNumber),
          "unexpected serial number size: %u\n", certInfo->SerialNumber.cbData);
-        todo_wine
         ok(!memcmp(certInfo->SerialNumber.pbData, serialNumber,
          sizeof(serialNumber)), "unexpected serial number\n");
-        todo_wine
         ok(certInfo->Issuer.cbData == sizeof(issuer),
          "unexpected issuer size: %u\n", certInfo->Issuer.cbData);
-        todo_wine
         ok(!memcmp(certInfo->Issuer.pbData, issuer, sizeof(issuer)),
          "unexpected issuer\n");
         CryptMemFree(buf);

commit dd75ab38c640e0be5a513f3051b0bdaccc7cc668
Author: Alexander Morozov <amorozov на etersoft.ru>
Date:   Wed Dec 15 17:35:29 2010 +0300

    crypt32: Implement decoding enveloped messages.

diff --git a/dlls/crypt32/crypt32_private.h b/dlls/crypt32/crypt32_private.h
index a4b9aff..65a9cd2 100644
--- a/dlls/crypt32/crypt32_private.h
+++ b/dlls/crypt32/crypt32_private.h
@@ -100,6 +100,10 @@ typedef struct _CRYPT_ENVELOPED_DATA
 BOOL CRYPT_AsnEncodePKCSEnvelopedData(const CRYPT_ENVELOPED_DATA *envelopedData,
  void *pvData, DWORD *pcbData);
 
+BOOL CRYPT_AsnDecodePKCSEnvelopedData(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
+ CRYPT_ENVELOPED_DATA *envelopedData, DWORD *pcbEnvelopedData);
+
 typedef struct _CRYPT_SIGNED_INFO
 {
     DWORD                 version;
diff --git a/dlls/crypt32/decode.c b/dlls/crypt32/decode.c
index a5602ac..62231cd 100644
--- a/dlls/crypt32/decode.c
+++ b/dlls/crypt32/decode.c
@@ -5569,6 +5569,124 @@ BOOL CRYPT_AsnDecodeCMSSignedInfo(const BYTE *pbEncoded, DWORD cbEncoded,
     return ret;
 }
 
+static BOOL CRYPT_AsnDecodeRecipientInfo(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded)
+{
+    BOOL ret;
+    CMSG_KEY_TRANS_RECIPIENT_INFO *info = pvStructInfo;
+    struct AsnDecodeSequenceItem items[] = {
+     { ASN_INTEGER, offsetof(CMSG_KEY_TRANS_RECIPIENT_INFO, dwVersion),
+       CRYPT_AsnDecodeIntInternal, sizeof(DWORD), FALSE, FALSE, 0, 0 },
+     { ASN_SEQUENCEOF, offsetof(CMSG_KEY_TRANS_RECIPIENT_INFO,
+       RecipientId.u.IssuerSerialNumber), CRYPT_AsnDecodeIssuerSerialNumber,
+       sizeof(CERT_ISSUER_SERIAL_NUMBER), FALSE, TRUE,
+       offsetof(CMSG_KEY_TRANS_RECIPIENT_INFO,
+       RecipientId.u.IssuerSerialNumber.Issuer.pbData), 0 },
+     { ASN_SEQUENCEOF, offsetof(CMSG_KEY_TRANS_RECIPIENT_INFO,
+       KeyEncryptionAlgorithm), CRYPT_AsnDecodeAlgorithmId,
+       sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE,
+       offsetof(CMSG_KEY_TRANS_RECIPIENT_INFO,
+       KeyEncryptionAlgorithm.pszObjId), 0 },
+     { ASN_OCTETSTRING, offsetof(CMSG_KEY_TRANS_RECIPIENT_INFO, EncryptedKey),
+       CRYPT_AsnDecodeOctetsInternal, sizeof(CRYPT_DATA_BLOB), FALSE, TRUE,
+       offsetof(CMSG_KEY_TRANS_RECIPIENT_INFO, EncryptedKey.pbData), 0 },
+    };
+
+    TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
+     pvStructInfo, *pcbStructInfo, pcbDecoded);
+
+    ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]),
+     pbEncoded, cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo,
+     pcbDecoded, info ? info->RecipientId.u.IssuerSerialNumber.Issuer.pbData :
+     NULL);
+    if (info)
+        info->RecipientId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
+    TRACE("returning %d\n", ret);
+    return ret;
+}
+
+static BOOL CRYPT_DecodeRecipientInfoArray(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded)
+{
+    BOOL ret;
+    struct AsnArrayDescriptor arrayDesc = { ASN_CONSTRUCTOR | ASN_SETOF,
+     offsetof(CRYPT_ENVELOPED_DATA, cRecipientInfo),
+     offsetof(CRYPT_ENVELOPED_DATA, rgRecipientInfo),
+     MEMBERSIZE(CRYPT_ENVELOPED_DATA, cRecipientInfo, encryptedContentInfo),
+     CRYPT_AsnDecodeRecipientInfo, sizeof(CMSG_KEY_TRANS_RECIPIENT_INFO), TRUE,
+     offsetof(CMSG_KEY_TRANS_RECIPIENT_INFO,
+     RecipientId.u.IssuerSerialNumber.Issuer.pbData) };
+
+    TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
+     pvStructInfo, *pcbStructInfo, pcbDecoded);
+
+    ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
+     dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded);
+    TRACE("returning %d\n", ret);
+    return ret;
+}
+
+static BOOL CRYPT_AsnDecodeEncryptedContentInfo(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded)
+{
+    BOOL ret;
+    CRYPT_ENCRYPTED_CONTENT_INFO *info = pvStructInfo;
+    struct AsnDecodeSequenceItem items[] = {
+     { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ENCRYPTED_CONTENT_INFO,
+       contentType), CRYPT_AsnDecodeOidInternal, sizeof(LPSTR),
+       FALSE, TRUE, offsetof(CRYPT_ENCRYPTED_CONTENT_INFO,
+       contentType), 0 },
+     { ASN_SEQUENCEOF, offsetof(CRYPT_ENCRYPTED_CONTENT_INFO,
+       contentEncryptionAlgorithm), CRYPT_AsnDecodeAlgorithmId,
+       sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE,
+       offsetof(CRYPT_ENCRYPTED_CONTENT_INFO,
+       contentEncryptionAlgorithm.pszObjId), 0 },
+     { ASN_CONTEXT | 0, offsetof(CRYPT_ENCRYPTED_CONTENT_INFO,
+       encryptedContent), CRYPT_AsnDecodeOctetsInternal,
+       sizeof(CRYPT_DATA_BLOB), TRUE, TRUE,
+       offsetof(CRYPT_ENCRYPTED_CONTENT_INFO, encryptedContent.pbData) },
+    };
+
+    TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
+     pvStructInfo, *pcbStructInfo, pcbDecoded);
+
+    ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]),
+     pbEncoded, cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo,
+     pcbDecoded, info ? info->contentType : NULL);
+    TRACE("returning %d\n", ret);
+    return ret;
+}
+
+BOOL CRYPT_AsnDecodePKCSEnvelopedData(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
+ CRYPT_ENVELOPED_DATA *envelopedData, DWORD *pcbEnvelopedData)
+{
+    BOOL ret;
+    struct AsnDecodeSequenceItem items[] = {
+     { ASN_INTEGER, offsetof(CRYPT_ENVELOPED_DATA, version),
+       CRYPT_AsnDecodeIntInternal, sizeof(DWORD), FALSE, FALSE, 0, 0 },
+     { ASN_CONSTRUCTOR | ASN_SETOF, offsetof(CRYPT_ENVELOPED_DATA,
+       cRecipientInfo), CRYPT_DecodeRecipientInfoArray,
+       MEMBERSIZE(CRYPT_ENVELOPED_DATA, cRecipientInfo, encryptedContentInfo),
+       FALSE, TRUE, offsetof(CRYPT_ENVELOPED_DATA, rgRecipientInfo), 0 },
+     { ASN_SEQUENCEOF, offsetof(CRYPT_ENVELOPED_DATA, encryptedContentInfo),
+       CRYPT_AsnDecodeEncryptedContentInfo,
+       sizeof(CRYPT_ENCRYPTED_CONTENT_INFO), FALSE, TRUE,
+       offsetof(CRYPT_ENVELOPED_DATA, encryptedContentInfo.contentType), 0 },
+    };
+
+    TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
+     pDecodePara, envelopedData, *pcbEnvelopedData);
+
+    ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]),
+     pbEncoded, cbEncoded, dwFlags, pDecodePara, envelopedData,
+     pcbEnvelopedData, NULL, NULL);
+    TRACE("returning %d\n", ret);
+    return ret;
+}
+
 static CryptDecodeObjectExFunc CRYPT_GetBuiltinDecoder(DWORD dwCertEncodingType,
  LPCSTR lpszStructType)
 {
diff --git a/dlls/crypt32/msg.c b/dlls/crypt32/msg.c
index 1c5cca4..d85d2a0 100644
--- a/dlls/crypt32/msg.c
+++ b/dlls/crypt32/msg.c
@@ -2045,14 +2045,23 @@ HCRYPTMSG WINAPI CryptMsgOpenToEncode(DWORD dwMsgEncodingType, DWORD dwFlags,
     return msg;
 }
 
+typedef struct _CEnvelopedDecodeMsg
+{
+    CRYPT_ENVELOPED_DATA *data;
+    HCRYPTPROV            crypt_prov;
+    CRYPT_DATA_BLOB       content;
+    BOOL                  decrypted;
+} CEnvelopedDecodeMsg;
+
 typedef struct _CDecodeMsg
 {
     CryptMsgBase           base;
     DWORD                  type;
     HCRYPTPROV             crypt_prov;
     union {
-        HCRYPTHASH     hash;
-        CSignedMsgData signed_data;
+        HCRYPTHASH          hash;
+        CSignedMsgData      signed_data;
+        CEnvelopedDecodeMsg enveloped_data;
     } u;
     CRYPT_DATA_BLOB        msg_data;
     CRYPT_DATA_BLOB        detached_data;
@@ -2071,6 +2080,12 @@ static void CDecodeMsg_Close(HCRYPTMSG hCryptMsg)
         if (msg->u.hash)
             CryptDestroyHash(msg->u.hash);
         break;
+    case CMSG_ENVELOPED:
+        if (msg->u.enveloped_data.crypt_prov)
+            CryptReleaseContext(msg->u.enveloped_data.crypt_prov, 0);
+        LocalFree(msg->u.enveloped_data.data);
+        CryptMemFree(msg->u.enveloped_data.content.pbData);
+        break;
     case CMSG_SIGNED:
         if (msg->u.signed_data.info)
         {
@@ -2203,6 +2218,21 @@ static BOOL CDecodeMsg_DecodeHashedContent(CDecodeMsg *msg,
     return ret;
 }
 
+static BOOL CDecodeMsg_DecodeEnvelopedContent(CDecodeMsg *msg,
+ const CRYPT_DER_BLOB *blob)
+{
+    BOOL ret;
+    CRYPT_ENVELOPED_DATA *envelopedData;
+    DWORD size;
+
+    ret = CRYPT_AsnDecodePKCSEnvelopedData(blob->pbData, blob->cbData,
+     CRYPT_DECODE_ALLOC_FLAG, NULL, (CRYPT_ENVELOPED_DATA *)&envelopedData,
+     &size);
+    if (ret)
+        msg->u.enveloped_data.data = envelopedData;
+    return ret;
+}
+
 static BOOL CDecodeMsg_DecodeSignedContent(CDecodeMsg *msg,
  const CRYPT_DER_BLOB *blob)
 {
@@ -2239,8 +2269,8 @@ static BOOL CDecodeMsg_DecodeContent(CDecodeMsg *msg, const CRYPT_DER_BLOB *blob
             msg->type = CMSG_HASHED;
         break;
     case CMSG_ENVELOPED:
-        FIXME("unimplemented for type CMSG_ENVELOPED\n");
-        ret = TRUE;
+        if ((ret = CDecodeMsg_DecodeEnvelopedContent(msg, blob)))
+            msg->type = CMSG_ENVELOPED;
         break;
     case CMSG_SIGNED:
         if ((ret = CDecodeMsg_DecodeSignedContent(msg, blob)))
@@ -2316,6 +2346,20 @@ static BOOL CDecodeMsg_FinalizeHashedContent(CDecodeMsg *msg,
     return ret;
 }
 
+static BOOL CDecodeMsg_FinalizeEnvelopedContent(CDecodeMsg *msg,
+ CRYPT_DER_BLOB *blob)
+{
+    CRYPT_DATA_BLOB *content;
+
+    if (msg->base.open_flags & CMSG_DETACHED_FLAG)
+        content = &msg->detached_data;
+    else
+        content =
+         &msg->u.enveloped_data.data->encryptedContentInfo.encryptedContent;
+
+    return CRYPT_ConstructBlob(&msg->u.enveloped_data.content, content);
+}
+
 static BOOL CDecodeMsg_FinalizeSignedContent(CDecodeMsg *msg,
  CRYPT_DER_BLOB *blob)
 {
@@ -2377,6 +2421,9 @@ static BOOL CDecodeMsg_FinalizeContent(CDecodeMsg *msg, CRYPT_DER_BLOB *blob)
     case CMSG_HASHED:
         ret = CDecodeMsg_FinalizeHashedContent(msg, blob);
         break;
+    case CMSG_ENVELOPED:
+        ret = CDecodeMsg_FinalizeEnvelopedContent(msg, blob);
+        break;
     case CMSG_SIGNED:
         ret = CDecodeMsg_FinalizeSignedContent(msg, blob);
         break;
@@ -3210,6 +3257,118 @@ static BOOL CDecodeSignedMsg_VerifySignatureEx(CDecodeMsg *msg,
     return ret;
 }
 
+static BOOL WINAPI CRYPT_ImportKeyTrans(
+ PCRYPT_ALGORITHM_IDENTIFIER pContentEncryptionAlgorithm,
+ PCMSG_CTRL_KEY_TRANS_DECRYPT_PARA pKeyTransDecryptPara, DWORD dwFlags,
+ void *pvReserved, HCRYPTKEY *phContentEncryptKey)
+{
+    BOOL ret;
+    HCRYPTKEY key;
+
+    ret = CryptGetUserKey(pKeyTransDecryptPara->hCryptProv,
+     pKeyTransDecryptPara->dwKeySpec ? pKeyTransDecryptPara->dwKeySpec :
+     AT_KEYEXCHANGE, &key);
+    if (ret)
+    {
+        CMSG_KEY_TRANS_RECIPIENT_INFO *info =
+         &pKeyTransDecryptPara->pKeyTrans[pKeyTransDecryptPara->dwRecipientIndex];
+        CRYPT_DATA_BLOB *encryptedKey = &info->EncryptedKey;
+        DWORD size = encryptedKey->cbData + sizeof(BLOBHEADER) + sizeof(ALG_ID);
+        BYTE *keyBlob = CryptMemAlloc(size);
+
+        if (keyBlob)
+        {
+            DWORD i, k = size - 1;
+            BLOBHEADER *blobHeader = (BLOBHEADER *)keyBlob;
+            ALG_ID *algID = (ALG_ID *)(keyBlob + sizeof(BLOBHEADER));
+
+            blobHeader->bType = SIMPLEBLOB;
+            blobHeader->bVersion = CUR_BLOB_VERSION;
+            blobHeader->reserved = 0;
+            blobHeader->aiKeyAlg = CertOIDToAlgId(
+             pContentEncryptionAlgorithm->pszObjId);
+            *algID = CertOIDToAlgId(info->KeyEncryptionAlgorithm.pszObjId);
+            for (i = 0; i < encryptedKey->cbData; ++i, --k)
+                keyBlob[k] = encryptedKey->pbData[i];
+
+            ret = CryptImportKey(pKeyTransDecryptPara->hCryptProv, keyBlob,
+             size, key, 0, phContentEncryptKey);
+            CryptMemFree(keyBlob);
+        }
+        else
+            ret = FALSE;
+        CryptDestroyKey(key);
+    }
+    return ret;
+}
+
+static BOOL CRYPT_ImportEncryptedKey(PCRYPT_ALGORITHM_IDENTIFIER contEncrAlg,
+ PCMSG_CTRL_DECRYPT_PARA para, PCMSG_KEY_TRANS_RECIPIENT_INFO info,
+ HCRYPTKEY *key)
+{
+    static HCRYPTOIDFUNCSET set = NULL;
+    PFN_CMSG_IMPORT_KEY_TRANS importKeyFunc = NULL;
+    HCRYPTOIDFUNCADDR hFunc = NULL;
+    CMSG_CTRL_KEY_TRANS_DECRYPT_PARA decryptPara;
+    BOOL ret;
+
+    memset(&decryptPara, 0, sizeof(decryptPara));
+    decryptPara.cbSize = sizeof(decryptPara);
+    decryptPara.hCryptProv = para->hCryptProv;
+    decryptPara.dwKeySpec = para->dwKeySpec;
+    decryptPara.pKeyTrans = info;
+    decryptPara.dwRecipientIndex = para->dwRecipientIndex;
+
+    if (!set)
+        set = CryptInitOIDFunctionSet(CMSG_OID_IMPORT_KEY_TRANS_FUNC, 0);
+    CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, contEncrAlg->pszObjId, 0,
+     (void **)&importKeyFunc, &hFunc);
+    if (!importKeyFunc)
+        importKeyFunc = CRYPT_ImportKeyTrans;
+    ret = importKeyFunc(contEncrAlg, &decryptPara, 0, NULL, key);
+    if (hFunc)
+        CryptFreeOIDFunctionAddress(hFunc, 0);
+    return ret;
+}
+
+static BOOL CDecodeEnvelopedMsg_CrtlDecrypt(CDecodeMsg *msg,
+ PCMSG_CTRL_DECRYPT_PARA para)
+{
+    BOOL ret = FALSE;
+    CEnvelopedDecodeMsg *enveloped_data = &msg->u.enveloped_data;
+    CRYPT_ENVELOPED_DATA *data = enveloped_data->data;
+
+    if (para->cbSize != sizeof(CMSG_CTRL_DECRYPT_PARA))
+        SetLastError(E_INVALIDARG);
+    else if (!data)
+        SetLastError(CRYPT_E_INVALID_MSG_TYPE);
+    else if (para->dwRecipientIndex >= data->cRecipientInfo)
+        SetLastError(CRYPT_E_INVALID_INDEX);
+    else if (enveloped_data->decrypted)
+        SetLastError(CRYPT_E_ALREADY_DECRYPTED);
+    else if (!para->hCryptProv)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (enveloped_data->content.cbData)
+    {
+        HCRYPTKEY key;
+
+        ret = CRYPT_ImportEncryptedKey(
+         &data->encryptedContentInfo.contentEncryptionAlgorithm, para,
+         data->rgRecipientInfo, &key);
+        if (ret)
+        {
+            ret = CryptDecrypt(key, 0, TRUE, 0, enveloped_data->content.pbData,
+             &enveloped_data->content.cbData);
+            CryptDestroyKey(key);
+        }
+    }
+    else
+        ret = TRUE;
+    if (ret)
+        enveloped_data->decrypted = TRUE;
+    return ret;
+}
+
 static BOOL CDecodeMsg_Control(HCRYPTMSG hCryptMsg, DWORD dwFlags,
  DWORD dwCtrlType, const void *pvCtrlPara)
 {
@@ -3231,6 +3390,13 @@ static BOOL CDecodeMsg_Control(HCRYPTMSG hCryptMsg, DWORD dwFlags,
     case CMSG_CTRL_DECRYPT:
         switch (msg->type)
         {
+        case CMSG_ENVELOPED:
+            ret = CDecodeEnvelopedMsg_CrtlDecrypt(msg,
+             (PCMSG_CTRL_DECRYPT_PARA)pvCtrlPara);
+            if (ret && (dwFlags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG))
+                msg->u.enveloped_data.crypt_prov =
+                 ((PCMSG_CTRL_DECRYPT_PARA)pvCtrlPara)->hCryptProv;
+            break;
         default:
             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
         }
diff --git a/dlls/crypt32/tests/msg.c b/dlls/crypt32/tests/msg.c
index e32690b..20ad5c9 100644
--- a/dlls/crypt32/tests/msg.c
+++ b/dlls/crypt32/tests/msg.c
@@ -2606,7 +2606,6 @@ static void test_decode_msg_update(void)
     SetLastError(0xdeadbeef);
     ret = CryptMsgUpdate(msg, envelopedEmptyContent,
      sizeof(envelopedEmptyContent), TRUE);
-    todo_wine
     ok(!ret &&
      (GetLastError() == CRYPT_E_ASN1_BADTAG ||
       GetLastError() == OSS_DATA_ERROR), /* Win9x */
@@ -3089,12 +3088,10 @@ static void test_decode_msg_get_param(void)
         decryptPara.hCryptProv = hCryptProv;
         SetLastError(0xdeadbeef);
         ret = CryptMsgControl(msg, 0, CMSG_CTRL_DECRYPT, &decryptPara);
-        todo_wine
         ok(ret, "CryptMsgControl failed: %08x\n", GetLastError());
         decryptPara.hCryptProv = 0;
         SetLastError(0xdeadbeef);
         ret = CryptMsgControl(msg, 0, CMSG_CTRL_DECRYPT, &decryptPara);
-        todo_wine
         ok(!ret && GetLastError() == CRYPT_E_ALREADY_DECRYPTED,
          "expected CRYPT_E_ALREADY_DECRYPTED, got %08x\n", GetLastError());
         todo_wine
@@ -3118,7 +3115,6 @@ static void test_decode_msg_get_param(void)
         decryptPara.hCryptProv = hCryptProv;
         SetLastError(0xdeadbeef);
         ret = CryptMsgControl(msg, 0, CMSG_CTRL_DECRYPT, &decryptPara);
-        todo_wine
         ok(ret, "CryptMsgControl failed: %08x\n", GetLastError());
         todo_wine
         check_param("enveloped bare message", msg, CMSG_CONTENT_PARAM, msgData,
@@ -3556,7 +3552,6 @@ static void test_msg_control(void)
     decryptPara.cbSize = 0;
     SetLastError(0xdeadbeef);
     ret = CryptMsgControl(msg, 0, CMSG_CTRL_DECRYPT, &decryptPara);
-    todo_wine
     ok(!ret && GetLastError() == E_INVALIDARG,
      "expected E_INVALIDARG, got %08x\n", GetLastError());
     decryptPara.cbSize = sizeof(decryptPara);
@@ -3573,7 +3568,6 @@ static void test_msg_control(void)
     ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError());
     SetLastError(0xdeadbeef);
     ret = CryptMsgControl(msg, 0, CMSG_CTRL_DECRYPT, &decryptPara);
-    todo_wine
     ok(!ret && GetLastError() == CRYPT_E_INVALID_INDEX,
      "expected CRYPT_E_INVALID_INDEX, got %08x\n", GetLastError());
     CryptMsgClose(msg);
@@ -3586,7 +3580,6 @@ static void test_msg_control(void)
     ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError());
     SetLastError(0xdeadbeef);
     ret = CryptMsgControl(msg, 0, CMSG_CTRL_DECRYPT, &decryptPara);
-    todo_wine
     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
      "expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
     CryptMsgClose(msg);

commit 60be01f16d142fd88371cb3e45eca50b6d50b81f
Author: Alexander Morozov <amorozov на etersoft.ru>
Date:   Wed Dec 15 16:40:01 2010 +0300

    wincrypt.h: Define PFN_CMSG_IMPORT_KEY_TRANS callback function.

diff --git a/include/wincrypt.h b/include/wincrypt.h
index 7d5a87c..8834561 100644
--- a/include/wincrypt.h
+++ b/include/wincrypt.h
@@ -2281,6 +2281,7 @@ static const WCHAR CERT_TRUST_PUB_AUTHENTICODE_FLAGS_VALUE_NAME[] =
 #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 CMSG_OID_IMPORT_KEY_TRANS_FUNC        "CryptMsgDllImportKeyTrans"
 
 #define CRYPT_OID_REGPATH "Software\\Microsoft\\Cryptography\\OID"
 #define CRYPT_OID_REG_ENCODING_TYPE_PREFIX "EncodingType "
@@ -3805,6 +3806,14 @@ typedef struct _CMSG_KEY_TRANS_ENCRYPT_INFO {
     DWORD                       dwFlags;
 } CMSG_KEY_TRANS_ENCRYPT_INFO, *PCMSG_KEY_TRANS_ENCRYPT_INFO;
 
+typedef struct _CMSG_CTRL_KEY_TRANS_DECRYPT_PARA {
+    DWORD                          cbSize;
+    HCRYPTPROV                     hCryptProv;
+    DWORD                          dwKeySpec;
+    PCMSG_KEY_TRANS_RECIPIENT_INFO pKeyTrans;
+    DWORD                          dwRecipientIndex;
+} CMSG_CTRL_KEY_TRANS_DECRYPT_PARA, *PCMSG_CTRL_KEY_TRANS_DECRYPT_PARA;
+
 typedef BOOL (WINAPI *PFN_CMSG_GEN_CONTENT_ENCRYPT_KEY)(
  PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo, DWORD dwFlags,
  void *pvReserved);
@@ -3815,6 +3824,11 @@ typedef BOOL (WINAPI *PFN_CMSG_EXPORT_KEY_TRANS)(
  PCMSG_KEY_TRANS_ENCRYPT_INFO pKeyTransEncryptInfo,
  DWORD dwFlags, void *pvReserved);
 
+typedef BOOL (WINAPI *PFN_CMSG_IMPORT_KEY_TRANS)(
+ PCRYPT_ALGORITHM_IDENTIFIER pContentEncryptionAlgorithm,
+ PCMSG_CTRL_KEY_TRANS_DECRYPT_PARA pKeyTransDecryptPara, DWORD dwFlags,
+ void *pvReserved, HCRYPTKEY *phContentEncryptKey);
+
 /* CryptMsgGetAndVerifySigner flags */
 #define CMSG_TRUSTED_SIGNER_FLAG   0x1
 #define CMSG_SIGNER_ONLY_FLAG      0x2


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