An interpreted, interactive, object-oriented programming language
CentOS Sources
2017-08-01 71084d584ff953f5463757ec6536406320560b4d
commit | author | age
71084d 1
CS 2 # HG changeset patch
3 # User Christian Heimes <christian@python.org>
4 # Date 1473197135 -7200
5 # Node ID 74805fd9e7343649372d0b9c76b4490b2975a674
6 # Parent  6f4f19217d9be12be7a9c86cf1e118b140564b4f
7 Issue #27691: Fix ssl module's parsing of GEN_RID subject alternative name fields in X.509 certs.
8
9 diff --git a/Lib/test/allsans.pem b/Lib/test/allsans.pem
10 new file mode 100644
11 --- /dev/null
12 +++ b/Lib/test/allsans.pem
13 @@ -0,0 +1,37 @@
14 +-----BEGIN PRIVATE KEY-----
15 +MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAOoy7/QOtTjQ0niE
16 +6uDcTwtkC0R2Tvy1AjVnXohCntZfdzbTGDoYTgXSOLsP8A697jUiJ8VCePGH50xG
17 +Z4DKnAF3a9O3a9nr2pLXb0iY3XOMv+YEBii7CfI+3oxFYgCl0sMgHzDD2ZTVYAsm
18 +DWgLUVsE2gHEccRwrM2tPf2EgR+FAgMBAAECgYEA3qyfyYVSeTrTYxO93x6ZaVMu
19 +A2IZp9zSxMQL9bKiI2GRj+cV2ebSCGbg2btFnD6qBor7FWsmYz+8g6FNN/9sY4az
20 +61rMqMtQvLBe+7L8w70FeTze4qQ4Y1oQri0qD6tBWhDVlpnbI5Py9bkZKD67yVUk
21 +elcEA/5x4PrYXkuqsAECQQD80NjT0mDvaY0JOOaQFSEpMv6QiUA8GGX8Xli7IoKb
22 +tAolPG8rQBa+qSpcWfDMTrWw/aWHuMEEQoP/bVDH9W4FAkEA7SYQbBAKnojZ5A3G
23 +kOHdV7aeivRQxQk/JN8Fb8oKB9Csvpv/BsuGxPKXHdhFa6CBTTsNRtHQw/szPo4l
24 +xMIjgQJAPoMxqibR+0EBM6+TKzteSL6oPXsCnBl4Vk/J5vPgkbmR7KUl4+7j8N8J
25 +b2554TrxKEN/w7CGYZRE6UrRd7ATNQJAWD7Yz41sli+wfPdPU2xo1BHljyl4wMk/
26 +EPZYbI/PCbdyAH/F935WyQTIjNeEhZc1Zkq6FwdOWw8ns3hrv3rKgQJAHXv1BqUa
27 +czGPIFxX2TNoqtcl6/En4vrxVB1wzsfzkkDAg98kBl7qsF+S3qujSzKikjeaVbI2
28 +/CyWR2P3yLtOmA==
29 +-----END PRIVATE KEY-----
30 +-----BEGIN CERTIFICATE-----
31 +MIIDcjCCAtugAwIBAgIJAN5dc9TOWjB7MA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV
32 +BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u
33 +IFNvZnR3YXJlIEZvdW5kYXRpb24xEDAOBgNVBAMMB2FsbHNhbnMwHhcNMTYwODA1
34 +MTAyMTExWhcNMjYwODAzMTAyMTExWjBdMQswCQYDVQQGEwJYWTEXMBUGA1UEBwwO
35 +Q2FzdGxlIEFudGhyYXgxIzAhBgNVBAoMGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0
36 +aW9uMRAwDgYDVQQDDAdhbGxzYW5zMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
37 +gQDqMu/0DrU40NJ4hOrg3E8LZAtEdk78tQI1Z16IQp7WX3c20xg6GE4F0ji7D/AO
38 +ve41IifFQnjxh+dMRmeAypwBd2vTt2vZ69qS129ImN1zjL/mBAYouwnyPt6MRWIA
39 +pdLDIB8ww9mU1WALJg1oC1FbBNoBxHHEcKzNrT39hIEfhQIDAQABo4IBODCCATQw
40 +ggEwBgNVHREEggEnMIIBI4IHYWxsc2Fuc6AeBgMqAwSgFwwVc29tZSBvdGhlciBp
41 +ZGVudGlmaWVyoDUGBisGAQUCAqArMCmgEBsOS0VSQkVST1MuUkVBTE2hFTAToAMC
42 +AQGhDDAKGwh1c2VybmFtZYEQdXNlckBleGFtcGxlLm9yZ4IPd3d3LmV4YW1wbGUu
43 +b3JnpGcwZTELMAkGA1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMw
44 +IQYDVQQKDBpQeXRob24gU29mdHdhcmUgRm91bmRhdGlvbjEYMBYGA1UEAwwPZGly
45 +bmFtZSBleGFtcGxlhhdodHRwczovL3d3dy5weXRob24ub3JnL4cEfwAAAYcQAAAA
46 +AAAAAAAAAAAAAAAAAYgEKgMEBTANBgkqhkiG9w0BAQsFAAOBgQAy16h+F+nOmeiT
47 +VWR0fc8F/j6FcadbLseAUaogcC15OGxCl4UYpLV88HBkABOoGCpP155qwWTwOrdG
48 +iYPGJSusf1OnJEbvzFejZf6u078bPd9/ZL4VWLjv+FPGkjd+N+/OaqMvgj8Lu99f
49 +3Y/C4S7YbHxxwff6C6l2Xli+q6gnuQ==
50 +-----END CERTIFICATE-----
51 diff --git a/Lib/test/make_ssl_certs.py b/Lib/test/make_ssl_certs.py
52 --- a/Lib/test/make_ssl_certs.py
53 +++ b/Lib/test/make_ssl_certs.py
54 @@ -20,7 +20,28 @@ req_template = """
55      CN                     = {hostname}
56  
57      [req_x509_extensions]
58 -    subjectAltName         = DNS:{hostname}
59 +    subjectAltName         = @san
60 +
61 +    [san]
62 +    DNS.1 = {hostname}
63 +    {extra_san}
64 +
65 +    [dir_sect]
66 +    C                      = XY
67 +    L                      = Castle Anthrax
68 +    O                      = Python Software Foundation
69 +    CN                     = dirname example
70 +
71 +    [princ_name]
72 +    realm = EXP:0, GeneralString:KERBEROS.REALM
73 +    principal_name = EXP:1, SEQUENCE:principal_seq
74 +
75 +    [principal_seq]
76 +    name_type = EXP:0, INTEGER:1
77 +    name_string = EXP:1, SEQUENCE:principals
78 +
79 +    [principals]
80 +    princ1 = GeneralString:username
81  
82      [ ca ]
83      default_ca      = CA_default
84 @@ -67,7 +88,7 @@ req_template = """
85  
86  here = os.path.abspath(os.path.dirname(__file__))
87  
88 -def make_cert_key(hostname, sign=False):
89 +def make_cert_key(hostname, sign=False, extra_san=''):
90      print("creating cert for " + hostname)
91      tempnames = []
92      for i in range(3):
93 @@ -75,8 +96,9 @@ def make_cert_key(hostname, sign=False):
94              tempnames.append(f.name)
95      req_file, cert_file, key_file = tempnames
96      try:
97 +        req = req_template.format(hostname=hostname, extra_san=extra_san)
98          with open(req_file, 'w') as f:
99 -            f.write(req_template.format(hostname=hostname))
100 +            f.write(req)
101          args = ['req', '-new', '-days', '3650', '-nodes',
102                  '-newkey', 'rsa:1024', '-keyout', key_file,
103                  '-config', req_file]
104 @@ -120,7 +142,7 @@ def make_ca():
105          f.write('unique_subject = no')
106  
107      with tempfile.NamedTemporaryFile("w") as t:
108 -        t.write(req_template.format(hostname='our-ca-server'))
109 +        t.write(req_template.format(hostname='our-ca-server', extra_san=''))
110          t.flush()
111          with tempfile.NamedTemporaryFile() as f:
112              args = ['req', '-new', '-days', '3650', '-extensions', 'v3_ca', '-nodes',
113 @@ -171,6 +193,25 @@ if __name__ == '__main__':
114          f.write(key)
115          f.write(cert)
116  
117 +    extra_san = [
118 +        'otherName.1 = 1.2.3.4;UTF8:some other identifier',
119 +        'otherName.2 = 1.3.6.1.5.2.2;SEQUENCE:princ_name',
120 +        'email.1 = user@example.org',
121 +        'DNS.2 = www.example.org',
122 +        # GEN_X400
123 +        'dirName.1 = dir_sect',
124 +        # GEN_EDIPARTY
125 +        'URI.1 = https://www.python.org/',
126 +        'IP.1 = 127.0.0.1',
127 +        'IP.2 = ::1',
128 +        'RID.1 = 1.2.3.4.5',
129 +    ]
130 +
131 +    cert, key = make_cert_key('allsans', extra_san='\n'.join(extra_san))
132 +    with open('allsans.pem', 'w') as f:
133 +        f.write(key)
134 +        f.write(cert)
135 +
136      unmake_ca()
137      print("\n\nPlease change the values in test_ssl.py, test_parse_cert function related to notAfter,notBefore and serialNumber")
138      check_call(['openssl','x509','-in','keycert.pem','-dates','-serial','-noout'])
139 diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
140 diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
141 index fa59641..9d5816b 100644
142 --- a/Lib/test/test_ssl.py
143 +++ b/Lib/test/test_ssl.py
144 @@ -57,6 +57,8 @@ CRLFILE = data_file("revocation.crl")
145  SIGNED_CERTFILE = data_file("keycert3.pem")
146  SIGNED_CERTFILE2 = data_file("keycert4.pem")
147  SIGNING_CA = data_file("pycacert.pem")
148 +# cert with all kinds of subject alt names
149 +ALLSANFILE = data_file("allsans.pem")
150  
151  SVN_PYTHON_ORG_ROOT_CERT = data_file("https_svn_python_org_root.pem")
152  
153 @@ -236,6 +238,28 @@ class BasicSocketTests(unittest.TestCase):
154                           ('IP Address', '2001:DB8:0:0:0:0:0:1\n'))
155                          )
156  
157 +    def test_parse_all_sans(self):
158 +        p = ssl._ssl._test_decode_cert(ALLSANFILE)
159 +        self.assertEqual(p['subjectAltName'],
160 +            (
161 +                ('DNS', 'allsans'),
162 +                ('othername', '<unsupported>'),
163 +                ('othername', '<unsupported>'),
164 +                ('email', 'user@example.org'),
165 +                ('DNS', 'www.example.org'),
166 +                ('DirName',
167 +                    ((('countryName', 'XY'),),
168 +                    (('localityName', 'Castle Anthrax'),),
169 +                    (('organizationName', 'Python Software Foundation'),),
170 +                    (('commonName', 'dirname example'),))),
171 +                ('URI', 'https://www.python.org/'),
172 +                ('IP Address', '127.0.0.1'),
173 +                ('IP Address', '0:0:0:0:0:0:0:1\n'),
174 +                ('Registered ID', '1.2.3.4.5')
175 +            )
176 +        )
177 +
178 +
179      def test_DER_to_PEM(self):
180          with open(SVN_PYTHON_ORG_ROOT_CERT, 'r') as f:
181              pem = f.read()
182 diff --git a/Modules/_ssl.c b/Modules/_ssl.c
183 --- a/Modules/_ssl.c
184 +++ b/Modules/_ssl.c
185 @@ -953,6 +953,35 @@ static PyObject *
186                  PyTuple_SET_ITEM(t, 1, v);
187                  break;
188  
189 +            case GEN_RID:
190 +                t = PyTuple_New(2);
191 +                if (t == NULL)
192 +                    goto fail;
193 +
194 +                v = PyUnicode_FromString("Registered ID");
195 +                if (v == NULL) {
196 +                    Py_DECREF(t);
197 +                    goto fail;
198 +                }
199 +                PyTuple_SET_ITEM(t, 0, v);
200 +
201 +                len = i2t_ASN1_OBJECT(buf, sizeof(buf)-1, name->d.rid);
202 +                if (len < 0) {
203 +                    Py_DECREF(t);
204 +                    _setSSLError(NULL, 0, __FILE__, __LINE__);
205 +                    goto fail;
206 +                } else if (len >= (int)sizeof(buf)) {
207 +                    v = PyUnicode_FromString("<INVALID>");
208 +                } else {
209 +                    v = PyUnicode_FromStringAndSize(buf, len);
210 +                }
211 +                if (v == NULL) {
212 +                    Py_DECREF(t);
213 +                    goto fail;
214 +                }
215 +                PyTuple_SET_ITEM(t, 1, v);
216 +                break;
217 +
218              default:
219                  /* for everything else, we use the OpenSSL print form */
220                  switch (gntype) {
221 @@ -978,8 +1007,12 @@ static PyObject *
222                      goto fail;
223                  }
224                  vptr = strchr(buf, ':');
225 -                if (vptr == NULL)
226 +                if (vptr == NULL) {
227 +                    PyErr_Format(PyExc_ValueError,
228 +                                 "Invalid value %.200s",
229 +                                 buf);
230                      goto fail;
231 +                }
232                  t = PyTuple_New(2);
233                  if (t == NULL)
234                      goto fail;
235