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
and friends."""
import argparse
import os
import pprint
import shutil
@ -8,7 +9,8 @@ import tempfile
from subprocess import *
startdate = "20180829142316Z"
enddate = "20371028142316Z"
enddate_default = "20371028142316Z"
days_default = "7000"
req_template = """
[ default ]
@ -79,8 +81,8 @@ req_template = """
default_startdate = {startdate}
enddate = {enddate}
default_enddate = {enddate}
default_days = 7000
default_crl_days = 7000
default_days = {days}
default_crl_days = {days}
certificate = pycacert.pem
private_key = pycakey.pem
serial = $dir/serial
@ -117,7 +119,7 @@ req_template = """
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'):
print("creating cert for " + hostname)
tempnames = []
@ -130,11 +132,12 @@ def make_cert_key(hostname, sign=False, extra_san='',
hostname=hostname,
extra_san=extra_san,
startdate=startdate,
enddate=enddate
enddate=cmdlineargs.enddate,
days=cmdlineargs.days
)
with open(req_file, 'w') as f:
f.write(req)
args = ['req', '-new', '-nodes', '-days', '7000',
args = ['req', '-new', '-nodes', '-days', cmdlineargs.days,
'-newkey', key, '-keyout', key_file,
'-extensions', ext,
'-config', req_file]
@ -175,7 +178,7 @@ TMP_CADIR = 'cadir'
def unmake_ca():
shutil.rmtree(TMP_CADIR)
def make_ca():
def make_ca(cmdlineargs):
os.mkdir(TMP_CADIR)
with open(os.path.join('cadir','index.txt'),'a+') as f:
pass # empty file
@ -192,7 +195,8 @@ def make_ca():
hostname='our-ca-server',
extra_san='',
startdate=startdate,
enddate=enddate
enddate=cmdlineargs.enddate,
days=cmdlineargs.days
)
t.write(req)
t.flush()
@ -219,14 +223,22 @@ def make_ca():
shutil.copy('capath/ceff1710.0', 'capath/b1930218.0')
def print_cert(path):
def write_cert_reference(path):
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__':
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)
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:
f.write(cert)
with open('ssl_key.pem', 'w') as f:
@ -243,24 +255,24 @@ if __name__ == '__main__':
f.write(cert)
# For certificate matching tests
make_ca()
cert, key = make_cert_key('fakehostname', ext='req_x509_extensions_simple')
make_ca(cmdlineargs)
cert, key = make_cert_key(cmdlineargs, 'fakehostname', ext='req_x509_extensions_simple')
with open('keycert2.pem', 'w') as f:
f.write(key)
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:
f.write(key)
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:
f.write(key)
f.write(cert)
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:
f.write(key)
@ -280,7 +292,7 @@ if __name__ == '__main__':
'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:
f.write(key)
f.write(cert)
@ -297,17 +309,17 @@ if __name__ == '__main__':
]
# 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:
f.write(key)
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:
f.write(key)
f.write(cert)
unmake_ca()
print("update Lib/test/test_ssl.py and Lib/test/test_asyncio/utils.py")
print_cert('keycert.pem')
print_cert('keycert3.pem')
print("Writing out reference data for Lib/test/test_ssl.py and Lib/test/test_asyncio/utils.py")
write_cert_reference('keycert.pem')
write_cert_reference('keycert3.pem')

View File

@ -15,6 +15,7 @@ import threading
import unittest
import weakref
import warnings
from ast import literal_eval
from unittest import mock
from http.server import HTTPServer
@ -56,24 +57,8 @@ ONLYCERT = data_file('certdata', 'ssl_cert.pem')
ONLYKEY = data_file('certdata', 'ssl_key.pem')
SIGNED_CERTFILE = data_file('certdata', 'keycert3.pem')
SIGNING_CA = data_file('certdata', 'pycacert.pem')
PEERCERT = {
'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
}
with open(data_file('certdata', 'keycert3.pem.reference')) as file:
PEERCERT = literal_eval(file.read())
def simple_server_sslcontext():
server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)

View File

@ -3,6 +3,7 @@
import sys
import unittest
import unittest.mock
from ast import literal_eval
from test import support
from test.support import import_helper
from test.support import os_helper
@ -82,21 +83,8 @@ BYTES_CAPATH = os.fsencode(CAPATH)
CAFILE_NEURONIO = data_file("capath", "4e1295a3.0")
CAFILE_CACERT = data_file("capath", "5ed36f99.0")
CERTFILE_INFO = {
'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
}
with open(data_file('keycert.pem.reference')) as file:
CERTFILE_INFO = literal_eval(file.read())
# empty CRL
CRLFILE = data_file("revocation.crl")
@ -106,23 +94,8 @@ SIGNED_CERTFILE = data_file("keycert3.pem")
SINGED_CERTFILE_ONLY = data_file("cert3.pem")
SIGNED_CERTFILE_HOSTNAME = 'localhost'
SIGNED_CERTFILE_INFO = {
'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
}
with open(data_file('keycert3.pem.reference')) as file:
SIGNED_CERTFILE_INFO = literal_eval(file.read())
SIGNED_CERTFILE2 = data_file("keycert4.pem")
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.