crypt32(2/25): Implement streamed encoding of definite-length data
messages
Juan Lang
juan.lang at gmail.com
Thu Jul 12 17:15:10 CDT 2007
Depends on patch 1/25 in this series.
--Juan
-------------- next part --------------
From b37155b02281dca195e0b67e801c3535d0f702ad Mon Sep 17 00:00:00 2001
From: Juan Lang <juanlang at juan.corp.google.com>
Date: Thu, 12 Jul 2007 14:20:20 -0700
Subject: [PATCH] Implement streamed encoding of definite-length data messages
---
dlls/crypt32/msg.c | 156 +++++++++++++++++++++++++++++++++++++++++-----
dlls/crypt32/tests/msg.c | 25 +++++++
2 files changed, 161 insertions(+), 20 deletions(-)
diff --git a/dlls/crypt32/msg.c b/dlls/crypt32/msg.c
index 63f6671..299b97e 100644
--- a/dlls/crypt32/msg.c
+++ b/dlls/crypt32/msg.c
@@ -19,8 +19,11 @@ #include <stdarg.h>
#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(HCRYPTM
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,30 +163,80 @@ static BOOL CDataEncodeMsg_Update(HCRYPT
if (msg->base.finalized)
SetLastError(CRYPT_E_MSG_ERROR);
- else if (!fFinal)
+ else if (msg->base.streamed)
{
- if (msg->base.open_flags & CMSG_DETACHED_FLAG)
- SetLastError(E_INVALIDARG);
- else
- SetLastError(CRYPT_E_MSG_ERROR);
+ 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
{
- msg->base.finalized = TRUE;
- if (!cbData)
- SetLastError(E_INVALIDARG);
+ if (!fFinal)
+ {
+ if (msg->base.open_flags & CMSG_DETACHED_FLAG)
+ SetLastError(E_INVALIDARG);
+ else
+ SetLastError(CRYPT_E_MSG_ERROR);
+ }
else
{
- 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.
- */
- 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");
+ msg->base.finalized = TRUE;
+ if (!cbData)
+ SetLastError(E_INVALIDARG);
+ else
+ {
+ CRYPT_DATA_BLOB blob = { cbData, (LPBYTE)pbData };
+
+ /* 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);
+ }
}
}
return ret;
@@ -189,6 +308,7 @@ static HCRYPTMSG CDataEncodeMsg_Open(DWO
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;
}
diff --git a/dlls/crypt32/tests/msg.c b/dlls/crypt32/tests/msg.c
index 1e987d2..4898c6e 100644
--- a/dlls/crypt32/tests/msg.c
+++ b/dlls/crypt32/tests/msg.c
@@ -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: */
--
1.4.1
More information about the wine-patches
mailing list