From d5a478edfa98164665d83ba6989aca499910752f Mon Sep 17 00:00:00 2001 From: Juan Lang Date: Wed, 25 Jul 2007 18:15:16 -0700 Subject: [PATCH] crypt32: Test and implement encoding signed messages with authenticated attributes. --- dlls/crypt32/msg.c | 155 ++++++++++++++++++++++++++++++++++----- dlls/crypt32/tests/msg.c | 37 ++++++++++ 2 files changed, 174 insertions(+), 18 deletions(-) diff --git a/dlls/crypt32/msg.c b/dlls/crypt32/msg.c index 7ccfb53056f..d932815ee4e 100644 --- a/dlls/crypt32/msg.c +++ b/dlls/crypt32/msg.c @@ -604,7 +604,8 @@ static BOOL CRYPT_IsValidSigner(CMSG_SIGNER_ENCODE_INFO_WITH_CMS *signer) typedef struct _CSignerHandles { HCRYPTPROV prov; - HCRYPTHASH hash; + HCRYPTHASH contentHash; + HCRYPTHASH authAttrHash; HCRYPTKEY key; } CSignerHandles; @@ -665,12 +666,18 @@ static void CRYPT_FreeBlobArray(BlobArray *array) 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); + BOOL ret; + + out->pszObjId = CryptMemAlloc(strlen(in->pszObjId) + 1); + if (out->pszObjId) + { + strcpy(out->pszObjId, in->pszObjId); + ret = CRYPT_CopyBlobArray((BlobArray *)&out->cValue, + (const BlobArray *)&in->cValue); + } + else + ret = FALSE; + return ret; } static BOOL CRYPT_CopyAttributes(CRYPT_ATTRIBUTES *out, @@ -711,7 +718,10 @@ static BOOL CSignerInfo_Construct(CSignerHandles *handles, if (!(open_flags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG)) CryptContextAddRef(handles->prov, NULL, 0); algID = CertOIDToAlgId(in->HashAlgorithm.pszObjId); - ret = CryptCreateHash(handles->prov, algID, 0, 0, &handles->hash); + ret = CryptCreateHash(handles->prov, algID, 0, 0, &handles->contentHash); + if (ret && in->cAuthAttr) + ret = CryptCreateHash(handles->prov, algID, 0, 0, + &handles->authAttrHash); if (ret) { /* Note: needs to change if CMS fields are supported */ @@ -752,6 +762,7 @@ static void CSignerInfo_Free(CMSG_SIGNER_INFO *info) for (j = 0; j < info->AuthAttrs.rgAttr[i].cValue; j++) CryptMemFree(info->AuthAttrs.rgAttr[i].rgValue[j].pbData); CryptMemFree(info->AuthAttrs.rgAttr[i].rgValue); + CryptMemFree(info->AuthAttrs.rgAttr[i].pszObjId); } CryptMemFree(info->AuthAttrs.rgAttr); for (i = 0; i < info->UnauthAttrs.cAttr; i++) @@ -759,6 +770,7 @@ static void CSignerInfo_Free(CMSG_SIGNER_INFO *info) for (j = 0; j < info->UnauthAttrs.rgAttr[i].cValue; j++) CryptMemFree(info->UnauthAttrs.rgAttr[i].rgValue[j].pbData); CryptMemFree(info->UnauthAttrs.rgAttr[i].rgValue); + CryptMemFree(info->UnauthAttrs.rgAttr[i].pszObjId); } CryptMemFree(info->UnauthAttrs.rgAttr); } @@ -783,7 +795,8 @@ static void CSignedEncodeMsg_Close(HCRYPTMSG hCryptMsg) { CSignerInfo_Free(&msg->info.rgSignerInfo[i]); CryptDestroyKey(msg->signerHandles[i].key); - CryptDestroyHash(msg->signerHandles[i].hash); + CryptDestroyHash(msg->signerHandles[i].contentHash); + CryptDestroyHash(msg->signerHandles[i].authAttrHash); CryptReleaseContext(msg->signerHandles[i].prov, 0); } CryptMemFree(msg->signerHandles); @@ -862,7 +875,7 @@ static BOOL CSignedEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType, if (dwIndex >= msg->info.cSignerInfo) SetLastError(CRYPT_E_INVALID_INDEX); else - ret = CryptGetHashParam(msg->signerHandles[dwIndex].hash, + ret = CryptGetHashParam(msg->signerHandles[dwIndex].contentHash, HP_HASHVAL, pvData, pcbData, 0); break; case CMSG_ENCODED_SIGNER: @@ -892,7 +905,103 @@ static BOOL CSignedEncodeMsg_UpdateHash(CSignedEncodeMsg *msg, TRACE("(%p, %p, %d)\n", msg, pbData, cbData); for (i = 0; ret && i < msg->info.cSignerInfo; i++) - ret = CryptHashData(msg->signerHandles[i].hash, pbData, cbData, 0); + ret = CryptHashData(msg->signerHandles[i].contentHash, pbData, cbData, + 0); + return ret; +} + +static BOOL CRYPT_AppendAttribute(CRYPT_ATTRIBUTES *out, + const CRYPT_ATTRIBUTE *in) +{ + BOOL ret = FALSE; + + out->rgAttr = CryptMemRealloc(out->rgAttr, + (out->cAttr + 1) * sizeof(CRYPT_ATTRIBUTE)); + if (out->rgAttr) + { + ret = CRYPT_CopyAttribute(&out->rgAttr[out->cAttr], in); + if (ret) + out->cAttr++; + } + return ret; +} + +static BOOL CSignedEncodeMsg_AppendMessageDigestAttribute(CSignedEncodeMsg *msg, + DWORD signerIndex) +{ + BOOL ret; + DWORD size; + CRYPT_HASH_BLOB hash = { 0, NULL }, encodedHash = { 0, NULL }; + char messageDigest[] = szOID_RSA_messageDigest; + CRYPT_ATTRIBUTE messageDigestAttr = { messageDigest, 1, &encodedHash }; + + size = sizeof(DWORD); + ret = CryptGetHashParam(msg->signerHandles[signerIndex].contentHash, + HP_HASHSIZE, (LPBYTE)&hash.cbData, &size, 0); + if (ret) + { + hash.pbData = CryptMemAlloc(hash.cbData); + ret = CryptGetHashParam(msg->signerHandles[signerIndex].contentHash, + HP_HASHVAL, hash.pbData, &hash.cbData, 0); + if (ret) + { + ret = CRYPT_AsnEncodeOctets(0, NULL, &hash, CRYPT_ENCODE_ALLOC_FLAG, + NULL, (LPBYTE)&encodedHash.pbData, &encodedHash.cbData); + if (ret) + { + ret = CRYPT_AppendAttribute( + &msg->info.rgSignerInfo[signerIndex].AuthAttrs, + &messageDigestAttr); + LocalFree(encodedHash.pbData); + } + } + CryptMemFree(hash.pbData); + } + return ret; +} + +static BOOL CSignedEncodeMsg_UpdateAuthenticatedAttributes( + CSignedEncodeMsg *msg) +{ + DWORD i; + BOOL ret = TRUE; + + TRACE("(%p)\n", msg); + + for (i = 0; ret && i < msg->info.cSignerInfo; i++) + { + if (msg->info.rgSignerInfo[i].AuthAttrs.cAttr) + { + BYTE oid_rsa_data_encoded[] = { 0x06,0x09,0x2a,0x86,0x48,0x86,0xf7, + 0x0d,0x01,0x07,0x01 }; + CRYPT_DATA_BLOB content = { sizeof(oid_rsa_data_encoded), + oid_rsa_data_encoded }; + char contentType[] = szOID_RSA_contentType; + CRYPT_ATTRIBUTE contentTypeAttr = { contentType, 1, &content }; + + /* FIXME: does this depend on inner OID? */ + ret = CRYPT_AppendAttribute(&msg->info.rgSignerInfo[i].AuthAttrs, + &contentTypeAttr); + if (ret) + ret = CSignedEncodeMsg_AppendMessageDigestAttribute(msg, i); + if (ret) + { + LPBYTE encodedAttrs; + DWORD size; + + ret = CryptEncodeObjectEx(X509_ASN_ENCODING, PKCS_ATTRIBUTES, + &msg->info.rgSignerInfo[i].AuthAttrs, CRYPT_ENCODE_ALLOC_FLAG, + NULL, (LPBYTE)&encodedAttrs, &size); + if (ret) + { + ret = CryptHashData(msg->signerHandles[i].authAttrHash, + encodedAttrs, size, 0); + LocalFree(encodedAttrs); + } + } + } + } + TRACE("returning %d\n", ret); return ret; } @@ -918,16 +1027,22 @@ static BOOL CSignedEncodeMsg_Sign(CSignedEncodeMsg *msg) for (i = 0; ret && i < msg->info.cSignerInfo; i++) { - ret = CryptSignHashW(msg->signerHandles[i].hash, AT_SIGNATURE, NULL, 0, - NULL, &msg->info.rgSignerInfo[i].EncryptedHash.cbData); + HCRYPTHASH hash; + + if (msg->info.rgSignerInfo[i].AuthAttrs.cAttr) + hash = msg->signerHandles[i].authAttrHash; + else + hash = msg->signerHandles[i].contentHash; + ret = CryptSignHashW(hash, AT_SIGNATURE, NULL, 0, NULL, + &msg->info.rgSignerInfo[i].EncryptedHash.cbData); if (ret) { msg->info.rgSignerInfo[i].EncryptedHash.pbData = CryptMemAlloc(msg->info.rgSignerInfo[i].EncryptedHash.cbData); if (msg->info.rgSignerInfo[i].EncryptedHash.pbData) { - ret = CryptSignHashW(msg->signerHandles[i].hash, AT_SIGNATURE, - NULL, 0, msg->info.rgSignerInfo[i].EncryptedHash.pbData, + ret = CryptSignHashW(hash, AT_SIGNATURE, NULL, 0, + msg->info.rgSignerInfo[i].EncryptedHash.pbData, &msg->info.rgSignerInfo[i].EncryptedHash.cbData); if (ret) CRYPT_ReverseBytes(&msg->info.rgSignerInfo[i].EncryptedHash); @@ -948,9 +1063,12 @@ static BOOL CSignedEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData, if (msg->base.streamed || (msg->base.open_flags & CMSG_DETACHED_FLAG)) { ret = CSignedEncodeMsg_UpdateHash(msg, pbData, cbData); - /* FIXME: hash authenticated attributes on final update */ if (ret && fFinal) - ret = CSignedEncodeMsg_Sign(msg); + { + ret = CSignedEncodeMsg_UpdateAuthenticatedAttributes(msg); + if (ret) + ret = CSignedEncodeMsg_Sign(msg); + } if (msg->base.streamed) FIXME("streamed partial stub\n"); } @@ -974,7 +1092,8 @@ static BOOL CSignedEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData, ret = TRUE; if (ret) ret = CSignedEncodeMsg_UpdateHash(msg, pbData, cbData); - /* FIXME: hash authenticated attributes */ + if (ret) + ret = CSignedEncodeMsg_UpdateAuthenticatedAttributes(msg); if (ret) ret = CSignedEncodeMsg_Sign(msg); } diff --git a/dlls/crypt32/tests/msg.c b/dlls/crypt32/tests/msg.c index ad4113a7e0c..8cfb72c8fde 100644 --- a/dlls/crypt32/tests/msg.c +++ b/dlls/crypt32/tests/msg.c @@ -1265,6 +1265,25 @@ static const BYTE signedEncodedSigner[] = { 0xa9,0xaa,0x6e,0xe9,0x2c,0xa0,0x1e,0xee,0xc2,0x60,0xbc,0x59,0xbe,0x3f,0x63, 0x06,0x8d,0xc9,0x11,0x1d,0x23,0x64,0x92,0xef,0x2e,0xfc,0x57,0x29,0xa4,0xaf, 0xe0,0xee,0x93,0x19,0x39,0x51,0xe4,0x44,0xb8,0x0b,0x28,0xf4,0xa8,0x0d }; +static const BYTE signedWithAuthAttrsBareContent[] = { +0x30,0x82,0x01,0x00,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x13,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x06,0x04,0x04,0x01,0x02,0x03,0x04,0x31, +0x81,0xd5,0x30,0x81,0xd2,0x02,0x01,0x01,0x30,0x1a,0x30,0x15,0x31,0x13,0x30, +0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61, +0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7, +0x0d,0x02,0x05,0x05,0x00,0xa0,0x5b,0x30,0x18,0x06,0x09,0x2a,0x86,0x48,0x86, +0xf7,0x0d,0x01,0x09,0x03,0x31,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x01,0x07,0x01,0x30,0x1e,0x06,0x03,0x55,0x04,0x03,0x31,0x17,0x30,0x15,0x31, +0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20, +0x4c,0x61,0x6e,0x67,0x00,0x30,0x1f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x01,0x09,0x04,0x31,0x12,0x04,0x10,0x08,0xd6,0xc0,0x5a,0x21,0x51,0x2a,0x79, +0xa1,0xdf,0xeb,0x9d,0x2a,0x8f,0x26,0x2f,0x30,0x04,0x06,0x00,0x05,0x00,0x04, +0x40,0xbf,0x65,0xde,0x7a,0x3e,0xa2,0x19,0x59,0xc3,0xc7,0x02,0x53,0xc9,0x72, +0xcd,0x74,0x96,0x70,0x0b,0x3b,0xcf,0x8b,0xd9,0x17,0x5c,0xc5,0xd1,0x83,0x41, +0x32,0x93,0xa6,0xf3,0x52,0x83,0x94,0xa9,0x6b,0x0a,0x92,0xcf,0xaf,0x12,0xfa, +0x40,0x53,0x12,0x84,0x03,0xab,0x10,0xa2,0x3d,0xe6,0x9f,0x5a,0xbf,0xc5,0xb8, +0xff,0xc6,0x33,0x63,0x34 }; static BYTE cert[] = { 0x30,0x7a,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30,0x11, 0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, @@ -1393,6 +1412,10 @@ static void test_signed_msg_encoding(void) CERT_INFO certInfo = { 0 }; CERT_BLOB encodedCert = { sizeof(cert), cert }; CRL_BLOB encodedCrl = { sizeof(crl), crl }; + char oid_common_name[] = szOID_COMMON_NAME; + CRYPT_ATTR_BLOB commonName = { sizeof(encodedCommonName), + encodedCommonName }; + CRYPT_ATTRIBUTE attr = { oid_common_name, 1, &commonName }; BOOL ret; HCRYPTKEY key; DWORD size; @@ -1458,6 +1481,20 @@ static void test_signed_msg_encoding(void) CryptMsgClose(msg); + signer.cAuthAttr = 1; + signer.rgAuthAttr = &attr; + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo, + NULL, NULL); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + + CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + check_param("signed with auth attrs bare content", msg, + CMSG_BARE_CONTENT_PARAM, signedWithAuthAttrsBareContent, + sizeof(signedWithAuthAttrsBareContent)); + + CryptMsgClose(msg); + + signer.cAuthAttr = 0; signInfo.rgCertEncoded = &encodedCert; signInfo.cCertEncoded = 1; msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo,