|
|
@ -0,0 +1,164 @@ |
|
|
|
#!/usr/bin/python |
|
|
|
import os,sys,argparse,subprocess,shutil |
|
|
|
import json,base64,binascii |
|
|
|
pki_directory = '/etc/pki' |
|
|
|
|
|
|
|
def letsencrypt_key_convert(file): |
|
|
|
with open(file) as fp: |
|
|
|
pkey=json.load(fp) |
|
|
|
def enc(data): |
|
|
|
missing_padding = 4 - len(data) % 4 |
|
|
|
if missing_padding: |
|
|
|
data += b'='* missing_padding |
|
|
|
return b'0x'+binascii.hexlify(base64.b64decode(data,b'-_')).upper() |
|
|
|
for k,v in pkey.items(): |
|
|
|
if k == 'kty': continue |
|
|
|
pkey[k] = enc(v.encode()).decode() |
|
|
|
|
|
|
|
res = "asn1=SEQUENCE:private_key\n[private_key]\nversion=INTEGER:0\n" |
|
|
|
res += "n=INTEGER:{}\n".format(pkey[u'n']) |
|
|
|
res += "e=INTEGER:{}\n".format(pkey[u'e']) |
|
|
|
res += "d=INTEGER:{}\n".format(pkey[u'd']) |
|
|
|
res += "p=INTEGER:{}\n".format(pkey[u'p']) |
|
|
|
res += "q=INTEGER:{}\n".format(pkey[u'q']) |
|
|
|
res += "dp=INTEGER:{}\n".format(pkey[u'dp']) |
|
|
|
res += "dq=INTEGER:{}\n".format(pkey[u'dq']) |
|
|
|
res += "qi=INTEGER:{}\n".format(pkey[u'qi']) |
|
|
|
return res |
|
|
|
|
|
|
|
|
|
|
|
def pki_directory_migrate(): |
|
|
|
os.mkdir(pki_directory) |
|
|
|
os.mkdir('%s/live' % (pki_directory)) |
|
|
|
os.mkdir('%s/backups' % (pki_directory)) |
|
|
|
os.mkdir('%s/accounts' % (pki_directory)) |
|
|
|
if os.path.isdir('/etc/letsencrypt/letsencrypt/accounts'): |
|
|
|
for x in os.listdir('/etc/letsencrypt/letsencrypt/accounts'): |
|
|
|
for xx in os.listdir('/etc/letsencrypt/letsencrypt/accounts/%s/directory/' % (x)): |
|
|
|
if os.path.isfile('/etc/letsencrypt/letsencrypt/accounts/%s/directory/%s/private_key.json' % (x, xx)): |
|
|
|
with open('%s/accounts/%s.tmp' % (pki_directory, x), 'w') as f: |
|
|
|
f.write(letsencrypt_key_convert('/etc/letsencrypt/letsencrypt/accounts/%s/directory/%s/private_key.json' % (x, xx))) |
|
|
|
subprocess.check_call(['openssl', 'asn1parse', '-noout', '-out', '%s/accounts/%s.der' % (pki_directory, x), '-genconf', '%s/accounts/%s.tmp' % (pki_directory, x)]) |
|
|
|
subprocess.check_call(['openssl', 'rsa', '-in', '%s/accounts/%s.der' % (pki_directory, x), '-out', '%s/accounts/%s.key' % (pki_directory, x), '-inform', 'der', '-outform', 'pem']) |
|
|
|
os.remove('%s/accounts/%s.tmp' % (pki_directory, x)) |
|
|
|
os.remove('%s/accounts/%s.der' % (pki_directory, x)) |
|
|
|
os.chmod('%s/accounts/%s.key' % (pki_directory, x), 0o400) |
|
|
|
|
|
|
|
def split_certificate(chain, cert, issuer): |
|
|
|
with open(chain, 'r') as chainfile: |
|
|
|
with open(cert, 'w') as certfile: |
|
|
|
with open(issuer, 'w') as issuerfile: |
|
|
|
first=True |
|
|
|
for l in chainfile.readlines(): |
|
|
|
if '\n' == l: |
|
|
|
first = False |
|
|
|
continue |
|
|
|
if first: |
|
|
|
certfile.write(l) |
|
|
|
else: |
|
|
|
issuerfile.write(l) |
|
|
|
|
|
|
|
if '__main__' == __name__: |
|
|
|
parser = argparse.ArgumentParser(); |
|
|
|
parser.add_argument('-d', '--domain', help='set domain', dest='domain', metavar='DOMAIN', type=str, nargs=1, required=True) |
|
|
|
parser.add_argument('-e', '--other-domains', help='set other domains', dest='other_domain', metavar='OTHER_DOMAIN', type=str, nargs=1, required=False) |
|
|
|
parser.add_argument('-c', help='create pki_directory structure', dest='create', action='store_true') |
|
|
|
parser.add_argument('-l', help='letsencrypt signature', dest='letsencrypt', action='store_true') |
|
|
|
args = parser.parse_args(); |
|
|
|
|
|
|
|
if args.create: |
|
|
|
pki_directory_migrate() |
|
|
|
sys.exit(0) |
|
|
|
if not os.path.isdir(pki_directory): |
|
|
|
print('Error: The directory structure does not exists', file=sys.stderr) |
|
|
|
sys.exit(1) |
|
|
|
|
|
|
|
# create a temp directory |
|
|
|
tmpdir = '%s/tmp' % (pki_directory) |
|
|
|
try: |
|
|
|
shutil.rmtree(tmpdir) |
|
|
|
except: |
|
|
|
pass |
|
|
|
os.mkdir(tmpdir) |
|
|
|
|
|
|
|
# create the keys |
|
|
|
subprocess.check_call(['openssl', 'genrsa', '-out', '%s/key.rsa.pem' % (tmpdir), '2048']) |
|
|
|
subprocess.check_call(['openssl', 'ecparam', '-out', '%s/key.ecc.pem' % (tmpdir), '-name', 'prime256v1', '-genkey']) |
|
|
|
|
|
|
|
# create csr |
|
|
|
o = ['DNS:%s' % (args.domain[0])] |
|
|
|
if args.other_domain: |
|
|
|
for d in args.other_domain[0].split(','): |
|
|
|
o.append('DNS:%s' % (d)) |
|
|
|
subprocess.check_call(['bash', '-c', 'openssl req -new -key "%s/key.rsa.pem" -out "%s/csr.rsa.pem" -subj "/O=confais.org/CN=%s" -reqexts cert -config <(cat /etc/ssl/openssl.cnf <(printf "[ cert ]\nsubjectAltName=%s"))' % (tmpdir, tmpdir, args.domain[0], ','.join(o))]) |
|
|
|
subprocess.check_call(['bash', '-c', 'openssl req -new -key "%s/key.ecc.pem" -out "%s/csr.ecc.pem" -subj "/O=confais.org/CN=%s" -reqexts cert -config <(cat /etc/ssl/openssl.cnf <(printf "[ cert ]\nsubjectAltName=%s"))' % (tmpdir, tmpdir, args.domain[0], ','.join(o))]) |
|
|
|
|
|
|
|
# sign the certificate |
|
|
|
if args.letsencrypt: |
|
|
|
with open('%s/chain.rsa.pem' % (tmpdir), 'w') as chainfile: |
|
|
|
subprocess.Popen(['acme-tiny', '--account-key', '%s/accounts/acme-v01.api.letsencrypt.org.key' % (pki_directory), '--csr', '%s/csr.rsa.pem' % (tmpdir), '--acme-dir', '/srv/http/.well-known/acme-challenge/'], stdout=chainfile) |
|
|
|
with open('%s/chain.ecc.pem' % (tmpdir), 'w') as chainfile: |
|
|
|
subprocess.Popen(['acme-tiny', '--account-key', '%s/accounts/acme-v01.api.letsencrypt.org.key' % (pki_directory), '--csr', '%s/csr.ecc.pem' % (tmpdir), '--acme-dir', '/srv/http/.well-known/acme-challenge/'], stdout=chainfile) |
|
|
|
else: |
|
|
|
# no letsencrypt signature |
|
|
|
input("Copy chain.rsa.pem to continue...") |
|
|
|
|
|
|
|
|
|
|
|
# split the chain into cert and issuer |
|
|
|
split_certificate('%s/chain.rsa.pem' % (tmpdir), '%s/cert.rsa.pem' % (tmpdir), '%s/issuer.rsa.pem' % (tmpdir)) |
|
|
|
split_certificate('%s/chain.ecc.pem' % (tmpdir), '%s/cert.ecc.pem' % (tmpdir), '%s/issuer.ecc.pem' % (tmpdir)) |
|
|
|
|
|
|
|
# certificate transparency |
|
|
|
if args.letsencrypt: |
|
|
|
subprocess.check_call(['bash', '-c', 'ct-submit ct.googleapis.com/pilot < %s/cert.rsa.pem > %s/ct.rsa.sct']) |
|
|
|
subprocess.check_call(['bash', '-c', 'ct-submit ct.googleapis.com/pilot < %s/cert.ecc.pem > %s/ct.ecc.sct']) |
|
|
|
|
|
|
|
# dh parameters |
|
|
|
subprocess.check_call(['openssl', 'dhparam', '-dsaparam', '-out', '%s/dh.pem' % (tmpdir), '2048']) |
|
|
|
|
|
|
|
# permissions |
|
|
|
os.chmod('%s/key.rsa.pem' % (tmpdir), 0o400) |
|
|
|
os.chmod('%s/key.ecc.pem' % (tmpdir), 0o400) |
|
|
|
os.chmod('%s/csr.rsa.pem' % (tmpdir), 0o444) |
|
|
|
os.chmod('%s/csr.ecc.pem' % (tmpdir), 0o444) |
|
|
|
os.chmod('%s/chain.rsa.pem' % (tmpdir), 0o444) |
|
|
|
os.chmod('%s/chain.ecc.pem' % (tmpdir), 0o444) |
|
|
|
os.chmod('%s/cert.rsa.pem' % (tmpdir), 0o444) |
|
|
|
os.chmod('%s/cert.ecc.pem' % (tmpdir), 0o444) |
|
|
|
os.chmod('%s/issuer.rsa.pem' % (tmpdir), 0o444) |
|
|
|
os.chmod('%s/issuer.ecc.pem' % (tmpdir), 0o444) |
|
|
|
if(os.path.isfile('%s/ct.rsa.sct' % (tmpdir))): |
|
|
|
os.chmod('%s/ct.rsa.sct' % (tmpdir), 0o444) |
|
|
|
os.chmod('%s/ct.ecc.sct' % (tmpdir), 0o444) |
|
|
|
os.chmod('%s/dh.pem' % (tmpdir), 0o444) |
|
|
|
|
|
|
|
# move files |
|
|
|
try: |
|
|
|
shutil.rmtree('%s/backups/%s' % (pki_directory, args.domain[0])) |
|
|
|
except: |
|
|
|
pass |
|
|
|
if os.path.isdir('%s/live/%s' % (pki_directory, args.domain[0])): |
|
|
|
shutil.move('%s/live/%s' % (pki_directory, args.domain[0]), '%s/backups/%s' % (pki_directory, args.domain[0])) |
|
|
|
shutil.move('%s/tmp/' % (pki_directory), '%s/live/%s' % (pki_directory, args.domain[0])) |
|
|
|
|
|
|
|
|
|
|
|
# display infos |
|
|
|
ret_rsa = subprocess.check_output(['ldns-dane', '-n', '-c', '%s/live/%s/cert.rsa.pem' % (pki_directory, args.domain[0]), 'create', args.domain[0], '443', '3', '1', '2' ]) |
|
|
|
ret_ecc = subprocess.check_output(['ldns-dane', '-n', '-c', '%s/live/%s/cert.ecc.pem' % (pki_directory, args.domain[0]), 'create', args.domain[0], '443', '3', '1', '2' ]) |
|
|
|
print('') |
|
|
|
print('========') |
|
|
|
|
|
|
|
print('TLSA:') |
|
|
|
print(ret_rsa.decode(), end='') |
|
|
|
print(ret_ecc.decode()) |
|
|
|
|
|
|
|
print('') |
|
|
|
|
|
|
|
ret_rsa = subprocess.check_output(['openssl', 'x509', '-in', '%s/live/%s/cert.rsa.pem' % (pki_directory, args.domain[0]), '-sha1', '-noout', '-fingerprint']) |
|
|
|
ret_ecc = subprocess.check_output(['openssl', 'x509', '-in', '%s/live/%s/cert.ecc.pem' % (pki_directory, args.domain[0]), '-sha1', '-noout', '-fingerprint']) |
|
|
|
print('SHA1:') |
|
|
|
print(ret_rsa.decode(), end='') |
|
|
|
print(ret_ecc.decode()) |
|
|
|
|
|
|
|
print('') |
|
|
|
print('Do not forget to copy files on the frontend reverse proxy!') |