From b7e420429db8e3a2eab503f49ce0b04a4ac7f551 Mon Sep 17 00:00:00 2001 From: Juan Lang Date: Tue, 21 Aug 2007 07:34:47 -0700 Subject: [PATCH] crypt32: Implement verifying a decoded signed message's signature. --- dlls/crypt32/msg.c | 43 +++++++++++++++++++++++++++++++++++++++- dlls/crypt32/tests/msg.c | 9 ++++----- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/dlls/crypt32/msg.c b/dlls/crypt32/msg.c index ace5e51bd74..c9226addb73 100644 --- a/dlls/crypt32/msg.c +++ b/dlls/crypt32/msg.c @@ -2084,6 +2084,47 @@ static BOOL CDecodeHashMsg_VerifyHash(CDecodeMsg *msg) return ret; } +static BOOL CDecodeSignedMsg_VerifySignature(CDecodeMsg *msg, PCERT_INFO info) +{ + BOOL ret = FALSE; + DWORD i; + + for (i = 0; !ret && i < msg->u.signed_data.info->cSignerInfo; i++) + { + ret = CertCompareCertificateName(X509_ASN_ENCODING, + &msg->u.signed_data.info->rgSignerInfo[i].Issuer, &info->Issuer); + if (ret) + ret = CertCompareIntegerBlob( + &msg->u.signed_data.info->rgSignerInfo[i].SerialNumber, + &info->SerialNumber); + } + if (ret) + { + HCRYPTKEY key; + + ret = CryptImportPublicKeyInfo(msg->crypt_prov, X509_ASN_ENCODING, + &info->SubjectPublicKeyInfo, &key); + if (ret) + { + HCRYPTHASH hash; + + if (msg->u.signed_data.info->rgSignerInfo[i].AuthAttrs.cAttr) + hash = msg->u.signed_data.signerHandles[i].authAttrHash; + else + hash = msg->u.signed_data.signerHandles[i].contentHash; + ret = CryptVerifySignatureW(hash, + msg->u.signed_data.info->rgSignerInfo[i].EncryptedHash.pbData, + msg->u.signed_data.info->rgSignerInfo[i].EncryptedHash.cbData, + key, NULL, 0); + CryptDestroyKey(key); + } + } + else + SetLastError(CRYPT_E_SIGNER_NOT_FOUND); + + return ret; +} + static BOOL CDecodeMsg_Control(HCRYPTMSG hCryptMsg, DWORD dwFlags, DWORD dwCtrlType, const void *pvCtrlPara) { @@ -2096,7 +2137,7 @@ static BOOL CDecodeMsg_Control(HCRYPTMSG hCryptMsg, DWORD dwFlags, switch (msg->type) { case CMSG_SIGNED: - FIXME("CMSG_CTRL_VERIFY_SIGNATURE: stub\n"); + ret = CDecodeSignedMsg_VerifySignature(msg, (PCERT_INFO)pvCtrlPara); break; default: SetLastError(CRYPT_E_INVALID_MSG_TYPE); diff --git a/dlls/crypt32/tests/msg.c b/dlls/crypt32/tests/msg.c index f079916e088..b1e6c94eee6 100644 --- a/dlls/crypt32/tests/msg.c +++ b/dlls/crypt32/tests/msg.c @@ -2291,7 +2291,6 @@ static void test_msg_control(void) */ SetLastError(0xdeadbeef); ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_SIGNATURE, &certInfo); - todo_wine ok(!ret && GetLastError() == CRYPT_E_SIGNER_NOT_FOUND, "Expected CRYPT_E_SIGNER_NOT_FOUND, got %08x\n", GetLastError()); /* The cert info is expected to have an issuer, serial number, and public @@ -2303,7 +2302,6 @@ static void test_msg_control(void) certInfo.Issuer.pbData = encodedCommonName; SetLastError(0xdeadbeef); ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_SIGNATURE, &certInfo); - todo_wine ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD, "Expected CRYPT_E_ASN1_EOD, got %08x\n", GetLastError()); CryptMsgClose(msg); @@ -2315,7 +2313,6 @@ static void test_msg_control(void) /* Again, cert info needs to have a public key set */ SetLastError(0xdeadbeef); ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_SIGNATURE, &certInfo); - todo_wine ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD, "Expected CRYPT_E_ASN1_EOD, got %08x\n", GetLastError()); /* The public key is supposed to be in encoded form.. */ @@ -2324,7 +2321,6 @@ static void test_msg_control(void) certInfo.SubjectPublicKeyInfo.PublicKey.pbData = aKey; SetLastError(0xdeadbeef); ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_SIGNATURE, &certInfo); - todo_wine ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG, "Expected CRYPT_E_ASN1_BADTAG, got %08x\n", GetLastError()); /* but not as a X509_PUBLIC_KEY_INFO.. */ @@ -2333,7 +2329,6 @@ static void test_msg_control(void) certInfo.SubjectPublicKeyInfo.PublicKey.pbData = encodedPubKey; SetLastError(0xdeadbeef); ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_SIGNATURE, &certInfo); - todo_wine ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG, "Expected CRYPT_E_ASN1_BADTAG, got %08x\n", GetLastError()); /* This decodes successfully, but it doesn't match any key in the message */ @@ -2341,6 +2336,10 @@ static void test_msg_control(void) certInfo.SubjectPublicKeyInfo.PublicKey.pbData = mod_encoded; SetLastError(0xdeadbeef); ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_SIGNATURE, &certInfo); + /* In Wine's rsaenh, this fails to decode because the key length is too + * small. Not sure if that's a bug in rsaenh, so leaving todo_wine for + * now. + */ todo_wine ok(!ret && GetLastError() == NTE_BAD_SIGNATURE, "Expected NTE_BAD_SIGNATURE, got %08x\n", GetLastError());