Blame SOURCES/00255-Fix-ssl-module-parsing-of-GEN_RID-subject-alternative-name-fields-in-X.509-certs.patch

71084d
71084d
# HG changeset patch
71084d
# User Christian Heimes <christian@python.org>
71084d
# Date 1473197135 -7200
71084d
# Node ID 74805fd9e7343649372d0b9c76b4490b2975a674
71084d
# Parent  6f4f19217d9be12be7a9c86cf1e118b140564b4f
71084d
Issue #27691: Fix ssl module's parsing of GEN_RID subject alternative name fields in X.509 certs.
71084d
71084d
diff --git a/Lib/test/allsans.pem b/Lib/test/allsans.pem
71084d
new file mode 100644
71084d
--- /dev/null
71084d
+++ b/Lib/test/allsans.pem
71084d
@@ -0,0 +1,37 @@
71084d
+-----BEGIN PRIVATE KEY-----
71084d
+MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAOoy7/QOtTjQ0niE
71084d
+6uDcTwtkC0R2Tvy1AjVnXohCntZfdzbTGDoYTgXSOLsP8A697jUiJ8VCePGH50xG
71084d
+Z4DKnAF3a9O3a9nr2pLXb0iY3XOMv+YEBii7CfI+3oxFYgCl0sMgHzDD2ZTVYAsm
71084d
+DWgLUVsE2gHEccRwrM2tPf2EgR+FAgMBAAECgYEA3qyfyYVSeTrTYxO93x6ZaVMu
71084d
+A2IZp9zSxMQL9bKiI2GRj+cV2ebSCGbg2btFnD6qBor7FWsmYz+8g6FNN/9sY4az
71084d
+61rMqMtQvLBe+7L8w70FeTze4qQ4Y1oQri0qD6tBWhDVlpnbI5Py9bkZKD67yVUk
71084d
+elcEA/5x4PrYXkuqsAECQQD80NjT0mDvaY0JOOaQFSEpMv6QiUA8GGX8Xli7IoKb
71084d
+tAolPG8rQBa+qSpcWfDMTrWw/aWHuMEEQoP/bVDH9W4FAkEA7SYQbBAKnojZ5A3G
71084d
+kOHdV7aeivRQxQk/JN8Fb8oKB9Csvpv/BsuGxPKXHdhFa6CBTTsNRtHQw/szPo4l
71084d
+xMIjgQJAPoMxqibR+0EBM6+TKzteSL6oPXsCnBl4Vk/J5vPgkbmR7KUl4+7j8N8J
71084d
+b2554TrxKEN/w7CGYZRE6UrRd7ATNQJAWD7Yz41sli+wfPdPU2xo1BHljyl4wMk/
71084d
+EPZYbI/PCbdyAH/F935WyQTIjNeEhZc1Zkq6FwdOWw8ns3hrv3rKgQJAHXv1BqUa
71084d
+czGPIFxX2TNoqtcl6/En4vrxVB1wzsfzkkDAg98kBl7qsF+S3qujSzKikjeaVbI2
71084d
+/CyWR2P3yLtOmA==
71084d
+-----END PRIVATE KEY-----
71084d
+-----BEGIN CERTIFICATE-----
71084d
+MIIDcjCCAtugAwIBAgIJAN5dc9TOWjB7MA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV
71084d
+BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u
71084d
+IFNvZnR3YXJlIEZvdW5kYXRpb24xEDAOBgNVBAMMB2FsbHNhbnMwHhcNMTYwODA1
71084d
+MTAyMTExWhcNMjYwODAzMTAyMTExWjBdMQswCQYDVQQGEwJYWTEXMBUGA1UEBwwO
71084d
+Q2FzdGxlIEFudGhyYXgxIzAhBgNVBAoMGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0
71084d
+aW9uMRAwDgYDVQQDDAdhbGxzYW5zMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
71084d
+gQDqMu/0DrU40NJ4hOrg3E8LZAtEdk78tQI1Z16IQp7WX3c20xg6GE4F0ji7D/AO
71084d
+ve41IifFQnjxh+dMRmeAypwBd2vTt2vZ69qS129ImN1zjL/mBAYouwnyPt6MRWIA
71084d
+pdLDIB8ww9mU1WALJg1oC1FbBNoBxHHEcKzNrT39hIEfhQIDAQABo4IBODCCATQw
71084d
+ggEwBgNVHREEggEnMIIBI4IHYWxsc2Fuc6AeBgMqAwSgFwwVc29tZSBvdGhlciBp
71084d
+ZGVudGlmaWVyoDUGBisGAQUCAqArMCmgEBsOS0VSQkVST1MuUkVBTE2hFTAToAMC
71084d
+AQGhDDAKGwh1c2VybmFtZYEQdXNlckBleGFtcGxlLm9yZ4IPd3d3LmV4YW1wbGUu
71084d
+b3JnpGcwZTELMAkGA1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMw
71084d
+IQYDVQQKDBpQeXRob24gU29mdHdhcmUgRm91bmRhdGlvbjEYMBYGA1UEAwwPZGly
71084d
+bmFtZSBleGFtcGxlhhdodHRwczovL3d3dy5weXRob24ub3JnL4cEfwAAAYcQAAAA
71084d
+AAAAAAAAAAAAAAAAAYgEKgMEBTANBgkqhkiG9w0BAQsFAAOBgQAy16h+F+nOmeiT
71084d
+VWR0fc8F/j6FcadbLseAUaogcC15OGxCl4UYpLV88HBkABOoGCpP155qwWTwOrdG
71084d
+iYPGJSusf1OnJEbvzFejZf6u078bPd9/ZL4VWLjv+FPGkjd+N+/OaqMvgj8Lu99f
71084d
+3Y/C4S7YbHxxwff6C6l2Xli+q6gnuQ==
71084d
+-----END CERTIFICATE-----
71084d
diff --git a/Lib/test/make_ssl_certs.py b/Lib/test/make_ssl_certs.py
71084d
--- a/Lib/test/make_ssl_certs.py
71084d
+++ b/Lib/test/make_ssl_certs.py
71084d
@@ -20,7 +20,28 @@ req_template = """
71084d
     CN                     = {hostname}
71084d
 
71084d
     [req_x509_extensions]
71084d
-    subjectAltName         = DNS:{hostname}
71084d
+    subjectAltName         = @san
71084d
+
71084d
+    [san]
71084d
+    DNS.1 = {hostname}
71084d
+    {extra_san}
71084d
+
71084d
+    [dir_sect]
71084d
+    C                      = XY
71084d
+    L                      = Castle Anthrax
71084d
+    O                      = Python Software Foundation
71084d
+    CN                     = dirname example
71084d
+
71084d
+    [princ_name]
71084d
+    realm = EXP:0, GeneralString:KERBEROS.REALM
71084d
+    principal_name = EXP:1, SEQUENCE:principal_seq
71084d
+
71084d
+    [principal_seq]
71084d
+    name_type = EXP:0, INTEGER:1
71084d
+    name_string = EXP:1, SEQUENCE:principals
71084d
+
71084d
+    [principals]
71084d
+    princ1 = GeneralString:username
71084d
 
71084d
     [ ca ]
71084d
     default_ca      = CA_default
71084d
@@ -67,7 +88,7 @@ req_template = """
71084d
 
71084d
 here = os.path.abspath(os.path.dirname(__file__))
71084d
 
71084d
-def make_cert_key(hostname, sign=False):
71084d
+def make_cert_key(hostname, sign=False, extra_san=''):
71084d
     print("creating cert for " + hostname)
71084d
     tempnames = []
71084d
     for i in range(3):
71084d
@@ -75,8 +96,9 @@ def make_cert_key(hostname, sign=False):
71084d
             tempnames.append(f.name)
71084d
     req_file, cert_file, key_file = tempnames
71084d
     try:
71084d
+        req = req_template.format(hostname=hostname, extra_san=extra_san)
71084d
         with open(req_file, 'w') as f:
71084d
-            f.write(req_template.format(hostname=hostname))
71084d
+            f.write(req)
71084d
         args = ['req', '-new', '-days', '3650', '-nodes',
71084d
                 '-newkey', 'rsa:1024', '-keyout', key_file,
71084d
                 '-config', req_file]
71084d
@@ -120,7 +142,7 @@ def make_ca():
71084d
         f.write('unique_subject = no')
71084d
 
71084d
     with tempfile.NamedTemporaryFile("w") as t:
71084d
-        t.write(req_template.format(hostname='our-ca-server'))
71084d
+        t.write(req_template.format(hostname='our-ca-server', extra_san=''))
71084d
         t.flush()
71084d
         with tempfile.NamedTemporaryFile() as f:
71084d
             args = ['req', '-new', '-days', '3650', '-extensions', 'v3_ca', '-nodes',
71084d
@@ -171,6 +193,25 @@ if __name__ == '__main__':
71084d
         f.write(key)
71084d
         f.write(cert)
71084d
 
71084d
+    extra_san = [
71084d
+        'otherName.1 = 1.2.3.4;UTF8:some other identifier',
71084d
+        'otherName.2 = 1.3.6.1.5.2.2;SEQUENCE:princ_name',
71084d
+        'email.1 = user@example.org',
71084d
+        'DNS.2 = www.example.org',
71084d
+        # GEN_X400
71084d
+        'dirName.1 = dir_sect',
71084d
+        # GEN_EDIPARTY
71084d
+        'URI.1 = https://www.python.org/',
71084d
+        'IP.1 = 127.0.0.1',
71084d
+        'IP.2 = ::1',
71084d
+        'RID.1 = 1.2.3.4.5',
71084d
+    ]
71084d
+
71084d
+    cert, key = make_cert_key('allsans', extra_san='\n'.join(extra_san))
71084d
+    with open('allsans.pem', 'w') as f:
71084d
+        f.write(key)
71084d
+        f.write(cert)
71084d
+
71084d
     unmake_ca()
71084d
     print("\n\nPlease change the values in test_ssl.py, test_parse_cert function related to notAfter,notBefore and serialNumber")
71084d
     check_call(['openssl','x509','-in','keycert.pem','-dates','-serial','-noout'])
71084d
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
71084d
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
71084d
index fa59641..9d5816b 100644
71084d
--- a/Lib/test/test_ssl.py
71084d
+++ b/Lib/test/test_ssl.py
71084d
@@ -57,6 +57,8 @@ CRLFILE = data_file("revocation.crl")
71084d
 SIGNED_CERTFILE = data_file("keycert3.pem")
71084d
 SIGNED_CERTFILE2 = data_file("keycert4.pem")
71084d
 SIGNING_CA = data_file("pycacert.pem")
71084d
+# cert with all kinds of subject alt names
71084d
+ALLSANFILE = data_file("allsans.pem")
71084d
 
71084d
 SVN_PYTHON_ORG_ROOT_CERT = data_file("https_svn_python_org_root.pem")
71084d
 
71084d
@@ -236,6 +238,28 @@ class BasicSocketTests(unittest.TestCase):
71084d
                          ('IP Address', '2001:DB8:0:0:0:0:0:1\n'))
71084d
                         )
71084d
 
71084d
+    def test_parse_all_sans(self):
71084d
+        p = ssl._ssl._test_decode_cert(ALLSANFILE)
71084d
+        self.assertEqual(p['subjectAltName'],
71084d
+            (
71084d
+                ('DNS', 'allsans'),
71084d
+                ('othername', '<unsupported>'),
71084d
+                ('othername', '<unsupported>'),
71084d
+                ('email', 'user@example.org'),
71084d
+                ('DNS', 'www.example.org'),
71084d
+                ('DirName',
71084d
+                    ((('countryName', 'XY'),),
71084d
+                    (('localityName', 'Castle Anthrax'),),
71084d
+                    (('organizationName', 'Python Software Foundation'),),
71084d
+                    (('commonName', 'dirname example'),))),
71084d
+                ('URI', 'https://www.python.org/'),
71084d
+                ('IP Address', '127.0.0.1'),
71084d
+                ('IP Address', '0:0:0:0:0:0:0:1\n'),
71084d
+                ('Registered ID', '1.2.3.4.5')
71084d
+            )
71084d
+        )
71084d
+
71084d
+
71084d
     def test_DER_to_PEM(self):
71084d
         with open(SVN_PYTHON_ORG_ROOT_CERT, 'r') as f:
71084d
             pem = f.read()
71084d
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
71084d
--- a/Modules/_ssl.c
71084d
+++ b/Modules/_ssl.c
71084d
@@ -953,6 +953,35 @@ static PyObject *
71084d
                 PyTuple_SET_ITEM(t, 1, v);
71084d
                 break;
71084d
 
71084d
+            case GEN_RID:
71084d
+                t = PyTuple_New(2);
71084d
+                if (t == NULL)
71084d
+                    goto fail;
71084d
+
71084d
+                v = PyUnicode_FromString("Registered ID");
71084d
+                if (v == NULL) {
71084d
+                    Py_DECREF(t);
71084d
+                    goto fail;
71084d
+                }
71084d
+                PyTuple_SET_ITEM(t, 0, v);
71084d
+
71084d
+                len = i2t_ASN1_OBJECT(buf, sizeof(buf)-1, name->d.rid);
71084d
+                if (len < 0) {
71084d
+                    Py_DECREF(t);
71084d
+                    _setSSLError(NULL, 0, __FILE__, __LINE__);
71084d
+                    goto fail;
71084d
+                } else if (len >= (int)sizeof(buf)) {
71084d
+                    v = PyUnicode_FromString("<INVALID>");
71084d
+                } else {
71084d
+                    v = PyUnicode_FromStringAndSize(buf, len);
71084d
+                }
71084d
+                if (v == NULL) {
71084d
+                    Py_DECREF(t);
71084d
+                    goto fail;
71084d
+                }
71084d
+                PyTuple_SET_ITEM(t, 1, v);
71084d
+                break;
71084d
+
71084d
             default:
71084d
                 /* for everything else, we use the OpenSSL print form */
71084d
                 switch (gntype) {
71084d
@@ -978,8 +1007,12 @@ static PyObject *
71084d
                     goto fail;
71084d
                 }
71084d
                 vptr = strchr(buf, ':');
71084d
-                if (vptr == NULL)
71084d
+                if (vptr == NULL) {
71084d
+                    PyErr_Format(PyExc_ValueError,
71084d
+                                 "Invalid value %.200s",
71084d
+                                 buf);
71084d
                     goto fail;
71084d
+                }
71084d
                 t = PyTuple_New(2);
71084d
                 if (t == NULL)
71084d
                     goto fail;
71084d