17db96d56Sopenharmony_ci"""Make the custom certificate and private key files used by test_ssl
27db96d56Sopenharmony_ciand friends."""
37db96d56Sopenharmony_ci
47db96d56Sopenharmony_ciimport os
57db96d56Sopenharmony_ciimport pprint
67db96d56Sopenharmony_ciimport shutil
77db96d56Sopenharmony_ciimport tempfile
87db96d56Sopenharmony_cifrom subprocess import *
97db96d56Sopenharmony_ci
107db96d56Sopenharmony_cistartdate = "20180829142316Z"
117db96d56Sopenharmony_cienddate = "20371028142316Z"
127db96d56Sopenharmony_ci
137db96d56Sopenharmony_cireq_template = """
147db96d56Sopenharmony_ci    [ default ]
157db96d56Sopenharmony_ci    base_url               = http://testca.pythontest.net/testca
167db96d56Sopenharmony_ci
177db96d56Sopenharmony_ci    [req]
187db96d56Sopenharmony_ci    distinguished_name     = req_distinguished_name
197db96d56Sopenharmony_ci    prompt                 = no
207db96d56Sopenharmony_ci
217db96d56Sopenharmony_ci    [req_distinguished_name]
227db96d56Sopenharmony_ci    C                      = XY
237db96d56Sopenharmony_ci    L                      = Castle Anthrax
247db96d56Sopenharmony_ci    O                      = Python Software Foundation
257db96d56Sopenharmony_ci    CN                     = {hostname}
267db96d56Sopenharmony_ci
277db96d56Sopenharmony_ci    [req_x509_extensions_nosan]
287db96d56Sopenharmony_ci
297db96d56Sopenharmony_ci    [req_x509_extensions_simple]
307db96d56Sopenharmony_ci    subjectAltName         = @san
317db96d56Sopenharmony_ci
327db96d56Sopenharmony_ci    [req_x509_extensions_full]
337db96d56Sopenharmony_ci    subjectAltName         = @san
347db96d56Sopenharmony_ci    keyUsage               = critical,keyEncipherment,digitalSignature
357db96d56Sopenharmony_ci    extendedKeyUsage       = serverAuth,clientAuth
367db96d56Sopenharmony_ci    basicConstraints       = critical,CA:false
377db96d56Sopenharmony_ci    subjectKeyIdentifier   = hash
387db96d56Sopenharmony_ci    authorityKeyIdentifier = keyid:always,issuer:always
397db96d56Sopenharmony_ci    authorityInfoAccess    = @issuer_ocsp_info
407db96d56Sopenharmony_ci    crlDistributionPoints  = @crl_info
417db96d56Sopenharmony_ci
427db96d56Sopenharmony_ci    [ issuer_ocsp_info ]
437db96d56Sopenharmony_ci    caIssuers;URI.0        = $base_url/pycacert.cer
447db96d56Sopenharmony_ci    OCSP;URI.0             = $base_url/ocsp/
457db96d56Sopenharmony_ci
467db96d56Sopenharmony_ci    [ crl_info ]
477db96d56Sopenharmony_ci    URI.0                  = $base_url/revocation.crl
487db96d56Sopenharmony_ci
497db96d56Sopenharmony_ci    [san]
507db96d56Sopenharmony_ci    DNS.1 = {hostname}
517db96d56Sopenharmony_ci    {extra_san}
527db96d56Sopenharmony_ci
537db96d56Sopenharmony_ci    [dir_sect]
547db96d56Sopenharmony_ci    C                      = XY
557db96d56Sopenharmony_ci    L                      = Castle Anthrax
567db96d56Sopenharmony_ci    O                      = Python Software Foundation
577db96d56Sopenharmony_ci    CN                     = dirname example
587db96d56Sopenharmony_ci
597db96d56Sopenharmony_ci    [princ_name]
607db96d56Sopenharmony_ci    realm = EXP:0, GeneralString:KERBEROS.REALM
617db96d56Sopenharmony_ci    principal_name = EXP:1, SEQUENCE:principal_seq
627db96d56Sopenharmony_ci
637db96d56Sopenharmony_ci    [principal_seq]
647db96d56Sopenharmony_ci    name_type = EXP:0, INTEGER:1
657db96d56Sopenharmony_ci    name_string = EXP:1, SEQUENCE:principals
667db96d56Sopenharmony_ci
677db96d56Sopenharmony_ci    [principals]
687db96d56Sopenharmony_ci    princ1 = GeneralString:username
697db96d56Sopenharmony_ci
707db96d56Sopenharmony_ci    [ ca ]
717db96d56Sopenharmony_ci    default_ca      = CA_default
727db96d56Sopenharmony_ci
737db96d56Sopenharmony_ci    [ CA_default ]
747db96d56Sopenharmony_ci    dir = cadir
757db96d56Sopenharmony_ci    database  = $dir/index.txt
767db96d56Sopenharmony_ci    crlnumber = $dir/crl.txt
777db96d56Sopenharmony_ci    default_md = sha256
787db96d56Sopenharmony_ci    startdate = {startdate}
797db96d56Sopenharmony_ci    default_startdate = {startdate}
807db96d56Sopenharmony_ci    enddate = {enddate}
817db96d56Sopenharmony_ci    default_enddate = {enddate}
827db96d56Sopenharmony_ci    default_days = 7000
837db96d56Sopenharmony_ci    default_crl_days = 7000
847db96d56Sopenharmony_ci    certificate = pycacert.pem
857db96d56Sopenharmony_ci    private_key = pycakey.pem
867db96d56Sopenharmony_ci    serial    = $dir/serial
877db96d56Sopenharmony_ci    RANDFILE  = $dir/.rand
887db96d56Sopenharmony_ci    policy          = policy_match
897db96d56Sopenharmony_ci
907db96d56Sopenharmony_ci    [ policy_match ]
917db96d56Sopenharmony_ci    countryName             = match
927db96d56Sopenharmony_ci    stateOrProvinceName     = optional
937db96d56Sopenharmony_ci    organizationName        = match
947db96d56Sopenharmony_ci    organizationalUnitName  = optional
957db96d56Sopenharmony_ci    commonName              = supplied
967db96d56Sopenharmony_ci    emailAddress            = optional
977db96d56Sopenharmony_ci
987db96d56Sopenharmony_ci    [ policy_anything ]
997db96d56Sopenharmony_ci    countryName   = optional
1007db96d56Sopenharmony_ci    stateOrProvinceName = optional
1017db96d56Sopenharmony_ci    localityName    = optional
1027db96d56Sopenharmony_ci    organizationName  = optional
1037db96d56Sopenharmony_ci    organizationalUnitName  = optional
1047db96d56Sopenharmony_ci    commonName    = supplied
1057db96d56Sopenharmony_ci    emailAddress    = optional
1067db96d56Sopenharmony_ci
1077db96d56Sopenharmony_ci
1087db96d56Sopenharmony_ci    [ v3_ca ]
1097db96d56Sopenharmony_ci
1107db96d56Sopenharmony_ci    subjectKeyIdentifier=hash
1117db96d56Sopenharmony_ci    authorityKeyIdentifier=keyid:always,issuer
1127db96d56Sopenharmony_ci    basicConstraints = CA:true
1137db96d56Sopenharmony_ci
1147db96d56Sopenharmony_ci    """
1157db96d56Sopenharmony_ci
1167db96d56Sopenharmony_cihere = os.path.abspath(os.path.dirname(__file__))
1177db96d56Sopenharmony_ci
1187db96d56Sopenharmony_ci
1197db96d56Sopenharmony_cidef make_cert_key(hostname, sign=False, extra_san='',
1207db96d56Sopenharmony_ci                  ext='req_x509_extensions_full', key='rsa:3072'):
1217db96d56Sopenharmony_ci    print("creating cert for " + hostname)
1227db96d56Sopenharmony_ci    tempnames = []
1237db96d56Sopenharmony_ci    for i in range(3):
1247db96d56Sopenharmony_ci        with tempfile.NamedTemporaryFile(delete=False) as f:
1257db96d56Sopenharmony_ci            tempnames.append(f.name)
1267db96d56Sopenharmony_ci    req_file, cert_file, key_file = tempnames
1277db96d56Sopenharmony_ci    try:
1287db96d56Sopenharmony_ci        req = req_template.format(
1297db96d56Sopenharmony_ci            hostname=hostname,
1307db96d56Sopenharmony_ci            extra_san=extra_san,
1317db96d56Sopenharmony_ci            startdate=startdate,
1327db96d56Sopenharmony_ci            enddate=enddate
1337db96d56Sopenharmony_ci        )
1347db96d56Sopenharmony_ci        with open(req_file, 'w') as f:
1357db96d56Sopenharmony_ci            f.write(req)
1367db96d56Sopenharmony_ci        args = ['req', '-new', '-nodes', '-days', '7000',
1377db96d56Sopenharmony_ci                '-newkey', key, '-keyout', key_file,
1387db96d56Sopenharmony_ci                '-extensions', ext,
1397db96d56Sopenharmony_ci                '-config', req_file]
1407db96d56Sopenharmony_ci        if sign:
1417db96d56Sopenharmony_ci            with tempfile.NamedTemporaryFile(delete=False) as f:
1427db96d56Sopenharmony_ci                tempnames.append(f.name)
1437db96d56Sopenharmony_ci                reqfile = f.name
1447db96d56Sopenharmony_ci            args += ['-out', reqfile ]
1457db96d56Sopenharmony_ci
1467db96d56Sopenharmony_ci        else:
1477db96d56Sopenharmony_ci            args += ['-x509', '-out', cert_file ]
1487db96d56Sopenharmony_ci        check_call(['openssl'] + args)
1497db96d56Sopenharmony_ci
1507db96d56Sopenharmony_ci        if sign:
1517db96d56Sopenharmony_ci            args = [
1527db96d56Sopenharmony_ci                'ca',
1537db96d56Sopenharmony_ci                '-config', req_file,
1547db96d56Sopenharmony_ci                '-extensions', ext,
1557db96d56Sopenharmony_ci                '-out', cert_file,
1567db96d56Sopenharmony_ci                '-outdir', 'cadir',
1577db96d56Sopenharmony_ci                '-policy', 'policy_anything',
1587db96d56Sopenharmony_ci                '-batch', '-infiles', reqfile
1597db96d56Sopenharmony_ci            ]
1607db96d56Sopenharmony_ci            check_call(['openssl'] + args)
1617db96d56Sopenharmony_ci
1627db96d56Sopenharmony_ci
1637db96d56Sopenharmony_ci        with open(cert_file, 'r') as f:
1647db96d56Sopenharmony_ci            cert = f.read()
1657db96d56Sopenharmony_ci        with open(key_file, 'r') as f:
1667db96d56Sopenharmony_ci            key = f.read()
1677db96d56Sopenharmony_ci        return cert, key
1687db96d56Sopenharmony_ci    finally:
1697db96d56Sopenharmony_ci        for name in tempnames:
1707db96d56Sopenharmony_ci            os.remove(name)
1717db96d56Sopenharmony_ci
1727db96d56Sopenharmony_ciTMP_CADIR = 'cadir'
1737db96d56Sopenharmony_ci
1747db96d56Sopenharmony_cidef unmake_ca():
1757db96d56Sopenharmony_ci    shutil.rmtree(TMP_CADIR)
1767db96d56Sopenharmony_ci
1777db96d56Sopenharmony_cidef make_ca():
1787db96d56Sopenharmony_ci    os.mkdir(TMP_CADIR)
1797db96d56Sopenharmony_ci    with open(os.path.join('cadir','index.txt'),'a+') as f:
1807db96d56Sopenharmony_ci        pass # empty file
1817db96d56Sopenharmony_ci    with open(os.path.join('cadir','crl.txt'),'a+') as f:
1827db96d56Sopenharmony_ci        f.write("00")
1837db96d56Sopenharmony_ci    with open(os.path.join('cadir','index.txt.attr'),'w+') as f:
1847db96d56Sopenharmony_ci        f.write('unique_subject = no')
1857db96d56Sopenharmony_ci    # random start value for serial numbers
1867db96d56Sopenharmony_ci    with open(os.path.join('cadir','serial'), 'w') as f:
1877db96d56Sopenharmony_ci        f.write('CB2D80995A69525B\n')
1887db96d56Sopenharmony_ci
1897db96d56Sopenharmony_ci    with tempfile.NamedTemporaryFile("w") as t:
1907db96d56Sopenharmony_ci        req = req_template.format(
1917db96d56Sopenharmony_ci            hostname='our-ca-server',
1927db96d56Sopenharmony_ci            extra_san='',
1937db96d56Sopenharmony_ci            startdate=startdate,
1947db96d56Sopenharmony_ci            enddate=enddate
1957db96d56Sopenharmony_ci        )
1967db96d56Sopenharmony_ci        t.write(req)
1977db96d56Sopenharmony_ci        t.flush()
1987db96d56Sopenharmony_ci        with tempfile.NamedTemporaryFile() as f:
1997db96d56Sopenharmony_ci            args = ['req', '-config', t.name, '-new',
2007db96d56Sopenharmony_ci                    '-nodes',
2017db96d56Sopenharmony_ci                    '-newkey', 'rsa:3072',
2027db96d56Sopenharmony_ci                    '-keyout', 'pycakey.pem',
2037db96d56Sopenharmony_ci                    '-out', f.name,
2047db96d56Sopenharmony_ci                    '-subj', '/C=XY/L=Castle Anthrax/O=Python Software Foundation CA/CN=our-ca-server']
2057db96d56Sopenharmony_ci            check_call(['openssl'] + args)
2067db96d56Sopenharmony_ci            args = ['ca', '-config', t.name,
2077db96d56Sopenharmony_ci                    '-out', 'pycacert.pem', '-batch', '-outdir', TMP_CADIR,
2087db96d56Sopenharmony_ci                    '-keyfile', 'pycakey.pem',
2097db96d56Sopenharmony_ci                    '-selfsign', '-extensions', 'v3_ca', '-infiles', f.name ]
2107db96d56Sopenharmony_ci            check_call(['openssl'] + args)
2117db96d56Sopenharmony_ci            args = ['ca', '-config', t.name, '-gencrl', '-out', 'revocation.crl']
2127db96d56Sopenharmony_ci            check_call(['openssl'] + args)
2137db96d56Sopenharmony_ci
2147db96d56Sopenharmony_ci    # capath hashes depend on subject!
2157db96d56Sopenharmony_ci    check_call([
2167db96d56Sopenharmony_ci        'openssl', 'x509', '-in', 'pycacert.pem', '-out', 'capath/ceff1710.0'
2177db96d56Sopenharmony_ci    ])
2187db96d56Sopenharmony_ci    shutil.copy('capath/ceff1710.0', 'capath/b1930218.0')
2197db96d56Sopenharmony_ci
2207db96d56Sopenharmony_ci
2217db96d56Sopenharmony_cidef print_cert(path):
2227db96d56Sopenharmony_ci    import _ssl
2237db96d56Sopenharmony_ci    pprint.pprint(_ssl._test_decode_cert(path))
2247db96d56Sopenharmony_ci
2257db96d56Sopenharmony_ci
2267db96d56Sopenharmony_ciif __name__ == '__main__':
2277db96d56Sopenharmony_ci    os.chdir(here)
2287db96d56Sopenharmony_ci    cert, key = make_cert_key('localhost', ext='req_x509_extensions_simple')
2297db96d56Sopenharmony_ci    with open('ssl_cert.pem', 'w') as f:
2307db96d56Sopenharmony_ci        f.write(cert)
2317db96d56Sopenharmony_ci    with open('ssl_key.pem', 'w') as f:
2327db96d56Sopenharmony_ci        f.write(key)
2337db96d56Sopenharmony_ci    print("password protecting ssl_key.pem in ssl_key.passwd.pem")
2347db96d56Sopenharmony_ci    check_call(['openssl','pkey','-in','ssl_key.pem','-out','ssl_key.passwd.pem','-aes256','-passout','pass:somepass'])
2357db96d56Sopenharmony_ci    check_call(['openssl','pkey','-in','ssl_key.pem','-out','keycert.passwd.pem','-aes256','-passout','pass:somepass'])
2367db96d56Sopenharmony_ci
2377db96d56Sopenharmony_ci    with open('keycert.pem', 'w') as f:
2387db96d56Sopenharmony_ci        f.write(key)
2397db96d56Sopenharmony_ci        f.write(cert)
2407db96d56Sopenharmony_ci
2417db96d56Sopenharmony_ci    with open('keycert.passwd.pem', 'a+') as f:
2427db96d56Sopenharmony_ci        f.write(cert)
2437db96d56Sopenharmony_ci
2447db96d56Sopenharmony_ci    # For certificate matching tests
2457db96d56Sopenharmony_ci    make_ca()
2467db96d56Sopenharmony_ci    cert, key = make_cert_key('fakehostname', ext='req_x509_extensions_simple')
2477db96d56Sopenharmony_ci    with open('keycert2.pem', 'w') as f:
2487db96d56Sopenharmony_ci        f.write(key)
2497db96d56Sopenharmony_ci        f.write(cert)
2507db96d56Sopenharmony_ci
2517db96d56Sopenharmony_ci    cert, key = make_cert_key('localhost', sign=True)
2527db96d56Sopenharmony_ci    with open('keycert3.pem', 'w') as f:
2537db96d56Sopenharmony_ci        f.write(key)
2547db96d56Sopenharmony_ci        f.write(cert)
2557db96d56Sopenharmony_ci
2567db96d56Sopenharmony_ci    cert, key = make_cert_key('fakehostname', sign=True)
2577db96d56Sopenharmony_ci    with open('keycert4.pem', 'w') as f:
2587db96d56Sopenharmony_ci        f.write(key)
2597db96d56Sopenharmony_ci        f.write(cert)
2607db96d56Sopenharmony_ci
2617db96d56Sopenharmony_ci    cert, key = make_cert_key(
2627db96d56Sopenharmony_ci        'localhost-ecc', sign=True, key='param:secp384r1.pem'
2637db96d56Sopenharmony_ci    )
2647db96d56Sopenharmony_ci    with open('keycertecc.pem', 'w') as f:
2657db96d56Sopenharmony_ci        f.write(key)
2667db96d56Sopenharmony_ci        f.write(cert)
2677db96d56Sopenharmony_ci
2687db96d56Sopenharmony_ci    extra_san = [
2697db96d56Sopenharmony_ci        'otherName.1 = 1.2.3.4;UTF8:some other identifier',
2707db96d56Sopenharmony_ci        'otherName.2 = 1.3.6.1.5.2.2;SEQUENCE:princ_name',
2717db96d56Sopenharmony_ci        'email.1 = user@example.org',
2727db96d56Sopenharmony_ci        'DNS.2 = www.example.org',
2737db96d56Sopenharmony_ci        # GEN_X400
2747db96d56Sopenharmony_ci        'dirName.1 = dir_sect',
2757db96d56Sopenharmony_ci        # GEN_EDIPARTY
2767db96d56Sopenharmony_ci        'URI.1 = https://www.python.org/',
2777db96d56Sopenharmony_ci        'IP.1 = 127.0.0.1',
2787db96d56Sopenharmony_ci        'IP.2 = ::1',
2797db96d56Sopenharmony_ci        'RID.1 = 1.2.3.4.5',
2807db96d56Sopenharmony_ci    ]
2817db96d56Sopenharmony_ci
2827db96d56Sopenharmony_ci    cert, key = make_cert_key('allsans', sign=True, extra_san='\n'.join(extra_san))
2837db96d56Sopenharmony_ci    with open('allsans.pem', 'w') as f:
2847db96d56Sopenharmony_ci        f.write(key)
2857db96d56Sopenharmony_ci        f.write(cert)
2867db96d56Sopenharmony_ci
2877db96d56Sopenharmony_ci    extra_san = [
2887db96d56Sopenharmony_ci        # könig (king)
2897db96d56Sopenharmony_ci        'DNS.2 = xn--knig-5qa.idn.pythontest.net',
2907db96d56Sopenharmony_ci        # königsgäßchen (king's alleyway)
2917db96d56Sopenharmony_ci        'DNS.3 = xn--knigsgsschen-lcb0w.idna2003.pythontest.net',
2927db96d56Sopenharmony_ci        'DNS.4 = xn--knigsgchen-b4a3dun.idna2008.pythontest.net',
2937db96d56Sopenharmony_ci        # βόλοσ (marble)
2947db96d56Sopenharmony_ci        'DNS.5 = xn--nxasmq6b.idna2003.pythontest.net',
2957db96d56Sopenharmony_ci        'DNS.6 = xn--nxasmm1c.idna2008.pythontest.net',
2967db96d56Sopenharmony_ci    ]
2977db96d56Sopenharmony_ci
2987db96d56Sopenharmony_ci    # IDN SANS, signed
2997db96d56Sopenharmony_ci    cert, key = make_cert_key('idnsans', sign=True, extra_san='\n'.join(extra_san))
3007db96d56Sopenharmony_ci    with open('idnsans.pem', 'w') as f:
3017db96d56Sopenharmony_ci        f.write(key)
3027db96d56Sopenharmony_ci        f.write(cert)
3037db96d56Sopenharmony_ci
3047db96d56Sopenharmony_ci    cert, key = make_cert_key('nosan', sign=True, ext='req_x509_extensions_nosan')
3057db96d56Sopenharmony_ci    with open('nosan.pem', 'w') as f:
3067db96d56Sopenharmony_ci        f.write(key)
3077db96d56Sopenharmony_ci        f.write(cert)
3087db96d56Sopenharmony_ci
3097db96d56Sopenharmony_ci    unmake_ca()
3107db96d56Sopenharmony_ci    print("update Lib/test/test_ssl.py and Lib/test/test_asyncio/utils.py")
3117db96d56Sopenharmony_ci    print_cert('keycert.pem')
3127db96d56Sopenharmony_ci    print_cert('keycert3.pem')
313