From 1c939363c01fc678e607d36dffbec4daded72312 Mon Sep 17 00:00:00 2001 From: Kishi85 Date: Mon, 21 Jan 2019 15:35:17 +0100 Subject: [PATCH] Automatically download CA from AIA-data in certificate (fixes github.com/moepman/acertmgr/issues/12) --- acertmgr.py | 3 +++ configuration.py | 8 ++++++-- tools.py | 33 ++++++++++++++++++++++++++++++++- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/acertmgr.py b/acertmgr.py index d9f8c40..9d73a7c 100755 --- a/acertmgr.py +++ b/acertmgr.py @@ -101,6 +101,9 @@ def cert_get(settings): crt_final = settings['cert_file'] shutil.copy2(crt_file, crt_final) os.chmod(crt_final, stat.S_IREAD) + # download current ca file for the new certificate if no static ca is configured + if "static_ca" in settings and not config['static_ca']: + tools.download_issuer_ca(crt_final, settings['ca_file']) finally: os.remove(csr_file) diff --git a/configuration.py b/configuration.py index 45bc9af..c0a8ff2 100644 --- a/configuration.py +++ b/configuration.py @@ -79,10 +79,14 @@ def parse_config_entry(entry, globalconfig): # SSL CA location ca_files = [x for x in entry if 'ca_file' in x] if len(ca_files) > 0: + config['static_ca'] = True config['ca_file'] = ca_files[0] + elif 'server_ca' in globalconfig: + config['static_ca'] = True + config['ca_file'] = globalconfig['server_ca'] else: - config['ca_file'] = globalconfig.get('server_ca', - os.path.join(config['cert_dir'], "{}.ca".format(config['id']))) + config['static_ca'] = False + config['ca_file'] = os.path.join(config['cert_dir'], "{}.ca".format(config['id'])) # SSL cert location cert_files = [x for x in entry if 'cert_file' in x] diff --git a/tools.py b/tools.py index 9d08818..6984a0c 100644 --- a/tools.py +++ b/tools.py @@ -16,7 +16,12 @@ from cryptography import x509 from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import rsa -from cryptography.x509.oid import NameOID +from cryptography.x509.oid import NameOID,ExtensionOID + +try: + from urllib.request import urlopen # Python 3 +except ImportError: + from urllib2 import urlopen # Python 2 class InvalidCertificateError(Exception): @@ -89,6 +94,32 @@ def new_rsa_key(path, key_size=4096): print('Warning: Could not set file permissions on {0}!'.format(path)) +# @brief download the issuer ca for a given certificate +# @param cert_file certificate file +# @param ca_file destination for the ca file +def download_issuer_ca(cert_file, ca_file): + with open(cert_file, 'r') as f: + cert_data = f.read() + cert = x509.load_pem_x509_certificate(cert_data, default_backend()) + aia = cert.extensions.get_extension_for_oid(ExtensionOID.AUTHORITY_INFORMATION_ACCESS) + + ca_issuers = None + for data in aia.value: + if data.access_method == x509.OID_CA_ISSUERS: + ca_issuers = data.access_location.value + break + + if not ca_issuers: + raise Exception("Could not determine issuer CA for {}".format(cert_file)) + + print("Downloading CA certificate from {} to {}".format(ca_issuers, ca_file)) + cadata = urlopen(ca_issuers).read() + cacert = x509.load_der_x509_certificate(cadata, default_backend()) + pem = cacert.public_bytes(encoding=serialization.Encoding.PEM) + with open(ca_file, 'wb') as pem_out: + pem_out.write(pem) + + # @brief convert certificate to PEM format # @param cert certificate object in pyopenssl format # @return the certificate in PEM format