mirror of
https://github.com/moepman/acertmgr.git
synced 2025-01-01 05:31:51 +01:00
acertmgr: change the way the issuer CA is fetched
This changes the way the issuer CA is retrieved if no static_ca file is used. Previously we would always download the CA using the AIA Info but API v2 provides normally the full chain PEM upon certificate retrieval and does not need this step. For the APIv2 case we now use the CA provided with the certificate which required some changes to the basic handling of CA files. APIv1 has been adapted to this new handling. APIv2 has a fallback option to the way APIv1 handles it in case no CA has been provided.
This commit is contained in:
parent
316ecdba2e
commit
c054ecebe9
@ -86,7 +86,7 @@ def cert_get(settings):
|
|||||||
cr = tools.new_cert_request(settings['domainlist'], key)
|
cr = tools.new_cert_request(settings['domainlist'], key)
|
||||||
print("Reading account key...")
|
print("Reading account key...")
|
||||||
acme.register_account()
|
acme.register_account()
|
||||||
crt = acme.get_crt_from_csr(cr, settings['domainlist'], challenge_handlers)
|
crt, ca = acme.get_crt_from_csr(cr, settings['domainlist'], challenge_handlers)
|
||||||
with io.open(crt_file, "w") as crt_fd:
|
with io.open(crt_file, "w") as crt_fd:
|
||||||
crt_fd.write(tools.convert_cert_to_pem(crt))
|
crt_fd.write(tools.convert_cert_to_pem(crt))
|
||||||
|
|
||||||
@ -95,10 +95,9 @@ def cert_get(settings):
|
|||||||
crt_final = settings['cert_file']
|
crt_final = settings['cert_file']
|
||||||
shutil.copy2(crt_file, crt_final)
|
shutil.copy2(crt_file, crt_final)
|
||||||
os.chmod(crt_final, stat.S_IREAD)
|
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 settings['static_ca']:
|
if "static_ca" in settings and not settings['static_ca']:
|
||||||
tools.download_issuer_ca(crt_final, settings['ca_file'])
|
with io.open(settings['ca_file'], "w") as ca_fd:
|
||||||
|
ca_fd.write(tools.convert_cert_to_pem(ca))
|
||||||
finally:
|
finally:
|
||||||
os.remove(csr_file)
|
os.remove(csr_file)
|
||||||
os.remove(crt_file)
|
os.remove(crt_file)
|
||||||
|
@ -97,7 +97,7 @@ class ACMEAuthority(AbstractACMEAuthority):
|
|||||||
# @param csr the certificate signing request in pyopenssl format
|
# @param csr the certificate signing request in pyopenssl format
|
||||||
# @param domains list of domains in the certificate, first is CN
|
# @param domains list of domains in the certificate, first is CN
|
||||||
# @param challenge_handlers a dict containing challenge for all given domains
|
# @param challenge_handlers a dict containing challenge for all given domains
|
||||||
# @return the certificate in pyopenssl format
|
# @return the certificate and corresponding ca as a tuple
|
||||||
# @note algorithm and parts of the code are from acme-tiny
|
# @note algorithm and parts of the code are from acme-tiny
|
||||||
def get_crt_from_csr(self, csr, domains, challenge_handlers):
|
def get_crt_from_csr(self, csr, domains, challenge_handlers):
|
||||||
header = self._prepare_header()
|
header = self._prepare_header()
|
||||||
@ -194,4 +194,4 @@ class ACMEAuthority(AbstractACMEAuthority):
|
|||||||
# return signed certificate!
|
# return signed certificate!
|
||||||
print("Certificate signed!")
|
print("Certificate signed!")
|
||||||
cert = x509.load_der_x509_certificate(result, default_backend())
|
cert = x509.load_der_x509_certificate(result, default_backend())
|
||||||
return cert
|
return cert, tools.download_issuer_ca(cert)
|
||||||
|
@ -146,7 +146,7 @@ class ACMEAuthority(AbstractACMEAuthority):
|
|||||||
# @param csr the certificate signing request in pyopenssl format
|
# @param csr the certificate signing request in pyopenssl format
|
||||||
# @param domains list of domains in the certificate, first is CN
|
# @param domains list of domains in the certificate, first is CN
|
||||||
# @param challenge_handlers a dict containing challenge for all given domains
|
# @param challenge_handlers a dict containing challenge for all given domains
|
||||||
# @return the certificate
|
# @return the certificate and corresponding ca as a tuple
|
||||||
# @note algorithm and parts of the code are from acme-tiny
|
# @note algorithm and parts of the code are from acme-tiny
|
||||||
def get_crt_from_csr(self, csr, domains, challenge_handlers):
|
def get_crt_from_csr(self, csr, domains, challenge_handlers):
|
||||||
accountkey_json = json.dumps(self.account_protected['jwk'], sort_keys=True, separators=(',', ':'))
|
accountkey_json = json.dumps(self.account_protected['jwk'], sort_keys=True, separators=(',', ':'))
|
||||||
@ -239,7 +239,7 @@ class ACMEAuthority(AbstractACMEAuthority):
|
|||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
code, order, _ = self._request_url(order_url)
|
code, order, _ = self._request_url(order_url)
|
||||||
if code >= 400:
|
if code >= 400:
|
||||||
raise ValueError("Order is still pending: {0} {1}".format(code, order))
|
raise ValueError("Order is still not ready to be finalized: {0} {1}".format(code, order))
|
||||||
|
|
||||||
# get the new certificate
|
# get the new certificate
|
||||||
print("Finalizing certificate")
|
print("Finalizing certificate")
|
||||||
@ -257,6 +257,15 @@ class ACMEAuthority(AbstractACMEAuthority):
|
|||||||
# return certificate
|
# return certificate
|
||||||
code, certificate, _ = self._request_url(finalize['certificate'], raw_result=True)
|
code, certificate, _ = self._request_url(finalize['certificate'], raw_result=True)
|
||||||
if code >= 400:
|
if code >= 400:
|
||||||
raise ValueError("Error downloading certificate: {0} {1}".format(code, certificate))
|
raise ValueError("Error downloading certificate chain: {0} {1}".format(code, certificate))
|
||||||
cert = x509.load_pem_x509_certificate(certificate, default_backend())
|
|
||||||
return cert
|
cert_dict = re.match(("(?P<cert>-----BEGIN CERTIFICATE-----[^\-]+-----END CERTIFICATE-----)\n\n"
|
||||||
|
"(?P<ca>-----BEGIN CERTIFICATE-----[^\-]+-----END CERTIFICATE-----)?"),
|
||||||
|
certificate.decode('utf-8'), re.DOTALL).groupdict()
|
||||||
|
cert = x509.load_pem_x509_certificate(cert_dict['cert'].encode('utf-8'), default_backend())
|
||||||
|
if cert_dict['ca'] is None:
|
||||||
|
ca = tools.download_issuer_ca(cert)
|
||||||
|
else:
|
||||||
|
ca = x509.load_pem_x509_certificate(cert_dict['ca'].encode('utf-8'), default_backend())
|
||||||
|
|
||||||
|
return cert, ca
|
||||||
|
@ -103,14 +103,10 @@ def new_rsa_key(path, key_size=4096):
|
|||||||
|
|
||||||
|
|
||||||
# @brief download the issuer ca for a given certificate
|
# @brief download the issuer ca for a given certificate
|
||||||
# @param cert_file certificate file
|
# @param cert certificate data
|
||||||
# @param ca_file destination for the ca file
|
# @returns ca certificate data
|
||||||
def download_issuer_ca(cert_file, ca_file):
|
def download_issuer_ca(cert):
|
||||||
with io.open(cert_file, 'r') as f:
|
|
||||||
cert_data = f.read().encode('utf-8')
|
|
||||||
cert = x509.load_pem_x509_certificate(cert_data, default_backend())
|
|
||||||
aia = cert.extensions.get_extension_for_oid(ExtensionOID.AUTHORITY_INFORMATION_ACCESS)
|
aia = cert.extensions.get_extension_for_oid(ExtensionOID.AUTHORITY_INFORMATION_ACCESS)
|
||||||
|
|
||||||
ca_issuers = None
|
ca_issuers = None
|
||||||
for data in aia.value:
|
for data in aia.value:
|
||||||
if data.access_method == x509.OID_CA_ISSUERS:
|
if data.access_method == x509.OID_CA_ISSUERS:
|
||||||
@ -118,14 +114,11 @@ def download_issuer_ca(cert_file, ca_file):
|
|||||||
break
|
break
|
||||||
|
|
||||||
if not ca_issuers:
|
if not ca_issuers:
|
||||||
raise Exception("Could not determine issuer CA for {}".format(cert_file))
|
raise Exception("Could not determine issuer CA for given certificate: {}".format(cert))
|
||||||
|
|
||||||
print("Downloading CA certificate from {} to {}".format(ca_issuers, ca_file))
|
print("Downloading CA certificate from {}".format(ca_issuers))
|
||||||
cadata = urlopen(ca_issuers).read()
|
cadata = urlopen(ca_issuers).read()
|
||||||
cacert = x509.load_der_x509_certificate(cadata, default_backend())
|
return x509.load_der_x509_certificate(cadata, default_backend())
|
||||||
pem = cacert.public_bytes(encoding=serialization.Encoding.PEM)
|
|
||||||
with io.open(ca_file, 'wb') as pem_out:
|
|
||||||
pem_out.write(pem)
|
|
||||||
|
|
||||||
|
|
||||||
# @brief convert certificate to PEM format
|
# @brief convert certificate to PEM format
|
||||||
|
Loading…
Reference in New Issue
Block a user