crypt32: Partially implement encoding signed messages.
This commit is contained in:
parent
71a5859ded
commit
b80101eb65
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue