Commit dd75ab38 authored by Alexander Morozov's avatar Alexander Morozov Committed by Alexandre Julliard

crypt32: Implement decoding enveloped messages.

parent 60be01f1
......@@ -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;
......
......@@ -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)
{
......
......@@ -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);
}
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment