mirror of
https://github.com/reactos/wine.git
synced 2024-11-29 14:40:56 +00:00
crypt32: Implement streamed encoding of definite-length data messages.
This commit is contained in:
parent
48afa16386
commit
afaba37ed7
@ -19,8 +19,11 @@
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "wincrypt.h"
|
||||
#include "snmp.h"
|
||||
|
||||
#include "wine/debug.h"
|
||||
#include "wine/exception.h"
|
||||
#include "crypt32_private.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(crypt);
|
||||
|
||||
@ -74,6 +77,7 @@ typedef struct _CDataEncodeMsg
|
||||
CryptMsgBase base;
|
||||
DWORD bare_content_len;
|
||||
LPBYTE bare_content;
|
||||
BOOL begun;
|
||||
} CDataEncodeMsg;
|
||||
|
||||
static const BYTE empty_data_content[] = { 0x04,0x00 };
|
||||
@ -86,6 +90,71 @@ static void CDataEncodeMsg_Close(HCRYPTMSG hCryptMsg)
|
||||
LocalFree(msg->bare_content);
|
||||
}
|
||||
|
||||
static WINAPI BOOL CRYPT_EncodeContentLength(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
|
||||
{
|
||||
const CDataEncodeMsg *msg = (const CDataEncodeMsg *)pvStructInfo;
|
||||
DWORD lenBytes;
|
||||
BOOL ret = TRUE;
|
||||
|
||||
/* Trick: report bytes needed based on total message length, even though
|
||||
* the message isn't available yet. The caller will use the length
|
||||
* reported here to encode its length.
|
||||
*/
|
||||
CRYPT_EncodeLen(msg->base.stream_info.cbContent, NULL, &lenBytes);
|
||||
if (!pbEncoded)
|
||||
*pcbEncoded = 1 + lenBytes + msg->base.stream_info.cbContent;
|
||||
else
|
||||
{
|
||||
if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
|
||||
pcbEncoded, 1 + lenBytes)))
|
||||
{
|
||||
if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
|
||||
pbEncoded = *(BYTE **)pbEncoded;
|
||||
*pbEncoded++ = ASN_OCTETSTRING;
|
||||
CRYPT_EncodeLen(msg->base.stream_info.cbContent, pbEncoded,
|
||||
&lenBytes);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL CRYPT_EncodeDataContentInfoHeader(CDataEncodeMsg *msg,
|
||||
CRYPT_DATA_BLOB *header)
|
||||
{
|
||||
BOOL ret;
|
||||
|
||||
if (msg->base.streamed && msg->base.stream_info.cbContent == 0xffffffff)
|
||||
{
|
||||
FIXME("unimplemented for indefinite-length encoding\n");
|
||||
header->cbData = 0;
|
||||
header->pbData = NULL;
|
||||
ret = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct AsnConstructedItem constructed = { 0, msg,
|
||||
CRYPT_EncodeContentLength };
|
||||
struct AsnEncodeSequenceItem items[2] = {
|
||||
{ szOID_RSA_data, CRYPT_AsnEncodeOid, 0 },
|
||||
{ &constructed, CRYPT_AsnEncodeConstructed, 0 },
|
||||
};
|
||||
|
||||
ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items,
|
||||
sizeof(items) / sizeof(items[0]), CRYPT_ENCODE_ALLOC_FLAG, NULL,
|
||||
(LPBYTE)&header->pbData, &header->cbData);
|
||||
if (ret)
|
||||
{
|
||||
/* Trick: subtract the content length from the reported length,
|
||||
* as the actual content hasn't come yet.
|
||||
*/
|
||||
header->cbData -= msg->base.stream_info.cbContent;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL CDataEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
|
||||
DWORD cbData, BOOL fFinal)
|
||||
{
|
||||
@ -94,7 +163,58 @@ static BOOL CDataEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
|
||||
|
||||
if (msg->base.finalized)
|
||||
SetLastError(CRYPT_E_MSG_ERROR);
|
||||
else if (!fFinal)
|
||||
else if (msg->base.streamed)
|
||||
{
|
||||
if (fFinal)
|
||||
msg->base.finalized = TRUE;
|
||||
__TRY
|
||||
{
|
||||
if (!msg->begun)
|
||||
{
|
||||
CRYPT_DATA_BLOB header;
|
||||
|
||||
msg->begun = TRUE;
|
||||
ret = CRYPT_EncodeDataContentInfoHeader(msg, &header);
|
||||
if (ret)
|
||||
{
|
||||
ret = msg->base.stream_info.pfnStreamOutput(
|
||||
msg->base.stream_info.pvArg, header.pbData, header.cbData,
|
||||
FALSE);
|
||||
LocalFree(header.pbData);
|
||||
}
|
||||
}
|
||||
if (!fFinal)
|
||||
ret = msg->base.stream_info.pfnStreamOutput(
|
||||
msg->base.stream_info.pvArg, (BYTE *)pbData, cbData,
|
||||
FALSE);
|
||||
else
|
||||
{
|
||||
if (msg->base.stream_info.cbContent == 0xffffffff)
|
||||
{
|
||||
BYTE indefinite_trailer[6] = { 0 };
|
||||
|
||||
ret = msg->base.stream_info.pfnStreamOutput(
|
||||
msg->base.stream_info.pvArg, (BYTE *)pbData, cbData,
|
||||
FALSE);
|
||||
if (ret)
|
||||
ret = msg->base.stream_info.pfnStreamOutput(
|
||||
msg->base.stream_info.pvArg, indefinite_trailer,
|
||||
sizeof(indefinite_trailer), TRUE);
|
||||
}
|
||||
else
|
||||
ret = msg->base.stream_info.pfnStreamOutput(
|
||||
msg->base.stream_info.pvArg, (BYTE *)pbData, cbData, TRUE);
|
||||
}
|
||||
}
|
||||
__EXCEPT_PAGE_FAULT
|
||||
{
|
||||
SetLastError(STATUS_ACCESS_VIOLATION);
|
||||
}
|
||||
__ENDTRY;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!fFinal)
|
||||
{
|
||||
if (msg->base.open_flags & CMSG_DETACHED_FLAG)
|
||||
SetLastError(E_INVALIDARG);
|
||||
@ -110,14 +230,13 @@ static BOOL CDataEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
|
||||
{
|
||||
CRYPT_DATA_BLOB blob = { cbData, (LPBYTE)pbData };
|
||||
|
||||
/* data messages don't allow non-final updates, don't bother
|
||||
* checking whether data already exist, they can't.
|
||||
/* non-streamed data messages don't allow non-final updates,
|
||||
* don't bother checking whether data already exist, they can't.
|
||||
*/
|
||||
ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
|
||||
&blob, CRYPT_ENCODE_ALLOC_FLAG, NULL, &msg->bare_content,
|
||||
&msg->bare_content_len);
|
||||
if (ret && msg->base.streamed)
|
||||
FIXME("stream info unimplemented\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
@ -189,6 +308,7 @@ static HCRYPTMSG CDataEncodeMsg_Open(DWORD dwFlags, const void *pvMsgEncodeInfo,
|
||||
CDataEncodeMsg_Close, CDataEncodeMsg_GetParam, CDataEncodeMsg_Update);
|
||||
msg->bare_content_len = sizeof(empty_data_content);
|
||||
msg->bare_content = (LPBYTE)empty_data_content;
|
||||
msg->begun = FALSE;
|
||||
}
|
||||
return (HCRYPTMSG)msg;
|
||||
}
|
||||
|
@ -336,6 +336,7 @@ static void test_data_msg_update(void)
|
||||
{
|
||||
HCRYPTMSG msg;
|
||||
BOOL ret;
|
||||
CMSG_STREAM_INFO streamInfo = { 0 };
|
||||
|
||||
msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL,
|
||||
NULL);
|
||||
@ -383,6 +384,28 @@ static void test_data_msg_update(void)
|
||||
ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
|
||||
ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
|
||||
CryptMsgClose(msg);
|
||||
|
||||
/* Calling update after opening with an empty stream info (with a bogus
|
||||
* output function) yields an error:
|
||||
*/
|
||||
msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL,
|
||||
&streamInfo);
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
|
||||
ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
|
||||
"Expected STATUS_ACCESS_VIOLATION, got %x\n", GetLastError());
|
||||
CryptMsgClose(msg);
|
||||
/* Calling update with a valid output function succeeds, even if the data
|
||||
* exceeds the size specified in the stream info.
|
||||
*/
|
||||
streamInfo.pfnStreamOutput = nop_stream_output;
|
||||
msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL,
|
||||
&streamInfo);
|
||||
ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
|
||||
ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
|
||||
ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
|
||||
ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
|
||||
CryptMsgClose(msg);
|
||||
}
|
||||
|
||||
static void test_data_msg_get_param(void)
|
||||
@ -600,7 +623,6 @@ static void test_data_msg_encoding(void)
|
||||
CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
|
||||
CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
|
||||
CryptMsgClose(msg);
|
||||
todo_wine
|
||||
check_updates("bogus data message with definite length", &a1, &accum);
|
||||
free_updates(&accum);
|
||||
/* A valid definite-length encoding: */
|
||||
@ -609,7 +631,6 @@ static void test_data_msg_encoding(void)
|
||||
NULL, &streamInfo);
|
||||
CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
|
||||
CryptMsgClose(msg);
|
||||
todo_wine
|
||||
check_updates("data message with definite length", &a2, &accum);
|
||||
free_updates(&accum);
|
||||
/* An indefinite-length encoding: */
|
||||
|
Loading…
Reference in New Issue
Block a user