Commit b80101eb authored by Juan Lang's avatar Juan Lang Committed by Alexandre Julliard

crypt32: Partially implement encoding signed messages.

parent 71a5859d
......@@ -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
......
......@@ -1540,6 +1540,88 @@ BOOL CRYPT_AsnEncodePKCSDigestedData(CRYPT_DIGESTED_DATA *digestedData,
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)
......
......@@ -627,25 +627,27 @@ static BOOL CRYPT_CopyBlob(CRYPT_DATA_BLOB *out, const CRYPT_DATA_BLOB *in)
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_ATTRIBUTE *out, const CRYPT_ATTRIBUTE *in)
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(HCRYPTMSG hCryptMsg)
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(HCRYPTMSG hCryptMsg, DWORD dwParamType,
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(DWORD dwFlags,
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);
......
......@@ -1289,7 +1289,6 @@ static void test_signed_msg_encoding(void)
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(void)
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(void)
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(void)
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
......
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