Blame SOURCES/0101-CVE-2022-4203-nc-match.patch

1ac26c
From c927a3492698c254637da836762f9b1f86cffabc Mon Sep 17 00:00:00 2001
1ac26c
From: Viktor Dukhovni <openssl-users@dukhovni.org>
1ac26c
Date: Tue, 13 Dec 2022 08:49:13 +0100
1ac26c
Subject: [PATCH 01/18] Fix type confusion in nc_match_single()
1ac26c
1ac26c
This function assumes that if the "gen" is an OtherName, then the "base"
1ac26c
is a rfc822Name constraint. This assumption is not true in all cases.
1ac26c
If the end-entity certificate contains an OtherName SAN of any type besides
1ac26c
SmtpUtf8Mailbox and the CA certificate contains a name constraint of
1ac26c
OtherName (of any type), then "nc_email_eai" will be invoked, with the
1ac26c
OTHERNAME "base" being incorrectly interpreted as a ASN1_IA5STRING.
1ac26c
1ac26c
Reported by Corey Bonnell from Digicert.
1ac26c
1ac26c
CVE-2022-4203
1ac26c
1ac26c
Reviewed-by: Paul Dale <pauli@openssl.org>
1ac26c
Reviewed-by: Hugo Landau <hlandau@openssl.org>
1ac26c
Reviewed-by: Tomas Mraz <tomas@openssl.org>
1ac26c
---
1ac26c
 crypto/x509/v3_ncons.c | 45 +++++++++++++++++++++++++++++-------------
1ac26c
 1 file changed, 31 insertions(+), 14 deletions(-)
1ac26c
1ac26c
diff --git a/crypto/x509/v3_ncons.c b/crypto/x509/v3_ncons.c
1ac26c
index 70a7e8304e..5101598512 100644
1ac26c
--- a/crypto/x509/v3_ncons.c
1ac26c
+++ b/crypto/x509/v3_ncons.c
1ac26c
@@ -31,7 +31,8 @@ static int do_i2r_name_constraints(const X509V3_EXT_METHOD *method,
1ac26c
 static int print_nc_ipadd(BIO *bp, ASN1_OCTET_STRING *ip);
1ac26c
 
1ac26c
 static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc);
1ac26c
-static int nc_match_single(GENERAL_NAME *sub, GENERAL_NAME *gen);
1ac26c
+static int nc_match_single(int effective_type, GENERAL_NAME *sub,
1ac26c
+                           GENERAL_NAME *gen);
1ac26c
 static int nc_dn(const X509_NAME *sub, const X509_NAME *nm);
1ac26c
 static int nc_dns(ASN1_IA5STRING *sub, ASN1_IA5STRING *dns);
1ac26c
 static int nc_email(ASN1_IA5STRING *sub, ASN1_IA5STRING *eml);
1ac26c
@@ -472,14 +473,17 @@ static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc)
1ac26c
 {
1ac26c
     GENERAL_SUBTREE *sub;
1ac26c
     int i, r, match = 0;
1ac26c
+    int effective_type = gen->type;
1ac26c
+
1ac26c
     /*
1ac26c
      * We need to compare not gen->type field but an "effective" type because
1ac26c
      * the otherName field may contain EAI email address treated specially
1ac26c
      * according to RFC 8398, section 6
1ac26c
      */
1ac26c
-    int effective_type = ((gen->type == GEN_OTHERNAME) &&
1ac26c
-                          (OBJ_obj2nid(gen->d.otherName->type_id) ==
1ac26c
-                           NID_id_on_SmtpUTF8Mailbox)) ? GEN_EMAIL : gen->type;
1ac26c
+    if (effective_type == GEN_OTHERNAME &&
1ac26c
+        (OBJ_obj2nid(gen->d.otherName->type_id) == NID_id_on_SmtpUTF8Mailbox)) {
1ac26c
+        effective_type = GEN_EMAIL;
1ac26c
+    }
1ac26c
 
1ac26c
     /*
1ac26c
      * Permitted subtrees: if any subtrees exist of matching the type at
1ac26c
@@ -488,7 +492,10 @@ static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc)
1ac26c
 
1ac26c
     for (i = 0; i < sk_GENERAL_SUBTREE_num(nc->permittedSubtrees); i++) {
1ac26c
         sub = sk_GENERAL_SUBTREE_value(nc->permittedSubtrees, i);
1ac26c
-        if (effective_type != sub->base->type)
1ac26c
+        if (effective_type != sub->base->type
1ac26c
+            || (effective_type == GEN_OTHERNAME &&
1ac26c
+                OBJ_cmp(gen->d.otherName->type_id,
1ac26c
+                        sub->base->d.otherName->type_id) != 0))
1ac26c
             continue;
1ac26c
         if (!nc_minmax_valid(sub))
1ac26c
             return X509_V_ERR_SUBTREE_MINMAX;
1ac26c
@@ -497,7 +504,7 @@ static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc)
1ac26c
             continue;
1ac26c
         if (match == 0)
1ac26c
             match = 1;
1ac26c
-        r = nc_match_single(gen, sub->base);
1ac26c
+        r = nc_match_single(effective_type, gen, sub->base);
1ac26c
         if (r == X509_V_OK)
1ac26c
             match = 2;
1ac26c
         else if (r != X509_V_ERR_PERMITTED_VIOLATION)
1ac26c
@@ -511,12 +518,15 @@ static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc)
1ac26c
 
1ac26c
     for (i = 0; i < sk_GENERAL_SUBTREE_num(nc->excludedSubtrees); i++) {
1ac26c
         sub = sk_GENERAL_SUBTREE_value(nc->excludedSubtrees, i);
1ac26c
-        if (effective_type != sub->base->type)
1ac26c
+        if (effective_type != sub->base->type
1ac26c
+            || (effective_type == GEN_OTHERNAME &&
1ac26c
+                OBJ_cmp(gen->d.otherName->type_id,
1ac26c
+                        sub->base->d.otherName->type_id) != 0))
1ac26c
             continue;
1ac26c
         if (!nc_minmax_valid(sub))
1ac26c
             return X509_V_ERR_SUBTREE_MINMAX;
1ac26c
 
1ac26c
-        r = nc_match_single(gen, sub->base);
1ac26c
+        r = nc_match_single(effective_type, gen, sub->base);
1ac26c
         if (r == X509_V_OK)
1ac26c
             return X509_V_ERR_EXCLUDED_VIOLATION;
1ac26c
         else if (r != X509_V_ERR_PERMITTED_VIOLATION)
1ac26c
@@ -528,15 +538,22 @@ static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc)
1ac26c
 
1ac26c
 }
1ac26c
 
1ac26c
-static int nc_match_single(GENERAL_NAME *gen, GENERAL_NAME *base)
1ac26c
+static int nc_match_single(int effective_type, GENERAL_NAME *gen,
1ac26c
+                           GENERAL_NAME *base)
1ac26c
 {
1ac26c
     switch (gen->type) {
1ac26c
     case GEN_OTHERNAME:
1ac26c
-        /*
1ac26c
-         * We are here only when we have SmtpUTF8 name,
1ac26c
-         * so we match the value of othername with base->d.rfc822Name
1ac26c
-         */
1ac26c
-        return nc_email_eai(gen->d.otherName->value, base->d.rfc822Name);
1ac26c
+        switch (effective_type) {
1ac26c
+        case GEN_EMAIL:
1ac26c
+            /*
1ac26c
+             * We are here only when we have SmtpUTF8 name,
1ac26c
+             * so we match the value of othername with base->d.rfc822Name
1ac26c
+             */
1ac26c
+            return nc_email_eai(gen->d.otherName->value, base->d.rfc822Name);
1ac26c
+
1ac26c
+        default:
1ac26c
+            return X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE;
1ac26c
+        }
1ac26c
 
1ac26c
     case GEN_DIRNAME:
1ac26c
         return nc_dn(gen->d.directoryName, base->d.directoryName);
1ac26c
-- 
1ac26c
2.39.1
1ac26c
1ac26c
From fe6842f5a5dc2fb66da7fb24bf4343a3aeedd50a Mon Sep 17 00:00:00 2001
1ac26c
From: Tomas Mraz <tomas@openssl.org>
1ac26c
Date: Tue, 13 Dec 2022 19:45:09 +0100
1ac26c
Subject: [PATCH 02/18] Add testcase for nc_match_single type confusion
1ac26c
1ac26c
Reviewed-by: Paul Dale <pauli@openssl.org>
1ac26c
Reviewed-by: Hugo Landau <hlandau@openssl.org>
1ac26c
---
1ac26c
 test/certs/bad-othername-cert.pem | 20 ++++++++++++++++++++
1ac26c
 test/certs/nccaothername-cert.pem | 20 ++++++++++++++++++++
1ac26c
 test/certs/nccaothername-key.pem  | 28 ++++++++++++++++++++++++++++
1ac26c
 test/certs/setup.sh               | 11 +++++++++++
1ac26c
 test/recipes/25-test_verify.t     |  5 ++++-
1ac26c
 5 files changed, 83 insertions(+), 1 deletion(-)
1ac26c
 create mode 100644 test/certs/bad-othername-cert.pem
1ac26c
 create mode 100644 test/certs/nccaothername-cert.pem
1ac26c
 create mode 100644 test/certs/nccaothername-key.pem
1ac26c
1ac26c
diff --git a/test/certs/bad-othername-cert.pem b/test/certs/bad-othername-cert.pem
1ac26c
new file mode 100644
1ac26c
index 0000000000..cf279de5ea
1ac26c
--- /dev/null
1ac26c
+++ b/test/certs/bad-othername-cert.pem
1ac26c
@@ -0,0 +1,20 @@
1ac26c
+-----BEGIN CERTIFICATE-----
1ac26c
+MIIDRDCCAiygAwIBAgIBAjANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDDBRUZXN0
1ac26c
+IE5DIENBIG90aGVybmFtZTAgFw0yMjEyMTMxODMzMTZaGA8yMTIyMTIxNDE4MzMx
1ac26c
+NlowMTEvMC0GA1UECgwmTkMgZW1haWwgaW4gb3RoZXJuYW1lIFRlc3QgQ2VydGlm
1ac26c
+aWNhdGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPgeoakqHk1zYt
1ac26c
+JZpEC0qkJPU/X0lfI+6GY2LHFY9KOSFqqmTXxrUtjQc3SdpQvBZhPuMZ8p82Jid2
1ac26c
+kkRHnWs0uqX9NtLO923yQalYvP6Mt3fokcYgw/C9b+I/q1PKUyN0kPB6McROguD5
1ac26c
+Jz2DcEufJBhbpyay1bFjEI2DAQJKDP/U7uH0EA7kH/27UMk0vfvL5uVjDvlo8i6S
1ac26c
+Ul8+u0cDV5ZFJW2VAJKLU3wp6IY4fZl9UqkHZuRQpMJGqAjAleWOIEpyyvfGGh0b
1ac26c
+75n3GJ+4YZ7CIBEgY7K0nIbKxtcDZPvmtbYg3g1tkPMTHcodFT7yEdqkBTJ5AGL7
1ac26c
+6U850OhjAgMBAAGjdzB1MB0GA1UdDgQWBBTBz0k+q6d4c3aM+s2IyOF/QP6zCTAf
1ac26c
+BgNVHSMEGDAWgBTwhghX7uNdMejZ3f4XorqOQoMqwTAJBgNVHRMEAjAAMCgGA1Ud
1ac26c
+EQQhMB+gHQYIKwYBBQUHCAegEQwPZm9vQGV4YW1wbGUub3JnMA0GCSqGSIb3DQEB
1ac26c
+CwUAA4IBAQAhxbCEVH8pq0aUMaLWaodyXdCqA0AKTFG6Mz9Rpwn89OwC8FylTEru
1ac26c
+t+Bqx/ZuTo8YzON8h9m7DIrQIjZKDLW/g5YbvIsxIVV9gWhAGohdsIyMKRBepSmr
1ac26c
+NxJQkO74RLBTamfl0WUCVM4HqroflFjBBG67CTJaQ9cH9ug3TKxaXCK1L6iQAXtq
1ac26c
+enILGai98Byo0LCFH4MQOhmhV1BDT2boIG/iYb5VKCTSX25vhaF+PNBhUoysjW0O
1ac26c
+vhQX8vrw42QRr4Qi7VfUBXzrbRTzxjOc4yqki7h2DcEdpginqe+aGyaFY+H9m/ka
1ac26c
+1AR5KN8h5SYKltSXknjs0pp1w4k49aHl
1ac26c
+-----END CERTIFICATE-----
1ac26c
diff --git a/test/certs/nccaothername-cert.pem b/test/certs/nccaothername-cert.pem
1ac26c
new file mode 100644
1ac26c
index 0000000000..f9b9b07b80
1ac26c
--- /dev/null
1ac26c
+++ b/test/certs/nccaothername-cert.pem
1ac26c
@@ -0,0 +1,20 @@
1ac26c
+-----BEGIN CERTIFICATE-----
1ac26c
+MIIDPjCCAiagAwIBAgIBAjANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdSb290
1ac26c
+IENBMCAXDTIyMTIxMzE4MTgwM1oYDzIxMjIxMjE0MTgxODAzWjAfMR0wGwYDVQQD
1ac26c
+DBRUZXN0IE5DIENBIG90aGVybmFtZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
1ac26c
+AQoCggEBAN0Dx+ei8CgtRKnDcYiLwX4vrA48at/o/zfX24X/WZZM1o9HUKo1FQBN
1ac26c
+vhESJu+gqPxuIePrk+/L25XdRqwCKk8wkWX0XIz18q5orOHUUFAWNK3g0FDj6N8H
1ac26c
+d8urNIbDJ44FCx+/0n8Ppiht/EYN3aVOW5enqbgZ+EEt+3AUG6ibieRdGri9g4oh
1ac26c
+IIx60MmVHLbuT/TcVZxaeWyTl6iWmsYosUyqlhTtu1uGtbVtkCAhBYloVvz4J5eA
1ac26c
+mVu/JuJbsNxbxVeO9Q8Kj6nb4jPPdGvZ3JPcabbWrz5LwaereBf5IPrXEVdQTlYB
1ac26c
+gI0pTz2CEDHSIrd7jzRUX/9EC2gMk6UCAwEAAaOBjzCBjDAPBgNVHRMBAf8EBTAD
1ac26c
+AQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU8IYIV+7jXTHo2d3+F6K6jkKDKsEw
1ac26c
+HwYDVR0jBBgwFoAUjvUlrx6ba4Q9fICayVOcTXL3o1IwLAYDVR0eBCUwI6EhMB+g
1ac26c
+HQYIKwYBBQUHCAegEQwPZm9vQGV4YW1wbGUub3JnMA0GCSqGSIb3DQEBCwUAA4IB
1ac26c
+AQDPI5uZd8DhSNKMvYF5bxOshd6h6UJ7YzZS7K6fhiygltdqzkHQ/5+4yiuUkDe4
1ac26c
+hOZlH8MCfXQy5jVZDTk24yNchpdfie5Bswn4SmQVQh3QyzOLxizoh0rLCf2PHueu
1ac26c
+dNVNhfiiJNJ5kd8MIuVG7CPK68dP0QrVR+DihROuJgvGB3ClKttLrgle19t4PFRR
1ac26c
+2wW6hJT9aXEjzLNyN1QFZKoShuiGX4xwjZh7VyKkV64p8hjojhcLk6dQkel+Jw4y
1ac26c
+OP26XbVfM8/6KG8f6WAZ8P0qJwHlhmi0EvRTnEpAM8WuenOeZH6ERZ9uZbRGh6xx
1ac26c
+LKQu2Aw2+bOEZ2vUtz0dBhX8
1ac26c
+-----END CERTIFICATE-----
1ac26c
diff --git a/test/certs/nccaothername-key.pem b/test/certs/nccaothername-key.pem
1ac26c
new file mode 100644
1ac26c
index 0000000000..d3e300ac2f
1ac26c
--- /dev/null
1ac26c
+++ b/test/certs/nccaothername-key.pem
1ac26c
@@ -0,0 +1,28 @@
1ac26c
+-----BEGIN PRIVATE KEY-----
1ac26c
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDdA8fnovAoLUSp
1ac26c
+w3GIi8F+L6wOPGrf6P8319uF/1mWTNaPR1CqNRUATb4REibvoKj8biHj65Pvy9uV
1ac26c
+3UasAipPMJFl9FyM9fKuaKzh1FBQFjSt4NBQ4+jfB3fLqzSGwyeOBQsfv9J/D6Yo
1ac26c
+bfxGDd2lTluXp6m4GfhBLftwFBuom4nkXRq4vYOKISCMetDJlRy27k/03FWcWnls
1ac26c
+k5eolprGKLFMqpYU7btbhrW1bZAgIQWJaFb8+CeXgJlbvybiW7DcW8VXjvUPCo+p
1ac26c
+2+Izz3Rr2dyT3Gm21q8+S8Gnq3gX+SD61xFXUE5WAYCNKU89ghAx0iK3e480VF//
1ac26c
+RAtoDJOlAgMBAAECggEAMFSJlCyEFlER3Qq9asXe9eRgXEuXdmfZ2aEVIuf8M/sR
1ac26c
+B0tpxxKtCUA24j5FL+0CzxKZTCFBnDRIzCyTbf1aOa9t+CzXyUZmP3/p4EdgmabF
1ac26c
+dcl93FZ+X7kfF/VUGu0Vmv+c12BH3Fu0cs5cVohlMecg7diu6zCYok43F+L5ymRy
1ac26c
+2mTcKkGc0ShWizj8Z9R3WJGssZOlxbxa/Zr4rZwRC24UVhfN8AfGWYx/StyQPQIw
1ac26c
+gtbbtOmwbyredQmY4jwNqgrnfZS9bkWwJbRuCmD5l7lxubBgcHQpoM+DQVeOLZIq
1ac26c
+uksFXeNfal9G5Bo747MMzpD7dJMCGmX+gbMY5oZF+QKBgQDs2MbY4nbxi+fV+KuV
1ac26c
+zUvis8m8Lpzf3T6NLkgSkUPRN9tGr95iLIrB/bRPJg5Ne02q/cT7d86B9rpE42w7
1ac26c
+eeIF9fANezX2AF8LUqNZhIR23J3tfB/eqGlJRZeMNia+lD09a7SWGwrS7sufY1I+
1ac26c
+JQGcHx77ntt+eQT1MUJ1skF06QKBgQDu4z+TW4QIA5ItxIReVdcfh5e3xLkzDEVP
1ac26c
+3KNo9tpXxvPwqapdeBh6c9z4Lqe3MKr5UPlDvVW+o40t6OjKxDCXczB8+JAM0OyX
1ac26c
+8V+K3zXXUxRgieSd3oMncTylSWIvouPP3aW37B67TKdRlRHgaBrpJT2wdk3kYR4t
1ac26c
+62J1eDdjXQKBgQDMsY0pZI/nskJrar7geM1c4IU5Xg+2aj/lRFqFsYYrC1s3fEd2
1ac26c
+EYjan6l1vi4eSLKXVTspGiIfsFzLrMGdpXjyLduJyzKXqTp7TrBebWkOUR0sYloo
1ac26c
+1OQprzuKskJJ81P6AVvRXw27vyW8Wtp5WwJJK5xbWq/YXj8qqagGkEiCAQKBgQCc
1ac26c
+RK3XAFurPmLGa7JHX5Hc/z8BKMAZo6JHrsZ6qFiGaRA0U1it0hz5JYfcFfECheSi
1ac26c
+ORUF+fn4PlbhPGXkFljPCbwjVBovOBA9CNl+J6u50pAW4r1ZhDB5gbqxSQLgtIaf
1ac26c
++JcqbFxiG6+sT36lNJS+BO2I3KrxhZJPaZY7z8szxQKBgQDRy70XzwOk8jXayiF2
1ac26c
+ej2IN7Ow9cgSE4tLEwR/vCjxvOlWhA3jC3wxoggshGJkpbP3DqLkQtwQm0h1lM8J
1ac26c
+QNtFwKzjtpf//bTlfFq08/YxWimTPMqzcV2PgRacB8P3yf1r8T7M4fA5TORCDWpW
1ac26c
+5FtOCFEmwQHTR8lu4c63qfxkEQ==
1ac26c
+-----END PRIVATE KEY-----
1ac26c
diff --git a/test/certs/setup.sh b/test/certs/setup.sh
1ac26c
index b9766aab20..2240cd9df0 100755
1ac26c
--- a/test/certs/setup.sh
1ac26c
+++ b/test/certs/setup.sh
1ac26c
@@ -388,6 +388,17 @@ REQMASK=MASK:0x800 ./mkcert.sh req badalt7-key "O = Bad NC Test Certificate 7" \
1ac26c
     "email.1 = good@good.org" "email.2 = any@good.com" \
1ac26c
     "IP = 127.0.0.1" "IP = 192.168.0.1"
1ac26c
 
1ac26c
+# Certs for CVE-2022-4203 testcase
1ac26c
+
1ac26c
+NC="excluded;otherName:SRVName;UTF8STRING:foo@example.org" ./mkcert.sh genca \
1ac26c
+    "Test NC CA othername" nccaothername-key nccaothername-cert \
1ac26c
+    root-key root-cert
1ac26c
+
1ac26c
+./mkcert.sh req alt-email-key "O = NC email in othername Test Certificate" | \
1ac26c
+    ./mkcert.sh geneealt bad-othername-key bad-othername-cert \
1ac26c
+    nccaothername-key nccaothername-cert \
1ac26c
+    "otherName.1 = SRVName;UTF8STRING:foo@example.org"
1ac26c
+
1ac26c
 # RSA-PSS signatures
1ac26c
 # SHA1
1ac26c
 ./mkcert.sh genee PSS-SHA1 ee-key ee-pss-sha1-cert ca-key ca-cert \
1ac26c
diff --git a/test/recipes/25-test_verify.t b/test/recipes/25-test_verify.t
1ac26c
index 4613489f57..e6a2bca731 100644
1ac26c
--- a/test/recipes/25-test_verify.t
1ac26c
+++ b/test/recipes/25-test_verify.t
1ac26c
@@ -29,7 +29,7 @@ sub verify {
1ac26c
     run(app([@args]));
1ac26c
 }
1ac26c
 
1ac26c
-plan tests => 162;
1ac26c
+plan tests => 163;
1ac26c
 
1ac26c
 # Canonical success
1ac26c
 ok(verify("ee-cert", "sslserver", ["root-cert"], ["ca-cert"]),
1ac26c
@@ -402,6 +402,9 @@ ok(!verify("badalt9-cert", "", ["root-cert"], ["ncca1-cert", "ncca3-cert"], ),
1ac26c
 ok(!verify("badalt10-cert", "", ["root-cert"], ["ncca1-cert", "ncca3-cert"], ),
1ac26c
    "Name constraints nested DNS name excluded");
1ac26c
 
1ac26c
+ok(!verify("bad-othername-cert", "", ["root-cert"], ["nccaothername-cert"], ),
1ac26c
+   "CVE-2022-4203 type confusion test");
1ac26c
+
1ac26c
 #Check that we get the expected failure return code
1ac26c
 with({ exit_checker => sub { return shift == 2; } },
1ac26c
      sub {
1ac26c
-- 
1ac26c
2.39.1
1ac26c