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 "windef.h"
|
||||||
#include "winbase.h"
|
#include "winbase.h"
|
||||||
#include "wincrypt.h"
|
#include "wincrypt.h"
|
||||||
|
#include "snmp.h"
|
||||||
|
|
||||||
#include "wine/debug.h"
|
#include "wine/debug.h"
|
||||||
|
#include "wine/exception.h"
|
||||||
|
#include "crypt32_private.h"
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(crypt);
|
WINE_DEFAULT_DEBUG_CHANNEL(crypt);
|
||||||
|
|
||||||
@ -74,6 +77,7 @@ typedef struct _CDataEncodeMsg
|
|||||||
CryptMsgBase base;
|
CryptMsgBase base;
|
||||||
DWORD bare_content_len;
|
DWORD bare_content_len;
|
||||||
LPBYTE bare_content;
|
LPBYTE bare_content;
|
||||||
|
BOOL begun;
|
||||||
} CDataEncodeMsg;
|
} CDataEncodeMsg;
|
||||||
|
|
||||||
static const BYTE empty_data_content[] = { 0x04,0x00 };
|
static const BYTE empty_data_content[] = { 0x04,0x00 };
|
||||||
@ -86,6 +90,71 @@ static void CDataEncodeMsg_Close(HCRYPTMSG hCryptMsg)
|
|||||||
LocalFree(msg->bare_content);
|
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,
|
static BOOL CDataEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
|
||||||
DWORD cbData, BOOL fFinal)
|
DWORD cbData, BOOL fFinal)
|
||||||
{
|
{
|
||||||
@ -94,7 +163,58 @@ static BOOL CDataEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
|
|||||||
|
|
||||||
if (msg->base.finalized)
|
if (msg->base.finalized)
|
||||||
SetLastError(CRYPT_E_MSG_ERROR);
|
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)
|
if (msg->base.open_flags & CMSG_DETACHED_FLAG)
|
||||||
SetLastError(E_INVALIDARG);
|
SetLastError(E_INVALIDARG);
|
||||||
@ -110,14 +230,13 @@ static BOOL CDataEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
|
|||||||
{
|
{
|
||||||
CRYPT_DATA_BLOB blob = { cbData, (LPBYTE)pbData };
|
CRYPT_DATA_BLOB blob = { cbData, (LPBYTE)pbData };
|
||||||
|
|
||||||
/* data messages don't allow non-final updates, don't bother
|
/* non-streamed data messages don't allow non-final updates,
|
||||||
* checking whether data already exist, they can't.
|
* don't bother checking whether data already exist, they can't.
|
||||||
*/
|
*/
|
||||||
ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
|
ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
|
||||||
&blob, CRYPT_ENCODE_ALLOC_FLAG, NULL, &msg->bare_content,
|
&blob, CRYPT_ENCODE_ALLOC_FLAG, NULL, &msg->bare_content,
|
||||||
&msg->bare_content_len);
|
&msg->bare_content_len);
|
||||||
if (ret && msg->base.streamed)
|
}
|
||||||
FIXME("stream info unimplemented\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@ -189,6 +308,7 @@ static HCRYPTMSG CDataEncodeMsg_Open(DWORD dwFlags, const void *pvMsgEncodeInfo,
|
|||||||
CDataEncodeMsg_Close, CDataEncodeMsg_GetParam, CDataEncodeMsg_Update);
|
CDataEncodeMsg_Close, CDataEncodeMsg_GetParam, CDataEncodeMsg_Update);
|
||||||
msg->bare_content_len = sizeof(empty_data_content);
|
msg->bare_content_len = sizeof(empty_data_content);
|
||||||
msg->bare_content = (LPBYTE)empty_data_content;
|
msg->bare_content = (LPBYTE)empty_data_content;
|
||||||
|
msg->begun = FALSE;
|
||||||
}
|
}
|
||||||
return (HCRYPTMSG)msg;
|
return (HCRYPTMSG)msg;
|
||||||
}
|
}
|
||||||
|
@ -336,6 +336,7 @@ static void test_data_msg_update(void)
|
|||||||
{
|
{
|
||||||
HCRYPTMSG msg;
|
HCRYPTMSG msg;
|
||||||
BOOL ret;
|
BOOL ret;
|
||||||
|
CMSG_STREAM_INFO streamInfo = { 0 };
|
||||||
|
|
||||||
msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL,
|
msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL,
|
||||||
NULL);
|
NULL);
|
||||||
@ -383,6 +384,28 @@ static void test_data_msg_update(void)
|
|||||||
ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
|
ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
|
||||||
ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
|
ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
|
||||||
CryptMsgClose(msg);
|
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)
|
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), FALSE);
|
||||||
CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
|
CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
|
||||||
CryptMsgClose(msg);
|
CryptMsgClose(msg);
|
||||||
todo_wine
|
|
||||||
check_updates("bogus data message with definite length", &a1, &accum);
|
check_updates("bogus data message with definite length", &a1, &accum);
|
||||||
free_updates(&accum);
|
free_updates(&accum);
|
||||||
/* A valid definite-length encoding: */
|
/* A valid definite-length encoding: */
|
||||||
@ -609,7 +631,6 @@ static void test_data_msg_encoding(void)
|
|||||||
NULL, &streamInfo);
|
NULL, &streamInfo);
|
||||||
CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
|
CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
|
||||||
CryptMsgClose(msg);
|
CryptMsgClose(msg);
|
||||||
todo_wine
|
|
||||||
check_updates("data message with definite length", &a2, &accum);
|
check_updates("data message with definite length", &a2, &accum);
|
||||||
free_updates(&accum);
|
free_updates(&accum);
|
||||||
/* An indefinite-length encoding: */
|
/* An indefinite-length encoding: */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user