rnhmjoj
5498e1de87
* use a template based on the Privoxy one * print a stack of the exceptions * link the documentation and issue tracker
117 lines
3.8 KiB
Python
Executable File
117 lines
3.8 KiB
Python
Executable File
'Certificate generation utilities'
|
|
|
|
__author__ = 'phoenix'
|
|
__version__ = '0.1'
|
|
|
|
import os
|
|
import time
|
|
import OpenSSL.crypto as crypto
|
|
import argparse
|
|
import sys
|
|
|
|
|
|
# Temp list for generating certs
|
|
workingList = set()
|
|
|
|
|
|
def create_CA(file):
|
|
'''
|
|
Generate the CA root certificate.
|
|
'''
|
|
key = crypto.PKey()
|
|
key.generate_key(crypto.TYPE_RSA, 2048)
|
|
ca = crypto.X509()
|
|
ca.set_serial_number(0)
|
|
# Value 2 means v3
|
|
ca.set_version(2)
|
|
subj = ca.get_subject()
|
|
subj.countryName = 'CN'
|
|
subj.organizationName = 'Privoxy'
|
|
subj.organizationalUnitName = 'pyOpenSSL'
|
|
subj.commonName = 'Privoxy Fake CA'
|
|
ca.gmtime_adj_notBefore(0)
|
|
ca.gmtime_adj_notAfter(24 * 60 * 60 * 3652)
|
|
ca.set_issuer(ca.get_subject())
|
|
ca.set_pubkey(key)
|
|
ca.add_extensions([
|
|
crypto.X509Extension(b'basicConstraints', True, b'CA:TRUE'),
|
|
crypto.X509Extension(b'nsCertType', False, b'sslCA'),
|
|
crypto.X509Extension(b'extendedKeyUsage', True,
|
|
b'serverAuth,clientAuth,emailProtection,'
|
|
b'timeStamping,msCodeInd,msCodeCom,msCTLSign'
|
|
b',msSGC,msEFS,nsSGC'),
|
|
crypto.X509Extension(b'keyUsage', False, b'keyCertSign, cRLSign'),
|
|
crypto.X509Extension(b'subjectKeyIdentifier', False, b'hash',
|
|
subject=ca)])
|
|
ca.sign(key, 'sha256')
|
|
file.write(crypto.dump_certificate(crypto.FILETYPE_PEM, ca).decode())
|
|
file.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, key).decode())
|
|
|
|
|
|
def get_cert(name, config):
|
|
'''
|
|
Return cert file path. Create it if it doesn't exist.
|
|
|
|
Reads from config:
|
|
cafile: the CA file to create dummpy cert files
|
|
certdir: the path where cert files are looked for or created
|
|
'''
|
|
certfile = os.path.join(config.certdir, name + '.crt')
|
|
if not os.path.exists(certfile):
|
|
dummy_cert(config.ca, certfile, name)
|
|
return certfile
|
|
|
|
|
|
def dummy_cert(cafile, certfile, commonname):
|
|
'''
|
|
Generates and writes a certificate to certfile
|
|
commonname: Common name for the generated certificate
|
|
Ref: https://github.com/mitmproxy/netlib/blob/master/netlib/certutils.py
|
|
'''
|
|
if certfile in workingList:
|
|
# Another thread is working on it, wait until it finish
|
|
while True:
|
|
time.sleep(0.2)
|
|
if certfile not in workingList:
|
|
break
|
|
else:
|
|
workingList.add(certfile)
|
|
with open(cafile, 'rb') as file:
|
|
content = file.read()
|
|
ca = crypto.load_certificate(crypto.FILETYPE_PEM, content)
|
|
key = crypto.load_privatekey(crypto.FILETYPE_PEM, content)
|
|
cert = crypto.X509()
|
|
# Value 2 means v3
|
|
cert.set_version(2)
|
|
cert.gmtime_adj_notBefore(0)
|
|
cert.gmtime_adj_notAfter(60 * 60 * 24 * 3652)
|
|
cert.set_issuer(ca.get_subject())
|
|
if commonname.startswith('.'):
|
|
domain = '*' + commonname
|
|
else:
|
|
domain = commonname
|
|
cert.get_subject().CN = domain
|
|
cert.set_serial_number(int(time.time()*10000))
|
|
cert.set_pubkey(ca.get_pubkey())
|
|
cert.add_extensions([
|
|
crypto.X509Extension(b'subjectAltName', False,
|
|
str.encode('DNS:'+domain))])
|
|
cert.sign(key, 'sha256')
|
|
with open(certfile, 'wb') as fp:
|
|
fp.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
|
|
fp.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, key))
|
|
workingList.remove(certfile)
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description='Generates CA Certificates.')
|
|
parser.add_argument('-f', '--file', type=argparse.FileType('w'),
|
|
default=sys.stdout,
|
|
help='CA certificate output file')
|
|
args = parser.parse_args()
|
|
create_CA(args.file)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|