crypt32(12/20): Partially implement encoding signed messages
Juan Lang
juan.lang at gmail.com
Mon Jul 23 20:30:40 CDT 2007
--Juan
-------------- next part --------------
From 62421d182d0d2a68c07a3ba585e388149a8e0841 Mon Sep 17 00:00:00 2001
From: Juan Lang <juanlang at juan.corp.google.com>
Date: Mon, 23 Jul 2007 18:11:17 -0700
Subject: [PATCH] Partially implement encoding signed messages
---
dlls/crypt32/crypt32_private.h | 17 ++++++
dlls/crypt32/encode.c | 82 +++++++++++++++++++++++++++++++
dlls/crypt32/msg.c | 106 +++++++++++++++++++++++++++++++++++-----
dlls/crypt32/tests/msg.c | 4 --
4 files changed, 193 insertions(+), 16 deletions(-)
diff --git a/dlls/crypt32/crypt32_private.h b/dlls/crypt32/crypt32_private.h
index a26b366..9b1fc27 100644
--- a/dlls/crypt32/crypt32_private.h
+++ b/dlls/crypt32/crypt32_private.h
@@ -82,6 +82,23 @@ typedef struct _CRYPT_DIGESTED_DATA
BOOL CRYPT_AsnEncodePKCSDigestedData(CRYPT_DIGESTED_DATA *digestedData,
void *pvData, DWORD *pcbData);
+typedef struct _CRYPT_SIGNED_INFO
+{
+ DWORD version;
+ DWORD cCertEncoded;
+ PCERT_BLOB rgCertEncoded;
+ DWORD cCrlEncoded;
+ PCRL_BLOB rgCrlEncoded;
+ DWORD cAttrCertEncoded;
+ PCERT_BLOB rgAttrCertEncoded;
+ CRYPT_CONTENT_INFO content;
+ DWORD cSignerInfo;
+ PCMSG_SIGNER_INFO rgSignerInfo;
+} CRYPT_SIGNED_INFO;
+
+BOOL CRYPT_AsnEncodePKCSSignedInfo(CRYPT_SIGNED_INFO *, void *pvData,
+ DWORD *pcbData);
+
/* Helper function to check *pcbEncoded, set it to the required size, and
* optionally to allocate memory. Assumes pbEncoded is not NULL.
* If CRYPT_ENCODE_ALLOC_FLAG is set in dwFlags, *pbEncoded will be set to a
diff --git a/dlls/crypt32/encode.c b/dlls/crypt32/encode.c
index e2fcc99..d63b389 100644
--- a/dlls/crypt32/encode.c
+++ b/dlls/crypt32/encode.c
@@ -1540,6 +1540,88 @@ BOOL CRYPT_AsnEncodePKCSDigestedData(CRY
sizeof(items) / sizeof(items[0]), 0, NULL, pvData, pcbData);
}
+BOOL CRYPT_AsnEncodePKCSSignedInfo(CRYPT_SIGNED_INFO *signedInfo, void *pvData,
+ DWORD *pcbData)
+{
+ struct AsnEncodeSequenceItem items[7] = {
+ { &signedInfo->version, CRYPT_AsnEncodeInt, 0 },
+ };
+ CRYPT_SET_OF digestAlgorithmsSet = { 0, NULL }, signerSet = { 0, NULL };
+ DWORD i, cItem = 1;
+ BOOL ret = TRUE;
+
+ if (signedInfo->cCertEncoded)
+ FIXME("unimplemented for certs\n");
+ if (signedInfo->cCrlEncoded)
+ FIXME("unimplemented for CRLs\n");
+ if (signedInfo->cAttrCertEncoded)
+ FIXME("unimplemented for attr certs\n");
+ if (signedInfo->cSignerInfo)
+ {
+ digestAlgorithmsSet.cValue = signedInfo->cSignerInfo;
+ digestAlgorithmsSet.rgValue =
+ CryptMemAlloc(digestAlgorithmsSet.cValue * sizeof(CRYPT_DER_BLOB));
+ if (digestAlgorithmsSet.rgValue)
+ {
+ memset(digestAlgorithmsSet.rgValue, 0,
+ digestAlgorithmsSet.cValue * sizeof(CRYPT_DER_BLOB));
+ for (i = 0; ret && i < digestAlgorithmsSet.cValue; i++)
+ ret = CRYPT_AsnEncodeAlgorithmIdWithNullParams(0, NULL,
+ &signedInfo->rgSignerInfo[i].HashAlgorithm,
+ CRYPT_ENCODE_ALLOC_FLAG, NULL,
+ (BYTE *)&digestAlgorithmsSet.rgValue[i].pbData,
+ &digestAlgorithmsSet.rgValue[i].cbData);
+ }
+ else
+ ret = FALSE;
+ if (ret)
+ {
+ items[cItem].pvStructInfo = &digestAlgorithmsSet;
+ items[cItem].encodeFunc = CRYPT_DEREncodeSet;
+ cItem++;
+ }
+ }
+ items[cItem].pvStructInfo = &signedInfo->content;
+ items[cItem].encodeFunc = CRYPT_AsnEncodePKCSContentInfoInternal;
+ cItem++;
+ if (ret && signedInfo->cSignerInfo)
+ {
+ signerSet.cValue = signedInfo->cSignerInfo;
+ signerSet.rgValue =
+ CryptMemAlloc(signerSet.cValue * sizeof(CRYPT_DER_BLOB));
+ if (signerSet.rgValue)
+ {
+ memset(signerSet.rgValue, 0,
+ signerSet.cValue * sizeof(CRYPT_DER_BLOB));
+ for (i = 0; ret && i < signerSet.cValue; i++)
+ ret = CryptEncodeObjectEx(
+ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS7_SIGNER_INFO,
+ &signedInfo->rgSignerInfo[i], CRYPT_ENCODE_ALLOC_FLAG, NULL,
+ &signerSet.rgValue[i].pbData, &signerSet.rgValue[i].cbData);
+ }
+ else
+ ret = FALSE;
+ if (ret)
+ {
+ items[cItem].pvStructInfo = &signerSet;
+ items[cItem].encodeFunc = CRYPT_DEREncodeSet;
+ cItem++;
+ }
+ }
+ if (ret)
+ ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
+ pvData, pcbData);
+
+ for (i = 0; i < digestAlgorithmsSet.cValue; i++)
+ LocalFree(digestAlgorithmsSet.rgValue[i].pbData);
+ CryptMemFree(digestAlgorithmsSet.rgValue);
+ for (i = 0; i < signerSet.cValue; i++)
+ LocalFree(signerSet.rgValue[i].pbData);
+ CryptMemFree(signerSet.rgValue);
+
+ return ret;
+}
+
static BOOL WINAPI CRYPT_AsnEncodePKCSContentInfo(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
diff --git a/dlls/crypt32/msg.c b/dlls/crypt32/msg.c
index 226c04b..cd1dd39 100644
--- a/dlls/crypt32/msg.c
+++ b/dlls/crypt32/msg.c
@@ -627,25 +627,27 @@ static BOOL CRYPT_CopyBlob(CRYPT_DATA_BL
return ret;
}
-static BOOL CRYPT_CopyAttribute(CRYPT_ATTRIBUTE *out, const CRYPT_ATTRIBUTE *in)
+typedef struct _BlobArray
+{
+ DWORD cBlobs;
+ PCRYPT_DATA_BLOB blobs;
+} BlobArray;
+
+static BOOL CRYPT_CopyBlobArray(BlobArray *out, const BlobArray *in)
{
BOOL ret = TRUE;
- /* Assumption: algorithm IDs will point to static strings, not stack-based
- * ones, so copying the pointer values is safe.
- */
- out->pszObjId = in->pszObjId;
- out->cValue = in->cValue;
- if (out->cValue)
+ out->cBlobs = in->cBlobs;
+ if (out->cBlobs)
{
- out->rgValue = CryptMemAlloc(out->cValue * sizeof(CRYPT_DATA_BLOB));
- if (out->rgValue)
+ out->blobs = CryptMemAlloc(out->cBlobs * sizeof(CRYPT_DATA_BLOB));
+ if (out->blobs)
{
DWORD i;
- memset(out->rgValue, 0, out->cValue * sizeof(CRYPT_DATA_BLOB));
- for (i = 0; ret && i < out->cValue; i++)
- ret = CRYPT_CopyBlob(&out->rgValue[i], &in->rgValue[i]);
+ memset(out->blobs, 0, out->cBlobs * sizeof(CRYPT_DATA_BLOB));
+ for (i = 0; ret && i < out->cBlobs; i++)
+ ret = CRYPT_CopyBlob(&out->blobs[i], &in->blobs[i]);
}
else
ret = FALSE;
@@ -653,6 +655,25 @@ static BOOL CRYPT_CopyAttribute(CRYPT_AT
return ret;
}
+static void CRYPT_FreeBlobArray(BlobArray *array)
+{
+ DWORD i;
+
+ for (i = 0; i < array->cBlobs; i++)
+ CryptMemFree(array->blobs[i].pbData);
+ CryptMemFree(array->blobs);
+}
+
+static BOOL CRYPT_CopyAttribute(CRYPT_ATTRIBUTE *out, const CRYPT_ATTRIBUTE *in)
+{
+ /* Assumption: algorithm IDs will point to static strings, not stack-based
+ * ones, so copying the pointer values is safe.
+ */
+ out->pszObjId = in->pszObjId;
+ return CRYPT_CopyBlobArray((BlobArray *)&out->cValue,
+ (const BlobArray *)&in->cValue);
+}
+
static BOOL CRYPT_CopyAttributes(CRYPT_ATTRIBUTES *out,
const CRYPT_ATTRIBUTES *in)
{
@@ -749,6 +770,10 @@ typedef struct _CSignedEncodeMsg
CRYPT_DATA_BLOB data;
DWORD cSigners;
CSignerInfo *signers;
+ DWORD cCertEncoded;
+ PCERT_BLOB rgCertEncoded;
+ DWORD cCrlEncoded;
+ PCRL_BLOB rgCrlEncoded;
} CSignedEncodeMsg;
static void CSignedEncodeMsg_Close(HCRYPTMSG hCryptMsg)
@@ -757,6 +782,8 @@ static void CSignedEncodeMsg_Close(HCRYP
DWORD i;
CryptMemFree(msg->data.pbData);
+ CRYPT_FreeBlobArray((BlobArray *)&msg->cCertEncoded);
+ CRYPT_FreeBlobArray((BlobArray *)&msg->cCrlEncoded);
for (i = 0; i < msg->cSigners; i++)
CSignerInfo_Free(&msg->signers[i]);
CryptMemFree(msg->signers);
@@ -770,6 +797,55 @@ static BOOL CSignedEncodeMsg_GetParam(HC
switch (dwParamType)
{
+ case CMSG_BARE_CONTENT_PARAM:
+ {
+ CRYPT_SIGNED_INFO info;
+ char oid_rsa_data[] = szOID_RSA_data;
+
+ /* Note: needs to change if CMS fields are supported */
+ info.version = CMSG_SIGNED_DATA_V1;
+ info.cCertEncoded = msg->cCertEncoded;
+ info.rgCertEncoded = msg->rgCertEncoded;
+ info.cCrlEncoded = msg->cCrlEncoded;
+ info.rgCrlEncoded = msg->rgCrlEncoded;
+ info.cAttrCertEncoded = 0;
+ info.cSignerInfo = msg->cSigners;
+ /* Quirk: OID is only encoded messages if an update has happened */
+ if (msg->base.state != MsgStateInit)
+ info.content.pszObjId = oid_rsa_data;
+ else
+ info.content.pszObjId = NULL;
+ if (msg->data.cbData)
+ {
+ CRYPT_DATA_BLOB blob = { msg->data.cbData, msg->data.pbData };
+
+ ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
+ &blob, CRYPT_ENCODE_ALLOC_FLAG, NULL,
+ &info.content.Content.pbData, &info.content.Content.cbData);
+ }
+ else
+ {
+ info.content.Content.cbData = 0;
+ info.content.Content.pbData = NULL;
+ ret = TRUE;
+ }
+ if (ret)
+ {
+ info.rgSignerInfo =
+ CryptMemAlloc(msg->cSigners * sizeof(CMSG_SIGNER_INFO));
+ if (info.rgSignerInfo)
+ {
+ DWORD i;
+
+ for (i = 0; i < info.cSignerInfo; i++)
+ info.rgSignerInfo[i] = msg->signers[i].info;
+ ret = CRYPT_AsnEncodePKCSSignedInfo(&info, pvData, pcbData);
+ CryptMemFree(info.rgSignerInfo);
+ }
+ LocalFree(info.content.Content.pbData);
+ }
+ break;
+ }
case CMSG_COMPUTED_HASH_PARAM:
if (dwIndex >= msg->cSigners)
SetLastError(CRYPT_E_INVALID_INDEX);
@@ -931,6 +1007,12 @@ static HCRYPTMSG CSignedEncodeMsg_Open(D
else
ret = FALSE;
}
+ if (ret)
+ ret = CRYPT_CopyBlobArray((BlobArray *)&msg->cCertEncoded,
+ (const BlobArray *)&info->cCertEncoded);
+ if (ret)
+ ret = CRYPT_CopyBlobArray((BlobArray *)&msg->cCrlEncoded,
+ (const BlobArray *)&info->cCrlEncoded);
if (!ret)
{
CSignedEncodeMsg_Close(msg);
diff --git a/dlls/crypt32/tests/msg.c b/dlls/crypt32/tests/msg.c
index 18c758b..7a244b5 100644
--- a/dlls/crypt32/tests/msg.c
+++ b/dlls/crypt32/tests/msg.c
@@ -1289,7 +1289,6 @@ static void test_signed_msg_encoding(voi
CMSG_DETACHED_FLAG, CMSG_SIGNED, &signInfo, NULL, NULL);
ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
- todo_wine
check_param("detached signed empty bare content", msg,
CMSG_BARE_CONTENT_PARAM, signedEmptyBareContent,
sizeof(signedEmptyBareContent));
@@ -1300,7 +1299,6 @@ static void test_signed_msg_encoding(voi
ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
check_param("detached signed hash", msg, CMSG_COMPUTED_HASH_PARAM,
signedHash, sizeof(signedHash));
- todo_wine
check_param("detached signed bare content", msg, CMSG_BARE_CONTENT_PARAM,
detachedSignedBareContent, sizeof(detachedSignedBareContent));
todo_wine
@@ -1317,7 +1315,6 @@ static void test_signed_msg_encoding(voi
NULL, NULL);
ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
- todo_wine
check_param("signed empty bare content", msg, CMSG_BARE_CONTENT_PARAM,
signedEmptyBareContent, sizeof(signedEmptyBareContent));
todo_wine
@@ -1325,7 +1322,6 @@ static void test_signed_msg_encoding(voi
signedEmptyContent, sizeof(signedEmptyContent));
ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
- todo_wine
check_param("signed bare content", msg, CMSG_BARE_CONTENT_PARAM,
signedBareContent, sizeof(signedBareContent));
todo_wine
--
1.4.1
More information about the wine-patches
mailing list