Convert Let's Encrypt SSL certificate to java keystore for UniFi controller.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# -*- coding: utf-8 -*- | |
## -------------------------------=[ Info ]=--------------------------------- ## | |
# | |
## -=[ Author ]=------------------------------------------------------------- ## | |
# | |
# shr00mie | |
# 09.22.2019 | |
# v0.2 | |
# | |
## -=[ Use Case ]=----------------------------------------------------------- ## | |
# | |
# Python variant of UniFi controller SSL cert script. | |
# | |
## -=[ Requirements ]=------------------------------------------------------- ## | |
# | |
# pip3: OpenSSL & pyjks | |
# files: cert.pem, chain.pem, privkey.pem | |
# | |
## -=[ Breakdown ]=---------------------------------------------------------- ## | |
# | |
# Currently designed to take cert.pem, chain.pem, privkey.pem as provided by | |
# Let's Encrypt and convert to a java keystore for the UniFi controller. | |
# | |
## -=[ To-Do ]=-------------------------------------------------------------- ## | |
# | |
# A lot, i'm sure. | |
# | |
## -=[ Notes ]=-------------------------------------------------------------- ## | |
# | |
# 1. make a damn backup of your current keystore in case something goes tits | |
# up. keystore is located @ /var/lib/unifi/keystore. if you end up burning | |
# the whole place down, you were warned. | |
# 2. script should be run from same device as unifi controller (for now) | |
# 3. +x the script | |
# 4. if running as root, make sure python path is in root's PATH | |
# 5. required arg: --path | |
# 6. example: sudo ./script.py --path /full/path/to/certs/folder | |
# | |
## -=[ Script ]=------------------------------------------------------------- ## | |
from OpenSSL.crypto import load_certificate as LC | |
from OpenSSL.crypto import load_privatekey as LP | |
from OpenSSL.crypto import dump_certificate as DC | |
from OpenSSL.crypto import dump_privatekey as DP | |
from OpenSSL.crypto import FILETYPE_PEM as PEM | |
from OpenSSL.crypto import FILETYPE_ASN1 as ASN1 | |
from jks import KeyStore, PrivateKeyEntry | |
from OpenSSL.crypto import x509, PKey | |
from subprocess import Popen, PIPE | |
from pathlib import Path as p | |
from time import sleep | |
import argparse | |
import logging | |
def logger(name): | |
log_fmt_long='%(asctime)s | %(name)s | %(levelname)s | %(message)s' | |
log_fmt_short='%(name)s | %(levelname)s | %(message)s' | |
log_dt='%Y-%m-%d %H:%M:%S' | |
sh = logging.StreamHandler() | |
sh.formatter = logging.Formatter( | |
fmt=log_fmt_long, | |
datefmt=log_dt | |
) | |
slh = logging.handlers.SysLogHandler('/dev/log') | |
slh.formatter = logging.Formatter( | |
fmt=log_fmt_short, | |
datefmt=log_dt | |
) | |
logging.basicConfig( | |
level=logging.INFO, | |
handlers=[sh, slh] | |
) | |
return logging.getLogger(name) | |
log = logger('unifissl') | |
parser = argparse.ArgumentParser() | |
parser.add_argument('--path', type=str, required=True, help='Path to certificate files.') | |
args = parser.parse_args() | |
class UniFiSSL: | |
def __init__(self, path): | |
self.path = p(path) | |
def load_files(self): | |
return { | |
'cert': LC(PEM, (self.path / 'cert.pem').open(mode='r').read()), | |
'chain': LC(PEM, (self.path / 'chain.pem').open(mode='r').read()), | |
'key': LP(PEM, (self.path / 'privkey.pem').open(mode='r').read()) | |
} | |
def to_asn1(self, files): | |
return { | |
name: DP(ASN1, data) if isinstance(data, PKey) | |
else DC(ASN1, data) | |
for name, data in files.items() | |
} | |
def pke(self, asn1): | |
return PrivateKeyEntry.new( | |
alias='unifi', | |
certs=[asn1['cert'], asn1['chain']], | |
key=asn1['key'], | |
key_format='rsa_raw' | |
) | |
def ks(self, pke): | |
return KeyStore.new( | |
store_type='jks', | |
store_entries=[pke] | |
) | |
def save_ks(self, ks): | |
ks.save( | |
filename='/var/lib/unifi/keystore', | |
store_password='aircontrolenterprise' | |
) | |
def restart_unifi_service(self): | |
command = 'service unifi restart' | |
p = Popen(command.split(), stdin=PIPE, stderr=PIPE, universal_newlines=True) | |
while True: | |
if p.poll() is None: | |
sleep(0.5) | |
continue | |
else: | |
break | |
def run(self): | |
log.info('Loading Files.') | |
files = self.load_files() | |
log.info('Converting Files to ASN1.') | |
asn1 = self.to_asn1(files) | |
log.info('Creating PrivateKeyEntry.') | |
pke = self.pke(asn1) | |
log.info('Adding PrivateKeyEntry to KeyStore.') | |
ks = self.ks(pke) | |
log.info('Saving KeyStore to /var/lib/unifi/keystore') | |
self.save_ks(ks) | |
log.info('Restarting UniFi service.') | |
self.restart_unifi_service() | |
if __name__ == '__main__': | |
us = UniFiSSL(args.path) | |
us.run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Tried the script, had this error, not sure where else to post it: