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,
|
BOOL CRYPT_AsnEncodePKCSDigestedData(CRYPT_DIGESTED_DATA *digestedData,
|
||||||
void *pvData, DWORD *pcbData);
|
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
|
/* Helper function to check *pcbEncoded, set it to the required size, and
|
||||||
* optionally to allocate memory. Assumes pbEncoded is not NULL.
|
* optionally to allocate memory. Assumes pbEncoded is not NULL.
|
||||||
* If CRYPT_ENCODE_ALLOC_FLAG is set in dwFlags, *pbEncoded will be set to a
|
* 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);
|
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,
|
static BOOL WINAPI CRYPT_AsnEncodePKCSContentInfo(DWORD dwCertEncodingType,
|
||||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
|
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;
|
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;
|
BOOL ret = TRUE;
|
||||||
|
|
||||||
/* Assumption: algorithm IDs will point to static strings, not stack-based
|
out->cBlobs = in->cBlobs;
|
||||||
* ones, so copying the pointer values is safe.
|
if (out->cBlobs)
|
||||||
*/
|
|
||||||
out->pszObjId = in->pszObjId;
|
|
||||||
out->cValue = in->cValue;
|
|
||||||
if (out->cValue)
|
|
||||||
{
|
{
|
||||||
out->rgValue = CryptMemAlloc(out->cValue * sizeof(CRYPT_DATA_BLOB));
|
out->blobs = CryptMemAlloc(out->cBlobs * sizeof(CRYPT_DATA_BLOB));
|
||||||
if (out->rgValue)
|
if (out->blobs)
|
||||||
{
|
{
|
||||||
DWORD i;
|
DWORD i;
|
||||||
|
|
||||||
memset(out->rgValue, 0, out->cValue * sizeof(CRYPT_DATA_BLOB));
|
memset(out->blobs, 0, out->cBlobs * sizeof(CRYPT_DATA_BLOB));
|
||||||
for (i = 0; ret && i < out->cValue; i++)
|
for (i = 0; ret && i < out->cBlobs; i++)
|
||||||
ret = CRYPT_CopyBlob(&out->rgValue[i], &in->rgValue[i]);
|
ret = CRYPT_CopyBlob(&out->blobs[i], &in->blobs[i]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ret = FALSE;
|
ret = FALSE;
|
||||||
|
@ -653,6 +655,25 @@ static BOOL CRYPT_CopyAttribute(CRYPT_ATTRIBUTE *out, const CRYPT_ATTRIBUTE *in)
|
||||||
return ret;
|
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,
|
static BOOL CRYPT_CopyAttributes(CRYPT_ATTRIBUTES *out,
|
||||||
const CRYPT_ATTRIBUTES *in)
|
const CRYPT_ATTRIBUTES *in)
|
||||||
{
|
{
|
||||||
|
@ -749,6 +770,10 @@ typedef struct _CSignedEncodeMsg
|
||||||
CRYPT_DATA_BLOB data;
|
CRYPT_DATA_BLOB data;
|
||||||
DWORD cSigners;
|
DWORD cSigners;
|
||||||
CSignerInfo *signers;
|
CSignerInfo *signers;
|
||||||
|
DWORD cCertEncoded;
|
||||||
|
PCERT_BLOB rgCertEncoded;
|
||||||
|
DWORD cCrlEncoded;
|
||||||
|
PCRL_BLOB rgCrlEncoded;
|
||||||
} CSignedEncodeMsg;
|
} CSignedEncodeMsg;
|
||||||
|
|
||||||
static void CSignedEncodeMsg_Close(HCRYPTMSG hCryptMsg)
|
static void CSignedEncodeMsg_Close(HCRYPTMSG hCryptMsg)
|
||||||
|
@ -757,6 +782,8 @@ static void CSignedEncodeMsg_Close(HCRYPTMSG hCryptMsg)
|
||||||
DWORD i;
|
DWORD i;
|
||||||
|
|
||||||
CryptMemFree(msg->data.pbData);
|
CryptMemFree(msg->data.pbData);
|
||||||
|
CRYPT_FreeBlobArray((BlobArray *)&msg->cCertEncoded);
|
||||||
|
CRYPT_FreeBlobArray((BlobArray *)&msg->cCrlEncoded);
|
||||||
for (i = 0; i < msg->cSigners; i++)
|
for (i = 0; i < msg->cSigners; i++)
|
||||||
CSignerInfo_Free(&msg->signers[i]);
|
CSignerInfo_Free(&msg->signers[i]);
|
||||||
CryptMemFree(msg->signers);
|
CryptMemFree(msg->signers);
|
||||||
|
@ -770,6 +797,55 @@ static BOOL CSignedEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
|
||||||
|
|
||||||
switch (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:
|
case CMSG_COMPUTED_HASH_PARAM:
|
||||||
if (dwIndex >= msg->cSigners)
|
if (dwIndex >= msg->cSigners)
|
||||||
SetLastError(CRYPT_E_INVALID_INDEX);
|
SetLastError(CRYPT_E_INVALID_INDEX);
|
||||||
|
@ -931,6 +1007,12 @@ static HCRYPTMSG CSignedEncodeMsg_Open(DWORD dwFlags,
|
||||||
else
|
else
|
||||||
ret = FALSE;
|
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)
|
if (!ret)
|
||||||
{
|
{
|
||||||
CSignedEncodeMsg_Close(msg);
|
CSignedEncodeMsg_Close(msg);
|
||||||
|
|
|
@ -1289,7 +1289,6 @@ static void test_signed_msg_encoding(void)
|
||||||
CMSG_DETACHED_FLAG, CMSG_SIGNED, &signInfo, NULL, NULL);
|
CMSG_DETACHED_FLAG, CMSG_SIGNED, &signInfo, NULL, NULL);
|
||||||
ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
|
ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
|
||||||
|
|
||||||
todo_wine
|
|
||||||
check_param("detached signed empty bare content", msg,
|
check_param("detached signed empty bare content", msg,
|
||||||
CMSG_BARE_CONTENT_PARAM, signedEmptyBareContent,
|
CMSG_BARE_CONTENT_PARAM, signedEmptyBareContent,
|
||||||
sizeof(signedEmptyBareContent));
|
sizeof(signedEmptyBareContent));
|
||||||
|
@ -1300,7 +1299,6 @@ static void test_signed_msg_encoding(void)
|
||||||
ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
|
ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
|
||||||
check_param("detached signed hash", msg, CMSG_COMPUTED_HASH_PARAM,
|
check_param("detached signed hash", msg, CMSG_COMPUTED_HASH_PARAM,
|
||||||
signedHash, sizeof(signedHash));
|
signedHash, sizeof(signedHash));
|
||||||
todo_wine
|
|
||||||
check_param("detached signed bare content", msg, CMSG_BARE_CONTENT_PARAM,
|
check_param("detached signed bare content", msg, CMSG_BARE_CONTENT_PARAM,
|
||||||
detachedSignedBareContent, sizeof(detachedSignedBareContent));
|
detachedSignedBareContent, sizeof(detachedSignedBareContent));
|
||||||
todo_wine
|
todo_wine
|
||||||
|
@ -1317,7 +1315,6 @@ static void test_signed_msg_encoding(void)
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
|
ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
|
||||||
|
|
||||||
todo_wine
|
|
||||||
check_param("signed empty bare content", msg, CMSG_BARE_CONTENT_PARAM,
|
check_param("signed empty bare content", msg, CMSG_BARE_CONTENT_PARAM,
|
||||||
signedEmptyBareContent, sizeof(signedEmptyBareContent));
|
signedEmptyBareContent, sizeof(signedEmptyBareContent));
|
||||||
todo_wine
|
todo_wine
|
||||||
|
@ -1325,7 +1322,6 @@ static void test_signed_msg_encoding(void)
|
||||||
signedEmptyContent, sizeof(signedEmptyContent));
|
signedEmptyContent, sizeof(signedEmptyContent));
|
||||||
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());
|
||||||
todo_wine
|
|
||||||
check_param("signed bare content", msg, CMSG_BARE_CONTENT_PARAM,
|
check_param("signed bare content", msg, CMSG_BARE_CONTENT_PARAM,
|
||||||
signedBareContent, sizeof(signedBareContent));
|
signedBareContent, sizeof(signedBareContent));
|
||||||
todo_wine
|
todo_wine
|
||||||
|
|
Loading…
Reference in New Issue