# Copyright 2014-2021 Canonical Limited. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import subprocess from charmhelpers.core import hookenv def generate_selfsigned(keyfile, certfile, keysize="1024", config=None, subject=None, cn=None): """Generate selfsigned SSL key pair You must provide one of the 3 optional arguments: config, subject or cn If more than one is provided the leftmost will be used Arguments: keyfile -- (required) full path to the keyfile to be created certfile -- (required) full path to the certfile to be created keysize -- (optional) SSL key length config -- (optional) openssl configuration file subject -- (optional) dictionary with SSL subject variables cn -- (optional) cerfificate common name Required keys in subject dict: cn -- Common name (eq. FQDN) Optional keys in subject dict country -- Country Name (2 letter code) state -- State or Province Name (full name) locality -- Locality Name (eg, city) organization -- Organization Name (eg, company) organizational_unit -- Organizational Unit Name (eg, section) email -- Email Address """ cmd = [] if config: cmd = ["/usr/bin/openssl", "req", "-new", "-newkey", "rsa:{}".format(keysize), "-days", "365", "-nodes", "-x509", "-keyout", keyfile, "-out", certfile, "-config", config] elif subject: ssl_subject = "" if "country" in subject: ssl_subject = ssl_subject + "/C={}".format(subject["country"]) if "state" in subject: ssl_subject = ssl_subject + "/ST={}".format(subject["state"]) if "locality" in subject: ssl_subject = ssl_subject + "/L={}".format(subject["locality"]) if "organization" in subject: ssl_subject = ssl_subject + "/O={}".format(subject["organization"]) if "organizational_unit" in subject: ssl_subject = ssl_subject + "/OU={}".format(subject["organizational_unit"]) if "cn" in subject: ssl_subject = ssl_subject + "/CN={}".format(subject["cn"]) else: hookenv.log("When using \"subject\" argument you must " "provide \"cn\" field at very least") return False if "email" in subject: ssl_subject = ssl_subject + "/emailAddress={}".format(subject["email"]) cmd = ["/usr/bin/openssl", "req", "-new", "-newkey", "rsa:{}".format(keysize), "-days", "365", "-nodes", "-x509", "-keyout", keyfile, "-out", certfile, "-subj", ssl_subject] elif cn: cmd = ["/usr/bin/openssl", "req", "-new", "-newkey", "rsa:{}".format(keysize), "-days", "365", "-nodes", "-x509", "-keyout", keyfile, "-out", certfile, "-subj", "/CN={}".format(cn)] if not cmd: hookenv.log("No config, subject or cn provided," "unable to generate self signed SSL certificates") return False try: subprocess.check_call(cmd) return True except Exception as e: print("Execution of openssl command failed:\n{}".format(e)) return False