Juan Lang : crypt32: Accept any matching CN when checking a certificate' s name.

Alexandre Julliard julliard at winehq.org
Fri Dec 17 11:30:46 CST 2010


Module: wine
Branch: master
Commit: 667aeb3ede3ddad63b387fad248b66c03690c5a6
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=667aeb3ede3ddad63b387fad248b66c03690c5a6

Author: Juan Lang <juan.lang at gmail.com>
Date:   Thu Dec 16 10:31:47 2010 -0800

crypt32: Accept any matching CN when checking a certificate's name.

---

 dlls/crypt32/chain.c       |   19 ++++++++++---
 dlls/crypt32/tests/chain.c |   63 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 78 insertions(+), 4 deletions(-)

diff --git a/dlls/crypt32/chain.c b/dlls/crypt32/chain.c
index 1fb368b..d7c10b3 100644
--- a/dlls/crypt32/chain.c
+++ b/dlls/crypt32/chain.c
@@ -3343,13 +3343,24 @@ static BOOL match_dns_to_subject_dn(PCCERT_CONTEXT cert, LPCWSTR server_name)
         }
         else
         {
-            PCERT_RDN_ATTR attr;
+            DWORD i, j;
 
             /* If the certificate isn't using a DN attribute in the name, make
-             * make sure the common name matches.
+             * make sure at least one common name matches.  From RFC 2818,
+             * section 3.1:
+             * "If more than one identity of a given type is present in the
+             * certificate (e.g., more than one dNSName name, a match in any
+             * one of the set is considered acceptable.)"
              */
-            if ((attr = CertFindRDNAttr(szOID_COMMON_NAME, name)))
-                matches = match_common_name(server_name, attr);
+            for (i = 0; !matches && i < name->cRDN; i++)
+                for (j = 0; !matches && j < name->rgRDN[i].cRDNAttr; j++)
+                {
+                    PCERT_RDN_ATTR attr = &name->rgRDN[i].rgRDNAttr[j];
+
+                    if (attr->pszObjId && !strcmp(szOID_COMMON_NAME,
+                     attr->pszObjId))
+                        matches = match_common_name(server_name, attr);
+                }
         }
         LocalFree(name);
     }
diff --git a/dlls/crypt32/tests/chain.c b/dlls/crypt32/tests/chain.c
index 11f297c..71be975 100644
--- a/dlls/crypt32/tests/chain.c
+++ b/dlls/crypt32/tests/chain.c
@@ -2568,6 +2568,39 @@ static const BYTE chain30_2[] = {
 0x5e,0xe2,0x2b,0xf5,0xa1,0xee,0x02,0x7e,0x09,0x15,0xff,0xc9,0xf6,0xaf,0xf5,
 0xcc,0xeb,0xfc,0xe7,0x3c,0x92,0xdb,0x31,0xab,0x1e,0xb8,0x9e,0xf0,0x5e,0xa3,
 0x93,0xfe,0xab,0x26,0x7b,0x01,0xa8,0x98,0x88,0xbb,0xee };
+/* chain0_0 -> chain31_1: a chain whose end certificate has two CNs, a
+ * wildcard name "*.foo.com" and a non-wildcard name "foo.com".
+ */
+static const BYTE chain31_1[] = {
+0x30,0x82,0x01,0xa2,0x30,0x82,0x01,0x0d,0xa0,0x03,0x02,0x01,0x02,0x02,0x01,
+0x01,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x30,
+0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,
+0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x35,0x30,0x31,0x30,0x30,0x30,
+0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x30,0x30,0x31,0x30,0x30,0x30,
+0x30,0x30,0x30,0x5a,0x30,0x24,0x31,0x22,0x30,0x0e,0x06,0x03,0x55,0x04,0x03,
+0x13,0x07,0x66,0x6f,0x6f,0x2e,0x63,0x6f,0x6d,0x30,0x10,0x06,0x03,0x55,0x04,
+0x03,0x13,0x09,0x2a,0x2e,0x66,0x6f,0x6f,0x2e,0x63,0x6f,0x6d,0x30,0x81,0x9d,
+0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x03,0x81,
+0x8d,0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xb8,0x52,0xda,0xc5,0x4b,0x3f,
+0xe5,0x33,0x0e,0x67,0x5f,0x48,0x21,0xdc,0x7e,0xef,0x37,0x33,0xba,0xff,0xb4,
+0xc6,0xdc,0xb6,0x17,0x8e,0x20,0x55,0x07,0x12,0xd2,0x7b,0x3c,0xce,0x30,0xc5,
+0xa7,0x48,0x9f,0x6e,0xfe,0xb8,0xbe,0xdb,0x9f,0x9b,0x17,0x60,0x16,0xde,0xc6,
+0x8b,0x47,0xd1,0x57,0x71,0x3c,0x93,0xfc,0xbd,0xec,0x44,0x32,0x3b,0xb9,0xcf,
+0x6b,0x05,0x72,0xa7,0x87,0x8e,0x7e,0xd4,0x9a,0x87,0x1c,0x2f,0xb7,0x82,0x40,
+0xfc,0x6a,0x80,0x83,0x68,0x28,0xce,0x84,0xf4,0x0b,0x2e,0x44,0xcb,0x53,0xac,
+0x85,0x85,0xb5,0x46,0x36,0x98,0x3c,0x10,0x02,0xaa,0x02,0xbc,0x8b,0xa2,0x23,
+0xb2,0xd3,0x51,0x9a,0x22,0x4a,0xe3,0xaa,0x4e,0x7c,0xda,0x38,0xcf,0x49,0x98,
+0x72,0xa3,0x02,0x03,0x01,0x00,0x01,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,
+0xf7,0x0d,0x01,0x01,0x05,0x03,0x81,0x81,0x00,0xa0,0x93,0x52,0x87,0x81,0xe2,
+0xff,0x2a,0xc7,0xef,0x5f,0x3c,0xbc,0x88,0x99,0xc0,0x47,0x3e,0x13,0xe9,0x87,
+0xfa,0x36,0xd7,0xb5,0xe8,0xdf,0x70,0xcc,0x36,0xe4,0x70,0x3c,0xcd,0xa2,0x0b,
+0x31,0x6e,0x0a,0xb9,0x00,0xf0,0x4f,0xb6,0xc2,0xce,0xf4,0x33,0x1e,0xc0,0x29,
+0xc0,0x73,0x0c,0xcf,0x28,0xa5,0x26,0x9d,0xc2,0xaf,0x85,0x30,0x81,0xbf,0xd1,
+0x70,0x3f,0x69,0x15,0xc5,0x41,0x1d,0x8e,0xd4,0xfa,0x02,0xcd,0xba,0xf1,0xf2,
+0x67,0xb5,0x45,0x29,0xad,0xe8,0x54,0x9a,0x0f,0x1a,0x8f,0xdf,0x16,0xf4,0xcb,
+0x43,0x08,0xe5,0x78,0x2b,0x95,0xf3,0x75,0xb6,0x88,0xf0,0x6b,0x5c,0x5b,0x50,
+0x04,0x91,0x3b,0x89,0x5a,0x60,0x1f,0xfc,0x36,0x53,0x32,0x36,0x0a,0x4d,0x03,
+0x2c,0xd7 };
 
 typedef struct _CONST_DATA_BLOB
 {
@@ -3195,6 +3228,10 @@ static const CERT_TRUST_STATUS elementStatus30[] = {
 static const SimpleChainStatusCheck simpleStatus30[] = {
  { sizeof(elementStatus30) / sizeof(elementStatus30[0]), elementStatus30 },
 };
+static CONST_DATA_BLOB chain31[] = {
+ { sizeof(chain0_0), chain0_0 },
+ { sizeof(chain31_1), chain31_1 },
+};
 static CONST_DATA_BLOB selfSignedChain[] = {
  { sizeof(selfSignedCert), selfSignedCert }
 };
@@ -4027,6 +4064,16 @@ static const ChainPolicyCheck invalidExtensionPolicyCheck = {
  { 0, CERT_E_CRITICAL, 0, 1, NULL}, &badDateNestingStatus, 0
 };
 
+static const ChainPolicyCheck fooPolicyCheckWithMatchingName = {
+ { sizeof(chain31) / sizeof(chain31[0]), chain31 },
+ { 0, 0, -1, -1, NULL}, NULL, 0
+};
+
+static const ChainPolicyCheck fooPolicyCheckWithoutMatchingName = {
+ { sizeof(chain31) / sizeof(chain31[0]), chain31 },
+ { 0, CERT_E_CN_NO_MATCH, 0, 0, NULL}, NULL, 0
+};
+
 static const ChainPolicyCheck authenticodePolicyCheck[] = {
  { { sizeof(chain0) / sizeof(chain0[0]), chain0 },
    { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 },
@@ -4324,6 +4371,9 @@ static void check_ssl_policy(void)
      'w','i','n','e','h','q','.','o','r','g',0 };
     WCHAR a_dot_b_dot_winehq_dot_org[] = { 'a','.','b','.',
      'w','i','n','e','h','q','.','o','r','g',0 };
+    WCHAR foo_dot_com[] = { 'f','o','o','.','c','o','m',0 };
+    WCHAR afoo_dot_com[] = { 'a','f','o','o','.','c','o','m',0 };
+    WCHAR a_dot_foo_dot_com[] = { 'a','.','f','o','o','.','c','o','m',0 };
     HCERTSTORE testRoot;
     CERT_CHAIN_ENGINE_CONFIG engineConfig = { sizeof(engineConfig), 0 };
     HCERTCHAINENGINE engine;
@@ -4473,6 +4523,19 @@ static void check_ssl_policy(void)
     sslPolicyPara.pwszServerName = NULL;
     CHECK_CHAIN_POLICY_STATUS(CERT_CHAIN_POLICY_SSL, NULL,
      invalidExtensionPolicyCheck, &oct2007, &policyPara);
+    /* Test chain31, which has two CNs, "*.foo.com" and "foo.com", against
+     * some names that match one of the CNs:
+     */
+    sslPolicyPara.pwszServerName = foo_dot_com;
+    CHECK_CHAIN_POLICY_STATUS(CERT_CHAIN_POLICY_SSL, NULL,
+     fooPolicyCheckWithMatchingName, &oct2007, &policyPara);
+    sslPolicyPara.pwszServerName = a_dot_foo_dot_com;
+    CHECK_CHAIN_POLICY_STATUS(CERT_CHAIN_POLICY_SSL, NULL,
+     fooPolicyCheckWithMatchingName, &oct2007, &policyPara);
+    /* and against a name that doesn't match either CN: */
+    sslPolicyPara.pwszServerName = afoo_dot_com;
+    CHECK_CHAIN_POLICY_STATUS(CERT_CHAIN_POLICY_SSL, NULL,
+     fooPolicyCheckWithoutMatchingName, &oct2007, &policyPara);
 }
 
 static void testVerifyCertChainPolicy(void)




More information about the wine-cvs mailing list