|
| 1 | +From 8cae89bd2d496ad44fae8c0a40ca508461806d95 Mon Sep 17 00:00:00 2001 |
| 2 | +From: Alexander Kanavin <alex.kanavin@gmail.com> |
| 3 | +Date: Wed, 25 Sep 2024 23:23:47 +0200 |
| 4 | +Subject: [PATCH] gh-119400: make_ssl_certs: update reference test data |
| 5 | + automatically, pass in expiration dates as parameters #119400 (GH-119401) |
| 6 | + |
| 7 | +* Lib/test/certdata: do not hardcode reference cert data into tests |
| 8 | + |
| 9 | +The script was simply printing the reference data and asking |
| 10 | +users to update it by hand into the test suites. This can |
| 11 | +be easily improved by writing the data into files and |
| 12 | +having the test cases load the files. |
| 13 | + |
| 14 | +* make_ssl_certs: make it possible to pass in expiration dates from command line |
| 15 | + |
| 16 | +Note that in this commit, the defaults are same as they were, |
| 17 | +so if nothing is specified the script works as before. |
| 18 | + |
| 19 | +--------- |
| 20 | +Upstream-Status: Backport |
| 21 | +Signed-off-by: Alexander Kanavin <alex.kanavin@gmail.com> |
| 22 | +--- |
| 23 | + Lib/test/certdata/keycert.pem.reference | 13 +++++ |
| 24 | + Lib/test/certdata/keycert3.pem.reference | 15 +++++ |
| 25 | + Lib/test/certdata/make_ssl_certs.py | 56 +++++++++++-------- |
| 26 | + Lib/test/test_asyncio/utils.py | 21 +------ |
| 27 | + Lib/test/test_ssl.py | 36 ++---------- |
| 28 | + ...-05-22-13-18-02.gh-issue-119400.WEt83v.rst | 2 + |
| 29 | + 6 files changed, 71 insertions(+), 72 deletions(-) |
| 30 | + create mode 100644 Lib/test/certdata/keycert.pem.reference |
| 31 | + create mode 100644 Lib/test/certdata/keycert3.pem.reference |
| 32 | + create mode 100644 Misc/NEWS.d/next/Build/2024-05-22-13-18-02.gh-issue-119400.WEt83v.rst |
| 33 | + |
| 34 | +diff --git a/Lib/test/certdata/keycert.pem.reference b/Lib/test/certdata/keycert.pem.reference |
| 35 | +new file mode 100644 |
| 36 | +index 00000000000..f9a82f35f34 |
| 37 | +--- /dev/null |
| 38 | ++++ b/Lib/test/certdata/keycert.pem.reference |
| 39 | +@@ -0,0 +1,13 @@ |
| 40 | ++{'issuer': ((('countryName', 'XY'),), |
| 41 | ++ (('localityName', 'Castle Anthrax'),), |
| 42 | ++ (('organizationName', 'Python Software Foundation'),), |
| 43 | ++ (('commonName', 'localhost'),)), |
| 44 | ++ 'notAfter': 'Jan 24 04:21:36 2043 GMT', |
| 45 | ++ 'notBefore': 'Nov 25 04:21:36 2023 GMT', |
| 46 | ++ 'serialNumber': '53E14833F7546C29256DD0F034F776C5E983004C', |
| 47 | ++ 'subject': ((('countryName', 'XY'),), |
| 48 | ++ (('localityName', 'Castle Anthrax'),), |
| 49 | ++ (('organizationName', 'Python Software Foundation'),), |
| 50 | ++ (('commonName', 'localhost'),)), |
| 51 | ++ 'subjectAltName': (('DNS', 'localhost'),), |
| 52 | ++ 'version': 3} |
| 53 | +diff --git a/Lib/test/certdata/keycert3.pem.reference b/Lib/test/certdata/keycert3.pem.reference |
| 54 | +new file mode 100644 |
| 55 | +index 00000000000..04a749c920b |
| 56 | +--- /dev/null |
| 57 | ++++ b/Lib/test/certdata/keycert3.pem.reference |
| 58 | +@@ -0,0 +1,15 @@ |
| 59 | ++{'OCSP': ('http://testca.pythontest.net/testca/ocsp/',), |
| 60 | ++ 'caIssuers': ('http://testca.pythontest.net/testca/pycacert.cer',), |
| 61 | ++ 'crlDistributionPoints': ('http://testca.pythontest.net/testca/revocation.crl',), |
| 62 | ++ 'issuer': ((('countryName', 'XY'),), |
| 63 | ++ (('organizationName', 'Python Software Foundation CA'),), |
| 64 | ++ (('commonName', 'our-ca-server'),)), |
| 65 | ++ 'notAfter': 'Oct 28 14:23:16 2037 GMT', |
| 66 | ++ 'notBefore': 'Aug 29 14:23:16 2018 GMT', |
| 67 | ++ 'serialNumber': 'CB2D80995A69525C', |
| 68 | ++ 'subject': ((('countryName', 'XY'),), |
| 69 | ++ (('localityName', 'Castle Anthrax'),), |
| 70 | ++ (('organizationName', 'Python Software Foundation'),), |
| 71 | ++ (('commonName', 'localhost'),)), |
| 72 | ++ 'subjectAltName': (('DNS', 'localhost'),), |
| 73 | ++ 'version': 3} |
| 74 | +\ No newline at end of file |
| 75 | +diff --git a/Lib/test/certdata/make_ssl_certs.py b/Lib/test/certdata/make_ssl_certs.py |
| 76 | +index ed2037c1fdf..48f980124e1 100644 |
| 77 | +--- a/Lib/test/certdata/make_ssl_certs.py |
| 78 | ++++ b/Lib/test/certdata/make_ssl_certs.py |
| 79 | +@@ -1,6 +1,7 @@ |
| 80 | + """Make the custom certificate and private key files used by test_ssl |
| 81 | + and friends.""" |
| 82 | + |
| 83 | ++import argparse |
| 84 | + import os |
| 85 | + import pprint |
| 86 | + import shutil |
| 87 | +@@ -8,7 +9,8 @@ |
| 88 | + from subprocess import * |
| 89 | + |
| 90 | + startdate = "20180829142316Z" |
| 91 | +-enddate = "20371028142316Z" |
| 92 | ++enddate_default = "20371028142316Z" |
| 93 | ++days_default = "7000" |
| 94 | + |
| 95 | + req_template = """ |
| 96 | + [ default ] |
| 97 | +@@ -79,8 +81,8 @@ |
| 98 | + default_startdate = {startdate} |
| 99 | + enddate = {enddate} |
| 100 | + default_enddate = {enddate} |
| 101 | +- default_days = 7000 |
| 102 | +- default_crl_days = 7000 |
| 103 | ++ default_days = {days} |
| 104 | ++ default_crl_days = {days} |
| 105 | + certificate = pycacert.pem |
| 106 | + private_key = pycakey.pem |
| 107 | + serial = $dir/serial |
| 108 | +@@ -117,7 +119,7 @@ |
| 109 | + here = os.path.abspath(os.path.dirname(__file__)) |
| 110 | + |
| 111 | + |
| 112 | +-def make_cert_key(hostname, sign=False, extra_san='', |
| 113 | ++def make_cert_key(cmdlineargs, hostname, sign=False, extra_san='', |
| 114 | + ext='req_x509_extensions_full', key='rsa:3072'): |
| 115 | + print("creating cert for " + hostname) |
| 116 | + tempnames = [] |
| 117 | +@@ -130,11 +132,12 @@ def make_cert_key(hostname, sign=False, extra_san='', |
| 118 | + hostname=hostname, |
| 119 | + extra_san=extra_san, |
| 120 | + startdate=startdate, |
| 121 | +- enddate=enddate |
| 122 | ++ enddate=cmdlineargs.enddate, |
| 123 | ++ days=cmdlineargs.days |
| 124 | + ) |
| 125 | + with open(req_file, 'w') as f: |
| 126 | + f.write(req) |
| 127 | +- args = ['req', '-new', '-nodes', '-days', '7000', |
| 128 | ++ args = ['req', '-new', '-nodes', '-days', cmdlineargs.days, |
| 129 | + '-newkey', key, '-keyout', key_file, |
| 130 | + '-extensions', ext, |
| 131 | + '-config', req_file] |
| 132 | +@@ -175,7 +178,7 @@ def make_cert_key(hostname, sign=False, extra_san='', |
| 133 | + def unmake_ca(): |
| 134 | + shutil.rmtree(TMP_CADIR) |
| 135 | + |
| 136 | +-def make_ca(): |
| 137 | ++def make_ca(cmdlineargs): |
| 138 | + os.mkdir(TMP_CADIR) |
| 139 | + with open(os.path.join('cadir','index.txt'),'a+') as f: |
| 140 | + pass # empty file |
| 141 | +@@ -192,7 +195,8 @@ def make_ca(): |
| 142 | + hostname='our-ca-server', |
| 143 | + extra_san='', |
| 144 | + startdate=startdate, |
| 145 | +- enddate=enddate |
| 146 | ++ enddate=cmdlineargs.enddate, |
| 147 | ++ days=cmdlineargs.days |
| 148 | + ) |
| 149 | + t.write(req) |
| 150 | + t.flush() |
| 151 | +@@ -219,14 +223,22 @@ def make_ca(): |
| 152 | + shutil.copy('capath/ceff1710.0', 'capath/b1930218.0') |
| 153 | + |
| 154 | + |
| 155 | +-def print_cert(path): |
| 156 | ++def write_cert_reference(path): |
| 157 | + import _ssl |
| 158 | +- pprint.pprint(_ssl._test_decode_cert(path)) |
| 159 | ++ refdata = pprint.pformat(_ssl._test_decode_cert(path)) |
| 160 | ++ print(refdata) |
| 161 | ++ with open(path + '.reference', 'w') as f: |
| 162 | ++ print(refdata, file=f) |
| 163 | + |
| 164 | + |
| 165 | + if __name__ == '__main__': |
| 166 | ++ parser = argparse.ArgumentParser(description='Make the custom certificate and private key files used by test_ssl and friends.') |
| 167 | ++ parser.add_argument('--days', default=days_default) |
| 168 | ++ parser.add_argument('--enddate', default=enddate_default) |
| 169 | ++ cmdlineargs = parser.parse_args() |
| 170 | ++ |
| 171 | + os.chdir(here) |
| 172 | +- cert, key = make_cert_key('localhost', ext='req_x509_extensions_simple') |
| 173 | ++ cert, key = make_cert_key(cmdlineargs, 'localhost', ext='req_x509_extensions_simple') |
| 174 | + with open('ssl_cert.pem', 'w') as f: |
| 175 | + f.write(cert) |
| 176 | + with open('ssl_key.pem', 'w') as f: |
| 177 | +@@ -243,26 +255,26 @@ def print_cert(path): |
| 178 | + f.write(cert) |
| 179 | + |
| 180 | + # For certificate matching tests |
| 181 | +- make_ca() |
| 182 | +- cert, key = make_cert_key('fakehostname', ext='req_x509_extensions_simple') |
| 183 | ++ make_ca(cmdlineargs) |
| 184 | ++ cert, key = make_cert_key(cmdlineargs, 'fakehostname', ext='req_x509_extensions_simple') |
| 185 | + with open('keycert2.pem', 'w') as f: |
| 186 | + f.write(key) |
| 187 | + f.write(cert) |
| 188 | + |
| 189 | +- cert, key = make_cert_key('localhost', sign=True) |
| 190 | ++ cert, key = make_cert_key(cmdlineargs, 'localhost', sign=True) |
| 191 | + with open('keycert3.pem', 'w') as f: |
| 192 | + f.write(key) |
| 193 | + f.write(cert) |
| 194 | + |
| 195 | + check_call(['openssl', 'x509', '-outform', 'pem', '-in', 'keycert3.pem', '-out', 'cert3.pem']) |
| 196 | + |
| 197 | +- cert, key = make_cert_key('fakehostname', sign=True) |
| 198 | ++ cert, key = make_cert_key(cmdlineargs, 'fakehostname', sign=True) |
| 199 | + with open('keycert4.pem', 'w') as f: |
| 200 | + f.write(key) |
| 201 | + f.write(cert) |
| 202 | + |
| 203 | + cert, key = make_cert_key( |
| 204 | +- 'localhost-ecc', sign=True, key='param:secp384r1.pem' |
| 205 | ++ cmdlineargs, 'localhost-ecc', sign=True, key='param:secp384r1.pem' |
| 206 | + ) |
| 207 | + with open('keycertecc.pem', 'w') as f: |
| 208 | + f.write(key) |
| 209 | +@@ -282,7 +294,7 @@ def print_cert(path): |
| 210 | + 'RID.1 = 1.2.3.4.5', |
| 211 | + ] |
| 212 | + |
| 213 | +- cert, key = make_cert_key('allsans', sign=True, extra_san='\n'.join(extra_san)) |
| 214 | ++ cert, key = make_cert_key(cmdlineargs, 'allsans', sign=True, extra_san='\n'.join(extra_san)) |
| 215 | + with open('allsans.pem', 'w') as f: |
| 216 | + f.write(key) |
| 217 | + f.write(cert) |
| 218 | +@@ -299,17 +311,17 @@ def print_cert(path): |
| 219 | + ] |
| 220 | + |
| 221 | + # IDN SANS, signed |
| 222 | +- cert, key = make_cert_key('idnsans', sign=True, extra_san='\n'.join(extra_san)) |
| 223 | ++ cert, key = make_cert_key(cmdlineargs, 'idnsans', sign=True, extra_san='\n'.join(extra_san)) |
| 224 | + with open('idnsans.pem', 'w') as f: |
| 225 | + f.write(key) |
| 226 | + f.write(cert) |
| 227 | + |
| 228 | +- cert, key = make_cert_key('nosan', sign=True, ext='req_x509_extensions_nosan') |
| 229 | ++ cert, key = make_cert_key(cmdlineargs, 'nosan', sign=True, ext='req_x509_extensions_nosan') |
| 230 | + with open('nosan.pem', 'w') as f: |
| 231 | + f.write(key) |
| 232 | + f.write(cert) |
| 233 | + |
| 234 | + unmake_ca() |
| 235 | +- print("update Lib/test/test_ssl.py and Lib/test/test_asyncio/utils.py") |
| 236 | +- print_cert('keycert.pem') |
| 237 | +- print_cert('keycert3.pem') |
| 238 | ++ print("Writing out reference data for Lib/test/test_ssl.py and Lib/test/test_asyncio/utils.py") |
| 239 | ++ write_cert_reference('keycert.pem') |
| 240 | ++ write_cert_reference('keycert3.pem') |
| 241 | +diff --git a/Lib/test/test_asyncio/utils.py b/Lib/test/test_asyncio/utils.py |
| 242 | +index ce2408fc1aa..cfb5de58902 100644 |
| 243 | +--- a/Lib/test/test_asyncio/utils.py |
| 244 | ++++ b/Lib/test/test_asyncio/utils.py |
| 245 | +@@ -15,6 +15,7 @@ |
| 246 | + import unittest |
| 247 | + import weakref |
| 248 | + import warnings |
| 249 | ++from ast import literal_eval |
| 250 | + from unittest import mock |
| 251 | + |
| 252 | + from http.server import HTTPServer |
| 253 | +@@ -56,24 +57,8 @@ def data_file(*filename): |
| 254 | + ONLYKEY = data_file('certdata', 'ssl_key.pem') |
| 255 | + SIGNED_CERTFILE = data_file('certdata', 'keycert3.pem') |
| 256 | + SIGNING_CA = data_file('certdata', 'pycacert.pem') |
| 257 | +-PEERCERT = { |
| 258 | +- 'OCSP': ('http://testca.pythontest.net/testca/ocsp/',), |
| 259 | +- 'caIssuers': ('http://testca.pythontest.net/testca/pycacert.cer',), |
| 260 | +- 'crlDistributionPoints': ('http://testca.pythontest.net/testca/revocation.crl',), |
| 261 | +- 'issuer': ((('countryName', 'XY'),), |
| 262 | +- (('organizationName', 'Python Software Foundation CA'),), |
| 263 | +- (('commonName', 'our-ca-server'),)), |
| 264 | +- 'notAfter': 'Oct 28 14:23:16 2037 GMT', |
| 265 | +- 'notBefore': 'Aug 29 14:23:16 2018 GMT', |
| 266 | +- 'serialNumber': 'CB2D80995A69525C', |
| 267 | +- 'subject': ((('countryName', 'XY'),), |
| 268 | +- (('localityName', 'Castle Anthrax'),), |
| 269 | +- (('organizationName', 'Python Software Foundation'),), |
| 270 | +- (('commonName', 'localhost'),)), |
| 271 | +- 'subjectAltName': (('DNS', 'localhost'),), |
| 272 | +- 'version': 3 |
| 273 | +-} |
| 274 | +- |
| 275 | ++with open(data_file('certdata', 'keycert3.pem.reference')) as file: |
| 276 | ++ PEERCERT = literal_eval(file.read()) |
| 277 | + |
| 278 | + def simple_server_sslcontext(): |
| 279 | + server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) |
| 280 | +diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py |
| 281 | +index 7fdd2be78d5..fb86383d78e 100644 |
| 282 | +--- a/Lib/test/test_ssl.py |
| 283 | ++++ b/Lib/test/test_ssl.py |
| 284 | +@@ -84,21 +84,8 @@ def data_file(*name): |
| 285 | + CAFILE_NEURONIO = data_file("capath", "4e1295a3.0") |
| 286 | + CAFILE_CACERT = data_file("capath", "5ed36f99.0") |
| 287 | + |
| 288 | +-CERTFILE_INFO = { |
| 289 | +- 'issuer': ((('countryName', 'XY'),), |
| 290 | +- (('localityName', 'Castle Anthrax'),), |
| 291 | +- (('organizationName', 'Python Software Foundation'),), |
| 292 | +- (('commonName', 'localhost'),)), |
| 293 | +- 'notAfter': 'Jan 24 04:21:36 2043 GMT', |
| 294 | +- 'notBefore': 'Nov 25 04:21:36 2023 GMT', |
| 295 | +- 'serialNumber': '53E14833F7546C29256DD0F034F776C5E983004C', |
| 296 | +- 'subject': ((('countryName', 'XY'),), |
| 297 | +- (('localityName', 'Castle Anthrax'),), |
| 298 | +- (('organizationName', 'Python Software Foundation'),), |
| 299 | +- (('commonName', 'localhost'),)), |
| 300 | +- 'subjectAltName': (('DNS', 'localhost'),), |
| 301 | +- 'version': 3 |
| 302 | +-} |
| 303 | ++with open(data_file('keycert.pem.reference')) as file: |
| 304 | ++ CERTFILE_INFO = literal_eval(file.read()) |
| 305 | + |
| 306 | + # empty CRL |
| 307 | + CRLFILE = data_file("revocation.crl") |
| 308 | +@@ -108,23 +95,8 @@ def data_file(*name): |
| 309 | + SINGED_CERTFILE_ONLY = data_file("cert3.pem") |
| 310 | + SIGNED_CERTFILE_HOSTNAME = 'localhost' |
| 311 | + |
| 312 | +-SIGNED_CERTFILE_INFO = { |
| 313 | +- 'OCSP': ('http://testca.pythontest.net/testca/ocsp/',), |
| 314 | +- 'caIssuers': ('http://testca.pythontest.net/testca/pycacert.cer',), |
| 315 | +- 'crlDistributionPoints': ('http://testca.pythontest.net/testca/revocation.crl',), |
| 316 | +- 'issuer': ((('countryName', 'XY'),), |
| 317 | +- (('organizationName', 'Python Software Foundation CA'),), |
| 318 | +- (('commonName', 'our-ca-server'),)), |
| 319 | +- 'notAfter': 'Oct 28 14:23:16 2037 GMT', |
| 320 | +- 'notBefore': 'Aug 29 14:23:16 2018 GMT', |
| 321 | +- 'serialNumber': 'CB2D80995A69525C', |
| 322 | +- 'subject': ((('countryName', 'XY'),), |
| 323 | +- (('localityName', 'Castle Anthrax'),), |
| 324 | +- (('organizationName', 'Python Software Foundation'),), |
| 325 | +- (('commonName', 'localhost'),)), |
| 326 | +- 'subjectAltName': (('DNS', 'localhost'),), |
| 327 | +- 'version': 3 |
| 328 | +-} |
| 329 | ++with open(data_file('keycert3.pem.reference')) as file: |
| 330 | ++ SIGNED_CERTFILE_INFO = literal_eval(file.read()) |
| 331 | + |
| 332 | + SIGNED_CERTFILE2 = data_file("keycert4.pem") |
| 333 | + SIGNED_CERTFILE2_HOSTNAME = 'fakehostname' |
| 334 | +diff --git a/Misc/NEWS.d/next/Build/2024-05-22-13-18-02.gh-issue-119400.WEt83v.rst b/Misc/NEWS.d/next/Build/2024-05-22-13-18-02.gh-issue-119400.WEt83v.rst |
| 335 | +new file mode 100644 |
| 336 | +index 00000000000..b4029f20579 |
| 337 | +--- /dev/null |
| 338 | ++++ b/Misc/NEWS.d/next/Build/2024-05-22-13-18-02.gh-issue-119400.WEt83v.rst |
| 339 | +@@ -0,0 +1,2 @@ |
| 340 | ++``make_ssl_certs``, the script that prepares certificate data for the |
| 341 | ++test suite, now allows specifying expiration dates. |
| 342 | +-- |
| 343 | +2.39.5 |
| 344 | + |
0 commit comments