Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Convert Let's Encrypt SSL certificate to java keystore for UniFi controller.
#!/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()
@dl-sledding
Copy link

dl-sledding commented Feb 25, 2020

Tried the script, had this error, not sure where else to post it:

Traceback (most recent call last):

File "./unifi_controller_ssl.py", line 78, in
log = logger('unifissl')
File "./unifi_controller_ssl.py", line 67, in logger
slh = logging.handlers.SysLogHandler('/dev/log')
AttributeError: module 'logging' has no attribute 'handlers'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment