diff --git a/dlls/crypt32/crypt32_private.h b/dlls/crypt32/crypt32_private.h index a26b36670fb..9b1fc279ebb 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 e2fcc99b092..d63b3897118 100644 --- a/dlls/crypt32/encode.c +++ b/dlls/crypt32/encode.c @@ -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) diff --git a/dlls/crypt32/msg.c b/dlls/crypt32/msg.c index 226c04bd0f1..cd1dd393967 100644 --- a/dlls/crypt32/msg.c +++ b/dlls/crypt32/msg.c @@ -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); diff --git a/dlls/crypt32/tests/msg.c b/dlls/crypt32/tests/msg.c index 18c758be7e4..7a244b5b603 100644 --- a/dlls/crypt32/tests/msg.c +++ b/dlls/crypt32/tests/msg.c @@ -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