diff options
author | Aaron LI <aly@aaronly.me> | 2017-11-03 19:04:47 +0800 |
---|---|---|
committer | Aaron LI <aly@aaronly.me> | 2017-11-03 19:04:47 +0800 |
commit | 62ff6000c3aa653a67f2d01dd8669d549d198282 (patch) | |
tree | 35f8babac4b270520bfc06c0ee34583ff5b1f27f | |
parent | e148cb4ec090da55cfc3f00dc1631900e48e0892 (diff) | |
download | atoolbox-62ff6000c3aa653a67f2d01dd8669d549d198282.tar.bz2 |
Import 2cca.py from https://github.com/nicolas314/2cca
-rwxr-xr-x | cli/2cca.py | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/cli/2cca.py b/cli/2cca.py new file mode 100755 index 0000000..5a062ca --- /dev/null +++ b/cli/2cca.py @@ -0,0 +1,248 @@ +#/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Credit: https://github.com/nicolas314/2cca (2017-May-12) +# + +import os +import sys + +defaults={ + 'root': { + 'days':3650, + 'ou':'RootCA', + 'extensions': { + 'basicConstraints': 'critical,CA:true,pathlen:1', + 'keyUsage': 'critical,keyCertSign,cRLSign' + } + }, + 'sub': { + 'days':3649, + 'ou':'CA', + 'extensions': { + 'basicConstraints': 'critical,CA:true,pathlen:1', + 'keyUsage': 'critical,keyCertSign,cRLSign' + } + }, + 'server': { + 'days': 3648, + 'ou':'server', + 'extensions': { + 'basicConstraints': 'critical,CA:false', + 'keyUsage': 'digitalSignature, keyEncipherment', + 'extendedKeyUsage':'serverAuth' + } + }, + 'client': { + 'days': 730, + 'ou': 'client', + 'extensions': { + 'basicConstraints': 'critical,CA:false', + 'keyUsage': 'digitalSignature', + 'extendedKeyUsage':'clientAuth' + } + }, + 'www': { + 'days': 730, + 'ou': 'server', + 'extensions': { + 'basicConstraints': 'critical,CA:false', + 'keyUsage': 'digitalSignature, keyEncipherment', + 'extendedKeyUsage': 'serverAuth, clientAuth' + } + } +} + +def run(cmd): + print cmd + os.system(cmd) + +def openssl_ecc_supported(): + supp = [] + p = os.popen('openssl ecparam -list_curves', 'r') + for line in p.readlines(): + fields = line.split(':') + if len(fields)==2: + supp.append(fields[0].strip()) + p.close() + return supp + +def get_config(args): + ec_supported=None + cmd=args[0] + cfg = {'command': cmd} + for arg in args[1:]: + fields = arg.split('=') + if len(fields)==1: + cfg[arg]=True + continue + if len(fields)!=2: + continue + if fields[0]=='alt': + if cfg.get('alt')==None: + cfg['alt']=list() + cfg['alt'].append(fields[1]) + elif fields[0]=='ecc': + if not ec_supported: + ec_supported = openssl_ecc_supported() + if not fields[1] in ec_supported: + print 'unsupported curve:', fields[1] + print 'supported curves:' + print ec_supported + raise SystemExit + cfg['ecc']=fields[1] + else: + cfg[fields[0].lower()]=fields[1] + # Consistency checks + if cmd in defaults.keys(): + if cfg.get('cn')==None: + print 'Specify a common name with cn=NAME' + raise SystemExit + cfg['days']=defaults[cmd]['days'] + cfg['ou']=defaults[cmd]['ou'] + if cmd in ['sub', 'server', 'client', 'www', 'crl', 'revoke']: + if cfg.get('ca')==None: + print 'Specify a CA to use for this operation with ca=NAME' + raise SystemExit + cfg['ext']=''' + [req] + distinguished_name=subject + x509_extensions=v3 + prompt=no + [subject] + CN=%(cn)s +''' % cfg + for elem in ['c', 'o', 'ou', 'st', 'l']: + if cfg.get(elem): + cfg['ext']+=elem.upper()+'='+cfg[elem]+'\n' + + cfg['ext']+=''' + [v3] + subjectKeyIdentifier = hash + authorityKeyIdentifier = keyid,issuer +''' + # Set extensions according to cert type + if cfg['command'] in ['root', 'sub', 'server', 'client', 'www']: + extensions = defaults[cfg['command']]['extensions'] + for ext in extensions.keys(): + cfg['ext']+='%s=%s\n' % (ext, extensions[ext]) + + # Factorize alt into SAN + if cfg.get('alt'): + cfg['ext']+=''' +subjectAltName=@alt_names +[alt_names] +''' + for i in range(len(cfg['alt'])): + cfg['ext']+='DNS.%d = %s\n' % (i+1, cfg['alt'][i]) + + f=open(cfg['cn']+'.cnf', 'w') + for line in (cfg['ext']).split('\n'): + f.write(line.strip()+'\n') + f.close() + return cfg + +def generate_serial(): + f=open('/dev/urandom', 'rb') + data=f.read(14) + f.close() + num='0x2cca' + for r in data: + num+='%02x' % ord(r) + return num + +def genkey(cfg): + # Generate key pair + keycmd='' + if cfg.get('ecc'): + keycmd='openssl ecparam -genkey -name %(ecc)s -out "%(cn)s.key"' % cfg + elif cfg.get('rsa'): + keycmd='openssl genrsa -out "%(cn)s.key" %(rsa)s' % cfg + else: + keycmd='openssl genrsa -out "%(cn)s.key" 2048' % cfg + run(keycmd) + +def gencsr(cfg): + cmd='openssl req -new -sha256 -key "%(cn)s.key" -out "%(cn)s.csr"' % cfg + cmd+=' -config "%(cn)s.cnf"' % cfg + cmd+=' -extensions v3' + run(cmd) + +def gencrt(cfg): + cmd='openssl x509 -req -sha256' + cmd+=' -CA "%(ca)s.crt" -CAkey "%(ca)s.key"' % cfg + cmd+=' -in "%(cn)s.csr" -out "%(cn)s.crt"' % cfg + cmd+=' -set_serial %s' % generate_serial() + if cfg.get('days'): + cmd+=' -days %(days)s' % cfg + cmd+=' -extfile "%(cn)s.cnf"' % cfg + cmd+=' -extensions v3' + run(cmd) + +def generate_root(cfg): + # Generate key pair + genkey(cfg) + # Generate self-signed certificate + cmd='openssl req -new -x509 -key "%(cn)s.key"' % cfg + cmd+=' -extensions v3' + cmd+=' -config "%(cn)s.cnf"' % cfg + cmd+=' -sha256' + cmd+=' -out "%(cn)s.crt"' % cfg + cmd+=' -set_serial %s' % generate_serial() + run(cmd) + #os.remove('%(cn)s.cnf' % cfg) + +def generate_identity(cfg): + # Generate key pair + genkey(cfg) + # Generate CSR + gencsr(cfg) + # Sign CSR with CA + gencrt(cfg) + # Delete temporary files + os.remove('%(cn)s.cnf' % cfg) + os.remove('%(cn)s.csr' % cfg) + +def crl_show(cfg): + print cfg + +def revoke(cfg): + print cfg + +if __name__=="__main__": + if len(sys.argv)==1: + print ''' + Available commands: + + 2cca root generate root identity + 2cca sub generate sub-CA identity + 2cca server generate openvpn server identity + 2cca client generate openvpn client identity + 2cca www generate web server identity + + with params: + CN=name mandatory + O=name mandatory for root, else inherited from CA + OU=name optional + C=country optional + L=locality optional + ST=state optional + email=address optional + alt=name1 alt=name2 ... optional alt names for www + days=value optional + ecc=curve curve name for ECC + rsa=size key size for RSA keys + + 2cca crl show crl + 2cca revoke +''' + raise SystemExit + + {'root': generate_root, + 'sub': generate_identity, + 'server': generate_identity, + 'client': generate_identity, + 'www': generate_identity, + 'crl': crl_show, + 'revoke': revoke}[sys.argv[1]](get_config(sys.argv[1:])) + |