crypt32(2/2): Implement CryptVerifyMessageSignature
Juan Lang
juan.lang at gmail.com
Wed Aug 22 11:44:21 CDT 2007
--Juan
-------------- next part --------------
From 039d712adac92c57480266650a92f6746cba98d9 Mon Sep 17 00:00:00 2001
From: Juan Lang <juan.lang at gmail.com>
Date: Wed, 22 Aug 2007 09:40:43 -0700
Subject: [PATCH] Implement CryptVerifyMessageSignature
---
dlls/crypt32/main.c | 12 ----
dlls/crypt32/msg.c | 132 +++++++++++++++++++++++++++++++++++++++++++
dlls/crypt32/tests/msg.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 272 insertions(+), 12 deletions(-)
diff --git a/dlls/crypt32/main.c b/dlls/crypt32/main.c
index aec288d..9e53e4b 100644
--- a/dlls/crypt32/main.c
+++ b/dlls/crypt32/main.c
@@ -235,15 +235,3 @@ BOOL WINAPI CryptQueryObject(DWORD dwObj
phCertStore, phMsg, ppvContext);
return FALSE;
}
-
-BOOL WINAPI CryptVerifyMessageSignature(PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara,
- DWORD dwSignerIndex, const BYTE* pbSignedBlob, DWORD cbSignedBlob,
- BYTE* pbDecoded, DWORD* pcbDecoded, PCCERT_CONTEXT* ppSignerCert)
-{
- FIXME("stub: %p, %d, %p, %d, %p, %p, %p\n",
- pVerifyPara, dwSignerIndex, pbSignedBlob, cbSignedBlob,
- pbDecoded, pcbDecoded, ppSignerCert);
- if (ppSignerCert)
- *ppSignerCert = NULL;
- return FALSE;
-}
diff --git a/dlls/crypt32/msg.c b/dlls/crypt32/msg.c
index dea6a11..13f7da4 100644
--- a/dlls/crypt32/msg.c
+++ b/dlls/crypt32/msg.c
@@ -2321,3 +2321,135 @@ LONG WINAPI CryptGetMessageSignerCount(D
}
return count;
}
+
+static CERT_INFO *CRYPT_GetSignerCertInfoFromMsg(HCRYPTMSG msg,
+ DWORD dwSignerIndex)
+{
+ CERT_INFO *certInfo = NULL;
+ DWORD size;
+
+ if (CryptMsgGetParam(msg, CMSG_SIGNER_CERT_INFO_PARAM, dwSignerIndex, NULL,
+ &size))
+ {
+ certInfo = CryptMemAlloc(size);
+ if (certInfo)
+ {
+ if (!CryptMsgGetParam(msg, CMSG_SIGNER_CERT_INFO_PARAM,
+ dwSignerIndex, certInfo, &size))
+ {
+ CryptMemFree(certInfo);
+ certInfo = NULL;
+ }
+ }
+ }
+ return certInfo;
+}
+
+static PCCERT_CONTEXT WINAPI CRYPT_DefaultGetSignerCertificate(void *pvGetArg,
+ DWORD dwCertEncodingType, PCERT_INFO pSignerId, HCERTSTORE hMsgCertStore)
+{
+ return CertFindCertificateInStore(hMsgCertStore, dwCertEncodingType, 0,
+ CERT_FIND_SUBJECT_CERT, pSignerId, NULL);
+}
+
+static inline PCCERT_CONTEXT CRYPT_GetSignerCertificate(HCRYPTMSG msg,
+ PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara, PCERT_INFO certInfo, HCERTSTORE store)
+{
+ PFN_CRYPT_GET_SIGNER_CERTIFICATE getCert;
+
+ if (pVerifyPara->pfnGetSignerCertificate)
+ getCert = pVerifyPara->pfnGetSignerCertificate;
+ else
+ getCert = CRYPT_DefaultGetSignerCertificate;
+ return getCert(pVerifyPara->pvGetArg,
+ pVerifyPara->dwMsgAndCertEncodingType, certInfo, store);
+}
+
+BOOL WINAPI CryptVerifyMessageSignature(PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara,
+ DWORD dwSignerIndex, const BYTE* pbSignedBlob, DWORD cbSignedBlob,
+ BYTE* pbDecoded, DWORD* pcbDecoded, PCCERT_CONTEXT* ppSignerCert)
+{
+ BOOL ret = FALSE;
+ DWORD size;
+ CRYPT_CONTENT_INFO *contentInfo;
+
+ TRACE("(%p, %d, %p, %d, %p, %p, %p)\n",
+ pVerifyPara, dwSignerIndex, pbSignedBlob, cbSignedBlob,
+ pbDecoded, pcbDecoded, ppSignerCert);
+
+ if (ppSignerCert)
+ *ppSignerCert = NULL;
+ if (pcbDecoded)
+ *pcbDecoded = 0;
+ if (!pVerifyPara ||
+ pVerifyPara->cbSize != sizeof(CRYPT_VERIFY_MESSAGE_PARA) ||
+ GET_CMSG_ENCODING_TYPE(pVerifyPara->dwMsgAndCertEncodingType) !=
+ PKCS_7_ASN_ENCODING)
+ {
+ SetLastError(E_INVALIDARG);
+ return FALSE;
+ }
+
+ ret = CryptDecodeObjectEx(pVerifyPara->dwMsgAndCertEncodingType,
+ PKCS_CONTENT_INFO, pbSignedBlob, cbSignedBlob,
+ CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
+ (LPBYTE)&contentInfo, &size);
+ if (ret)
+ {
+ if (strcmp(contentInfo->pszObjId, szOID_RSA_signedData))
+ {
+ SetLastError(CRYPT_E_UNEXPECTED_MSG_TYPE);
+ ret = FALSE;
+ }
+ else
+ {
+ HCRYPTMSG msg = CryptMsgOpenToDecode(
+ pVerifyPara->dwMsgAndCertEncodingType, 0, CMSG_SIGNED,
+ pVerifyPara->hCryptProv, NULL, NULL);
+
+ if (msg)
+ {
+ ret = CryptMsgUpdate(msg, contentInfo->Content.pbData,
+ contentInfo->Content.cbData, TRUE);
+ if (ret && pcbDecoded)
+ ret = CRYPT_CopyParam(pbDecoded, pcbDecoded,
+ contentInfo->Content.pbData, contentInfo->Content.cbData);
+ if (ret)
+ {
+ CERT_INFO *certInfo = CRYPT_GetSignerCertInfoFromMsg(msg,
+ dwSignerIndex);
+
+ ret = FALSE;
+ if (certInfo)
+ {
+ HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MSG,
+ pVerifyPara->dwMsgAndCertEncodingType,
+ pVerifyPara->hCryptProv, 0, msg);
+
+ if (store)
+ {
+ PCCERT_CONTEXT cert = CRYPT_GetSignerCertificate(
+ msg, pVerifyPara, certInfo, store);
+
+ if (cert)
+ {
+ ret = CryptMsgControl(msg, 0,
+ CMSG_CTRL_VERIFY_SIGNATURE, cert->pCertInfo);
+ if (ret && ppSignerCert)
+ *ppSignerCert = cert;
+ else
+ CertFreeCertificateContext(cert);
+ }
+ CertCloseStore(store, 0);
+ }
+ }
+ CryptMemFree(certInfo);
+ }
+ CryptMsgClose(msg);
+ }
+ }
+ LocalFree(contentInfo);
+ }
+ TRACE("returning %d\n", ret);
+ return ret;
+}
diff --git a/dlls/crypt32/tests/msg.c b/dlls/crypt32/tests/msg.c
index 008e60a..68487a5 100644
--- a/dlls/crypt32/tests/msg.c
+++ b/dlls/crypt32/tests/msg.c
@@ -2487,6 +2487,145 @@ static void test_msg_get_signer_count(vo
ok(count == 1, "Expected 1, got %d\n", count);
}
+static const BYTE signedWithCertEmptyContent[] = {
+0x30,0x81,0xdf,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02,0xa0,
+0x81,0xd1,0x30,0x81,0xce,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,
+0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x02,0x06,0x00,0xa0,0x7c,
+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,
+0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,
+0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,
+0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11,0x06,
+0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,
+0x00,0x30,0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00,0xa3,0x16,0x30,0x14,0x30,
+0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01,
+0xff,0x02,0x01,0x01,0x31,0x37,0x30,0x35,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,0x30,0x04,0x06,0x00,0x05,0x00,0x04,
+0x00 };
+static const BYTE signedWithCertContent[] = {
+0x30,0x82,0x01,0x32,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02,
+0xa0,0x82,0x01,0x23,0x30,0x82,0x01,0x1f,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,0xa0,0x7c,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,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,
+0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,
+0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,
+0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,
+0x20,0x4c,0x61,0x6e,0x67,0x00,0x30,0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00,
+0xa3,0x16,0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,
+0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01,0x31,0x77,0x30,0x75,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,0x30,0x04,
+0x06,0x00,0x05,0x00,0x04,0x40,0x81,0xa6,0x70,0xb3,0xef,0x59,0xd1,0x66,0xd1,
+0x9b,0xc0,0x9a,0xb6,0x9a,0x5e,0x6d,0x6f,0x6d,0x0d,0x59,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 signedWithCertWithPubKeyContent[] = {
+0x30,0x81,0xfc,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02,0xa0,
+0x81,0xee,0x30,0x81,0xeb,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,
+0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x02,0x06,0x00,0xa0,0x81,
+0x98,0x30,0x81,0x95,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,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,
+0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,
+0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,
+0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,
+0x6e,0x67,0x00,0x30,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,
+0x01,0x01,0x01,0x05,0x00,0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,
+0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xa3,0x16,0x30,0x14,0x30,0x12,
+0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,
+0x02,0x01,0x01,0x31,0x37,0x30,0x35,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,0x30,0x04,0x06,0x00,0x05,0x00,0x04,0x00 };
+
+static void test_verify_message_signature(void)
+{
+ BOOL ret;
+ CRYPT_VERIFY_MESSAGE_PARA para = { 0 };
+ PCCERT_CONTEXT cert;
+ DWORD cbDecoded;
+
+ SetLastError(0xdeadbeef);
+ ret = CryptVerifyMessageSignature(NULL, 0, NULL, 0, NULL, 0, NULL);
+ ok(!ret && GetLastError() == E_INVALIDARG,
+ "Expected E_INVALIDARG, got %08x\n", GetLastError());
+ SetLastError(0xdeadbeef);
+ ret = CryptVerifyMessageSignature(¶, 0, NULL, 0, NULL, 0, NULL);
+ ok(!ret && GetLastError() == E_INVALIDARG,
+ "Expected E_INVALIDARG, got %08x\n", GetLastError());
+ para.cbSize = sizeof(para);
+ SetLastError(0xdeadbeef);
+ ret = CryptVerifyMessageSignature(¶, 0, NULL, 0, NULL, 0, NULL);
+ ok(!ret && GetLastError() == E_INVALIDARG,
+ "Expected E_INVALIDARG, got %08x\n", GetLastError());
+ para.cbSize = 0;
+ para.dwMsgAndCertEncodingType = PKCS_7_ASN_ENCODING;
+ SetLastError(0xdeadbeef);
+ ret = CryptVerifyMessageSignature(¶, 0, NULL, 0, NULL, 0, NULL);
+ ok(!ret && GetLastError() == E_INVALIDARG,
+ "Expected E_INVALIDARG, got %08x\n", GetLastError());
+ para.cbSize = sizeof(para);
+ SetLastError(0xdeadbeef);
+ ret = CryptVerifyMessageSignature(¶, 0, NULL, 0, NULL, 0, NULL);
+ ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
+ "Expected CRYPT_E_ASN1_EOD, got %08x\n", GetLastError());
+ /* Check whether cert is set on error */
+ cert = (PCCERT_CONTEXT)0xdeadbeef;
+ ret = CryptVerifyMessageSignature(¶, 0, NULL, 0, NULL, 0, &cert);
+ ok(cert == NULL, "Expected NULL cert\n");
+ /* Check whether cbDecoded is set on error */
+ cbDecoded = 0xdeadbeef;
+ ret = CryptVerifyMessageSignature(¶, 0, NULL, 0, NULL, &cbDecoded,
+ NULL);
+ ok(!cbDecoded, "Expected 0\n");
+ SetLastError(0xdeadbeef);
+ ret = CryptVerifyMessageSignature(¶, 0, dataEmptyBareContent,
+ sizeof(dataEmptyBareContent), NULL, 0, NULL);
+ ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
+ "Expected CRYPT_E_ASN1_BADTAG, got %08x\n", GetLastError());
+ SetLastError(0xdeadbeef);
+ ret = CryptVerifyMessageSignature(¶, 0, dataEmptyContent,
+ sizeof(dataEmptyContent), NULL, 0, NULL);
+ ok(!ret && GetLastError() == CRYPT_E_UNEXPECTED_MSG_TYPE,
+ "Expected CRYPT_E_UNEXPECTED_MSG_TYPE, got %08x\n", GetLastError());
+ SetLastError(0xdeadbeef);
+ ret = CryptVerifyMessageSignature(¶, 0, signedEmptyBareContent,
+ sizeof(signedEmptyBareContent), NULL, 0, NULL);
+ ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
+ "Expected CRYPT_E_ASN1_BADTAG, got %08x\n", GetLastError());
+ SetLastError(0xdeadbeef);
+ ret = CryptVerifyMessageSignature(¶, 0, signedEmptyContent,
+ sizeof(signedEmptyContent), NULL, 0, NULL);
+ ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
+ "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError());
+ SetLastError(0xdeadbeef);
+ ret = CryptVerifyMessageSignature(¶, 0, signedContent,
+ sizeof(signedContent), NULL, 0, NULL);
+ ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
+ "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError());
+ /* FIXME: Windows fails with CRYPT_E_NOT_FOUND for these messages, but
+ * their signer certs have invalid public keys that fail to decode. In
+ * Wine therefore the failure is an ASN error. Need some messages with
+ * valid public keys and invalid signatures to check against.
+ */
+ ret = CryptVerifyMessageSignature(¶, 0, signedWithCertEmptyContent,
+ sizeof(signedWithCertEmptyContent), NULL, 0, NULL);
+ ok(!ret, "Expected failure\n");
+ ret = CryptVerifyMessageSignature(¶, 0, signedWithCertContent,
+ sizeof(signedWithCertContent), NULL, 0, NULL);
+ ok(!ret, "Expected failure\n");
+ ret = CryptVerifyMessageSignature(¶, 0, signedWithCertWithPubKeyContent,
+ sizeof(signedWithCertWithPubKeyContent), NULL, 0, NULL);
+ ok(!ret, "Expected failure\n");
+}
+
START_TEST(msg)
{
init_function_pointers();
@@ -2506,4 +2645,5 @@ START_TEST(msg)
/* simplified message functions */
test_msg_get_signer_count();
+ test_verify_message_signature();
}
--
1.4.1
More information about the wine-patches
mailing list