crypt32(8/8): Implement CryptVerifyMessageSignature

Juan Lang juan.lang at gmail.com
Tue Aug 21 17:21:48 CDT 2007


--Juan
-------------- next part --------------
From 96df26da150835d9c2bb5aaacdbb7f9d25643090 Mon Sep 17 00:00:00 2001
From: Juan Lang <juan.lang at gmail.com>
Date: Tue, 21 Aug 2007 15:16:34 -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(&para, 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(&para, 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(&para, 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(&para, 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(&para, 0, NULL, 0, NULL, 0, &cert);
+    ok(cert == NULL, "Expected NULL cert\n");
+    /* Check whether cbDecoded is set on error */
+    cbDecoded = 0xdeadbeef;
+    ret = CryptVerifyMessageSignature(&para, 0, NULL, 0, NULL, &cbDecoded,
+     NULL);
+    ok(!cbDecoded, "Expected 0\n");
+    SetLastError(0xdeadbeef);
+    ret = CryptVerifyMessageSignature(&para, 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(&para, 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(&para, 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(&para, 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(&para, 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(&para, 0, signedWithCertEmptyContent,
+     sizeof(signedWithCertEmptyContent), NULL, 0, NULL);
+    ok(!ret, "Expected failure\n");
+    ret = CryptVerifyMessageSignature(&para, 0, signedWithCertContent,
+     sizeof(signedWithCertContent), NULL, 0, NULL);
+    ok(!ret, "Expected failure\n");
+    ret = CryptVerifyMessageSignature(&para, 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