You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

199 lines
9.2 KiB

#!/usr/bin/python
import os,sys,argparse,subprocess,shutil,time
import json,base64,binascii
pki_directory = '/etc/keystore'
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')
parser.add_argument('--rsa', help='generate rsa key as well as ecdsa', dest='rsa', 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
if args.rsa:
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))
if args.rsa:
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:
if args.rsa:
with open('%s/chain.rsa.pem' % (tmpdir), 'w') as chainfile:
p = 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)
p.wait()
with open('%s/chain.ecc.pem' % (tmpdir), 'w') as chainfile:
p = 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)
p.wait()
else:
# no letsencrypt signature
input("Copy chain.ecc.pem or/and chain.rsa.pem to continue...")
time.sleep(15)
# split the chain into cert and issuer
if args.rsa:
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:
# if args.rsa:
# subprocess.check_call(['bash', '-c', 'ct-submit ct.googleapis.com/pilot < %s/chain.rsa.pem > %s/ct.rsa.sct' % (tmpdir, tmpdir)])
# subprocess.check_call(['bash', '-c', 'ct-submit ct.googleapis.com/pilot < %s/chain.ecc.pem > %s/ct.ecc.sct' % (tmpdir, tmpdir)])
if args.letsencrypt:
if args.rsa:
subprocess.check_call(['bash', '-c', 'ct-submit ct.cloudflare.com/logs/nimbus2021 < %s/chain.rsa.pem > %s/ct.rsa.sct' % (tmpdir, tmpdir)])
subprocess.check_call(['bash', '-c', 'ct-submit ct.cloudflare.com/logs/nimbus2021 < %s/chain.ecc.pem > %s/ct.ecc.sct' % (tmpdir, tmpdir)])
# dh parameters
#subprocess.check_call(['openssl', 'dhparam', '-dsaparam', '-out', '%s/dh.pem' % (tmpdir), '2048'])
with open("%s/dh.pem" % (tmpdir), "w") as f:
f.write("-----BEGIN DH PARAMETERS-----\n")
f.write("MIICCAKCAgEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz\n")
f.write("+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a\n")
f.write("87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7\n")
f.write("YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi\n")
f.write("7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD\n")
f.write("ssbzSibBsu/6iGtCOGEfz9zeNVs7ZRkDW7w09N75nAI4YbRvydbmyQd62R0mkff3\n")
f.write("7lmMsPrBhtkcrv4TCYUTknC0EwyTvEN5RPT9RFLi103TZPLiHnH1S/9croKrnJ32\n")
f.write("nuhtK8UiNjoNq8Uhl5sN6todv5pC1cRITgq80Gv6U93vPBsg7j/VnXwl5B0rZp4e\n")
f.write("8W5vUsMWTfT7eTDp5OWIV7asfV9C1p9tGHdjzx1VA0AEh/VbpX4xzHpxNciG77Qx\n")
f.write("iu1qHgEtnmgyqQdgCpGBMMRtx3j5ca0AOAkpmaMzy4t6Gh25PXFAADwqTs6p+Y0K\n")
f.write("zAqCkc3OyX3Pjsm1Wn+IpGtNtahR9EGC4caKAH5eZV9q//////////8CAQI=\n")
f.write("-----END DH PARAMETERS-----\n")
# permissions
if args.rsa:
os.chmod('%s/key.rsa.pem' % (tmpdir), 0o400)
os.chmod('%s/csr.rsa.pem' % (tmpdir), 0o444)
os.chmod('%s/chain.rsa.pem' % (tmpdir), 0o444)
os.chmod('%s/cert.rsa.pem' % (tmpdir), 0o444)
os.chmod('%s/issuer.rsa.pem' % (tmpdir), 0o444)
os.chmod('%s/key.ecc.pem' % (tmpdir), 0o400)
os.chmod('%s/csr.ecc.pem' % (tmpdir), 0o444)
os.chmod('%s/chain.ecc.pem' % (tmpdir), 0o444)
os.chmod('%s/cert.ecc.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)
if(os.path.isfile('%s/ct.ecc.sct' % (tmpdir))):
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
if args.rsa:
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:')
if args.rsa:
print(ret_rsa.decode(), end='')
print(ret_ecc.decode())
print('')
if args.rsa:
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:')
if args.rsa:
print(ret_rsa.decode(), end='')
print(ret_ecc.decode())
print('')
print('Do not forget to copy files on the frontend reverse proxy!')