gh-119400: make_ssl_certs: update reference test data automatically, pass in expiration dates as parameters #119400 (GH-119401)

* Lib/test/certdata: do not hardcode reference cert data into tests

The script was simply printing the reference data and asking
users to update it by hand into the test suites. This can
be easily improved by writing the data into files and
having the test cases load the files.

* make_ssl_certs: make it possible to pass in expiration dates from command line

Note that in this commit, the defaults are same as they were,
so if nothing is specified the script works as before.

---------

Signed-off-by: Alexander Kanavin <alex.kanavin@gmail.com>
This commit is contained in:
Alexander Kanavin 2024-09-25 23:23:47 +02:00 committed by GitHub
parent 17a544b257
commit 1ff1b899ce
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 72 additions and 72 deletions

View file

@ -0,0 +1,13 @@
{'issuer': ((('countryName', 'XY'),),
(('localityName', 'Castle Anthrax'),),
(('organizationName', 'Python Software Foundation'),),
(('commonName', 'localhost'),)),
'notAfter': 'Jan 24 04:21:36 2043 GMT',
'notBefore': 'Nov 25 04:21:36 2023 GMT',
'serialNumber': '53E14833F7546C29256DD0F034F776C5E983004C',
'subject': ((('countryName', 'XY'),),
(('localityName', 'Castle Anthrax'),),
(('organizationName', 'Python Software Foundation'),),
(('commonName', 'localhost'),)),
'subjectAltName': (('DNS', 'localhost'),),
'version': 3}

View file

@ -0,0 +1,15 @@
{'OCSP': ('http://testca.pythontest.net/testca/ocsp/',),
'caIssuers': ('http://testca.pythontest.net/testca/pycacert.cer',),
'crlDistributionPoints': ('http://testca.pythontest.net/testca/revocation.crl',),
'issuer': ((('countryName', 'XY'),),
(('organizationName', 'Python Software Foundation CA'),),
(('commonName', 'our-ca-server'),)),
'notAfter': 'Oct 28 14:23:16 2037 GMT',
'notBefore': 'Aug 29 14:23:16 2018 GMT',
'serialNumber': 'CB2D80995A69525C',
'subject': ((('countryName', 'XY'),),
(('localityName', 'Castle Anthrax'),),
(('organizationName', 'Python Software Foundation'),),
(('commonName', 'localhost'),)),
'subjectAltName': (('DNS', 'localhost'),),
'version': 3}

View file

@ -1,6 +1,7 @@
"""Make the custom certificate and private key files used by test_ssl """Make the custom certificate and private key files used by test_ssl
and friends.""" and friends."""
import argparse
import os import os
import pprint import pprint
import shutil import shutil
@ -8,7 +9,8 @@ import tempfile
from subprocess import * from subprocess import *
startdate = "20180829142316Z" startdate = "20180829142316Z"
enddate = "20371028142316Z" enddate_default = "20371028142316Z"
days_default = "7000"
req_template = """ req_template = """
[ default ] [ default ]
@ -79,8 +81,8 @@ req_template = """
default_startdate = {startdate} default_startdate = {startdate}
enddate = {enddate} enddate = {enddate}
default_enddate = {enddate} default_enddate = {enddate}
default_days = 7000 default_days = {days}
default_crl_days = 7000 default_crl_days = {days}
certificate = pycacert.pem certificate = pycacert.pem
private_key = pycakey.pem private_key = pycakey.pem
serial = $dir/serial serial = $dir/serial
@ -117,7 +119,7 @@ req_template = """
here = os.path.abspath(os.path.dirname(__file__)) here = os.path.abspath(os.path.dirname(__file__))
def make_cert_key(hostname, sign=False, extra_san='', def make_cert_key(cmdlineargs, hostname, sign=False, extra_san='',
ext='req_x509_extensions_full', key='rsa:3072'): ext='req_x509_extensions_full', key='rsa:3072'):
print("creating cert for " + hostname) print("creating cert for " + hostname)
tempnames = [] tempnames = []
@ -130,11 +132,12 @@ def make_cert_key(hostname, sign=False, extra_san='',
hostname=hostname, hostname=hostname,
extra_san=extra_san, extra_san=extra_san,
startdate=startdate, startdate=startdate,
enddate=enddate enddate=cmdlineargs.enddate,
days=cmdlineargs.days
) )
with open(req_file, 'w') as f: with open(req_file, 'w') as f:
f.write(req) f.write(req)
args = ['req', '-new', '-nodes', '-days', '7000', args = ['req', '-new', '-nodes', '-days', cmdlineargs.days,
'-newkey', key, '-keyout', key_file, '-newkey', key, '-keyout', key_file,
'-extensions', ext, '-extensions', ext,
'-config', req_file] '-config', req_file]
@ -175,7 +178,7 @@ TMP_CADIR = 'cadir'
def unmake_ca(): def unmake_ca():
shutil.rmtree(TMP_CADIR) shutil.rmtree(TMP_CADIR)
def make_ca(): def make_ca(cmdlineargs):
os.mkdir(TMP_CADIR) os.mkdir(TMP_CADIR)
with open(os.path.join('cadir','index.txt'),'a+') as f: with open(os.path.join('cadir','index.txt'),'a+') as f:
pass # empty file pass # empty file
@ -192,7 +195,8 @@ def make_ca():
hostname='our-ca-server', hostname='our-ca-server',
extra_san='', extra_san='',
startdate=startdate, startdate=startdate,
enddate=enddate enddate=cmdlineargs.enddate,
days=cmdlineargs.days
) )
t.write(req) t.write(req)
t.flush() t.flush()
@ -219,14 +223,22 @@ def make_ca():
shutil.copy('capath/ceff1710.0', 'capath/b1930218.0') shutil.copy('capath/ceff1710.0', 'capath/b1930218.0')
def print_cert(path): def write_cert_reference(path):
import _ssl import _ssl
pprint.pprint(_ssl._test_decode_cert(path)) refdata = pprint.pformat(_ssl._test_decode_cert(path))
print(refdata)
with open(path + '.reference', 'w') as f:
print(refdata, file=f)
if __name__ == '__main__': if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Make the custom certificate and private key files used by test_ssl and friends.')
parser.add_argument('--days', default=days_default)
parser.add_argument('--enddate', default=enddate_default)
cmdlineargs = parser.parse_args()
os.chdir(here) os.chdir(here)
cert, key = make_cert_key('localhost', ext='req_x509_extensions_simple') cert, key = make_cert_key(cmdlineargs, 'localhost', ext='req_x509_extensions_simple')
with open('ssl_cert.pem', 'w') as f: with open('ssl_cert.pem', 'w') as f:
f.write(cert) f.write(cert)
with open('ssl_key.pem', 'w') as f: with open('ssl_key.pem', 'w') as f:
@ -243,24 +255,24 @@ if __name__ == '__main__':
f.write(cert) f.write(cert)
# For certificate matching tests # For certificate matching tests
make_ca() make_ca(cmdlineargs)
cert, key = make_cert_key('fakehostname', ext='req_x509_extensions_simple') cert, key = make_cert_key(cmdlineargs, 'fakehostname', ext='req_x509_extensions_simple')
with open('keycert2.pem', 'w') as f: with open('keycert2.pem', 'w') as f:
f.write(key) f.write(key)
f.write(cert) f.write(cert)
cert, key = make_cert_key('localhost', sign=True) cert, key = make_cert_key(cmdlineargs, 'localhost', sign=True)
with open('keycert3.pem', 'w') as f: with open('keycert3.pem', 'w') as f:
f.write(key) f.write(key)
f.write(cert) f.write(cert)
cert, key = make_cert_key('fakehostname', sign=True) cert, key = make_cert_key(cmdlineargs, 'fakehostname', sign=True)
with open('keycert4.pem', 'w') as f: with open('keycert4.pem', 'w') as f:
f.write(key) f.write(key)
f.write(cert) f.write(cert)
cert, key = make_cert_key( cert, key = make_cert_key(
'localhost-ecc', sign=True, key='param:secp384r1.pem' cmdlineargs, 'localhost-ecc', sign=True, key='param:secp384r1.pem'
) )
with open('keycertecc.pem', 'w') as f: with open('keycertecc.pem', 'w') as f:
f.write(key) f.write(key)
@ -280,7 +292,7 @@ if __name__ == '__main__':
'RID.1 = 1.2.3.4.5', 'RID.1 = 1.2.3.4.5',
] ]
cert, key = make_cert_key('allsans', sign=True, extra_san='\n'.join(extra_san)) cert, key = make_cert_key(cmdlineargs, 'allsans', sign=True, extra_san='\n'.join(extra_san))
with open('allsans.pem', 'w') as f: with open('allsans.pem', 'w') as f:
f.write(key) f.write(key)
f.write(cert) f.write(cert)
@ -297,17 +309,17 @@ if __name__ == '__main__':
] ]
# IDN SANS, signed # IDN SANS, signed
cert, key = make_cert_key('idnsans', sign=True, extra_san='\n'.join(extra_san)) cert, key = make_cert_key(cmdlineargs, 'idnsans', sign=True, extra_san='\n'.join(extra_san))
with open('idnsans.pem', 'w') as f: with open('idnsans.pem', 'w') as f:
f.write(key) f.write(key)
f.write(cert) f.write(cert)
cert, key = make_cert_key('nosan', sign=True, ext='req_x509_extensions_nosan') cert, key = make_cert_key(cmdlineargs, 'nosan', sign=True, ext='req_x509_extensions_nosan')
with open('nosan.pem', 'w') as f: with open('nosan.pem', 'w') as f:
f.write(key) f.write(key)
f.write(cert) f.write(cert)
unmake_ca() unmake_ca()
print("update Lib/test/test_ssl.py and Lib/test/test_asyncio/utils.py") print("Writing out reference data for Lib/test/test_ssl.py and Lib/test/test_asyncio/utils.py")
print_cert('keycert.pem') write_cert_reference('keycert.pem')
print_cert('keycert3.pem') write_cert_reference('keycert3.pem')

View file

@ -15,6 +15,7 @@ import threading
import unittest import unittest
import weakref import weakref
import warnings import warnings
from ast import literal_eval
from unittest import mock from unittest import mock
from http.server import HTTPServer from http.server import HTTPServer
@ -56,24 +57,8 @@ ONLYCERT = data_file('certdata', 'ssl_cert.pem')
ONLYKEY = data_file('certdata', 'ssl_key.pem') ONLYKEY = data_file('certdata', 'ssl_key.pem')
SIGNED_CERTFILE = data_file('certdata', 'keycert3.pem') SIGNED_CERTFILE = data_file('certdata', 'keycert3.pem')
SIGNING_CA = data_file('certdata', 'pycacert.pem') SIGNING_CA = data_file('certdata', 'pycacert.pem')
PEERCERT = { with open(data_file('certdata', 'keycert3.pem.reference')) as file:
'OCSP': ('http://testca.pythontest.net/testca/ocsp/',), PEERCERT = literal_eval(file.read())
'caIssuers': ('http://testca.pythontest.net/testca/pycacert.cer',),
'crlDistributionPoints': ('http://testca.pythontest.net/testca/revocation.crl',),
'issuer': ((('countryName', 'XY'),),
(('organizationName', 'Python Software Foundation CA'),),
(('commonName', 'our-ca-server'),)),
'notAfter': 'Oct 28 14:23:16 2037 GMT',
'notBefore': 'Aug 29 14:23:16 2018 GMT',
'serialNumber': 'CB2D80995A69525C',
'subject': ((('countryName', 'XY'),),
(('localityName', 'Castle Anthrax'),),
(('organizationName', 'Python Software Foundation'),),
(('commonName', 'localhost'),)),
'subjectAltName': (('DNS', 'localhost'),),
'version': 3
}
def simple_server_sslcontext(): def simple_server_sslcontext():
server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)

View file

@ -3,6 +3,7 @@
import sys import sys
import unittest import unittest
import unittest.mock import unittest.mock
from ast import literal_eval
from test import support from test import support
from test.support import import_helper from test.support import import_helper
from test.support import os_helper from test.support import os_helper
@ -82,21 +83,8 @@ BYTES_CAPATH = os.fsencode(CAPATH)
CAFILE_NEURONIO = data_file("capath", "4e1295a3.0") CAFILE_NEURONIO = data_file("capath", "4e1295a3.0")
CAFILE_CACERT = data_file("capath", "5ed36f99.0") CAFILE_CACERT = data_file("capath", "5ed36f99.0")
CERTFILE_INFO = { with open(data_file('keycert.pem.reference')) as file:
'issuer': ((('countryName', 'XY'),), CERTFILE_INFO = literal_eval(file.read())
(('localityName', 'Castle Anthrax'),),
(('organizationName', 'Python Software Foundation'),),
(('commonName', 'localhost'),)),
'notAfter': 'Jan 24 04:21:36 2043 GMT',
'notBefore': 'Nov 25 04:21:36 2023 GMT',
'serialNumber': '53E14833F7546C29256DD0F034F776C5E983004C',
'subject': ((('countryName', 'XY'),),
(('localityName', 'Castle Anthrax'),),
(('organizationName', 'Python Software Foundation'),),
(('commonName', 'localhost'),)),
'subjectAltName': (('DNS', 'localhost'),),
'version': 3
}
# empty CRL # empty CRL
CRLFILE = data_file("revocation.crl") CRLFILE = data_file("revocation.crl")
@ -106,23 +94,8 @@ SIGNED_CERTFILE = data_file("keycert3.pem")
SINGED_CERTFILE_ONLY = data_file("cert3.pem") SINGED_CERTFILE_ONLY = data_file("cert3.pem")
SIGNED_CERTFILE_HOSTNAME = 'localhost' SIGNED_CERTFILE_HOSTNAME = 'localhost'
SIGNED_CERTFILE_INFO = { with open(data_file('keycert3.pem.reference')) as file:
'OCSP': ('http://testca.pythontest.net/testca/ocsp/',), SIGNED_CERTFILE_INFO = literal_eval(file.read())
'caIssuers': ('http://testca.pythontest.net/testca/pycacert.cer',),
'crlDistributionPoints': ('http://testca.pythontest.net/testca/revocation.crl',),
'issuer': ((('countryName', 'XY'),),
(('organizationName', 'Python Software Foundation CA'),),
(('commonName', 'our-ca-server'),)),
'notAfter': 'Oct 28 14:23:16 2037 GMT',
'notBefore': 'Aug 29 14:23:16 2018 GMT',
'serialNumber': 'CB2D80995A69525C',
'subject': ((('countryName', 'XY'),),
(('localityName', 'Castle Anthrax'),),
(('organizationName', 'Python Software Foundation'),),
(('commonName', 'localhost'),)),
'subjectAltName': (('DNS', 'localhost'),),
'version': 3
}
SIGNED_CERTFILE2 = data_file("keycert4.pem") SIGNED_CERTFILE2 = data_file("keycert4.pem")
SIGNED_CERTFILE2_HOSTNAME = 'fakehostname' SIGNED_CERTFILE2_HOSTNAME = 'fakehostname'

View file

@ -0,0 +1,2 @@
``make_ssl_certs``, the script that prepares certificate data for the
test suite, now allows specifying expiration dates.