mirror of
				https://github.com/laurivosandi/certidude
				synced 2025-10-31 01:19:11 +00:00 
			
		
		
		
	Migrate renewal to mutually authenticated TLS connection
This commit is contained in:
		| @@ -4,7 +4,7 @@ import logging | |||||||
| import json | import json | ||||||
| import os | import os | ||||||
| import hashlib | import hashlib | ||||||
| from asn1crypto import pem | from asn1crypto import pem, x509 | ||||||
| from asn1crypto.csr import CertificationRequest | from asn1crypto.csr import CertificationRequest | ||||||
| from base64 import b64decode | from base64 import b64decode | ||||||
| from certidude import config, push, errors | from certidude import config, push, errors | ||||||
| @@ -89,43 +89,29 @@ class RequestListResource(AuthorityHandler): | |||||||
|             cert_pk = cert["tbs_certificate"]["subject_public_key_info"].native |             cert_pk = cert["tbs_certificate"]["subject_public_key_info"].native | ||||||
|             csr_pk = csr["certification_request_info"]["subject_pk_info"].native |             csr_pk = csr["certification_request_info"]["subject_pk_info"].native | ||||||
|  |  | ||||||
|             if cert_pk == csr_pk: # Same public key, assume renewal |             try: | ||||||
|                 expires = cert["tbs_certificate"]["validity"]["not_after"].native.replace(tzinfo=None) |                 buf = req.get_header("X-SSL-CERT") | ||||||
|                 renewal_header = req.get_header("X-Renewal-Signature") |                 header, _, der_bytes = pem.unarmor(buf.replace("\t", "").encode("ascii")) | ||||||
|  |                 handshake_cert = x509.Certificate.load(der_bytes) | ||||||
|  |             except: | ||||||
|  |                 raise | ||||||
|  |             else: | ||||||
|  |                 # Same public key | ||||||
|  |                 if cert_pk == csr_pk: | ||||||
|  |                     # Used mutually authenticated TLS handshake, assume renewal | ||||||
|  |                     if handshake_cert.native == cert.native: | ||||||
|  |                         for subnet in config.RENEWAL_SUBNETS: | ||||||
|  |                             if req.context.get("remote_addr") in subnet: | ||||||
|  |                                 resp.set_header("Content-Type", "application/x-x509-user-cert") | ||||||
|  |                                 _, resp.body = self.authority._sign(csr, body, overwrite=True) | ||||||
|  |                                 logger.info("Renewing certificate for %s as %s is whitelisted", common_name, req.context.get("remote_addr")) | ||||||
|  |                                 return | ||||||
|  |  | ||||||
|                 if not renewal_header: |  | ||||||
|                     # No header supplied, redirect to signed API call |                     # No header supplied, redirect to signed API call | ||||||
|                     resp.status = falcon.HTTP_SEE_OTHER |                     resp.status = falcon.HTTP_SEE_OTHER | ||||||
|                     resp.location = os.path.join(os.path.dirname(req.relative_uri), "signed", common_name) |                     resp.location = os.path.join(os.path.dirname(req.relative_uri), "signed", common_name) | ||||||
|                     return |                     return | ||||||
|  |  | ||||||
|                 try: |  | ||||||
|                     renewal_signature = b64decode(renewal_header) |  | ||||||
|                 except (TypeError, ValueError): |  | ||||||
|                     logger.error("Renewal failed, bad signature supplied for %s", common_name) |  | ||||||
|                     reasons.append("Renewal failed, bad signature supplied") |  | ||||||
|                 else: |  | ||||||
|                     try: |  | ||||||
|                         asymmetric.rsa_pss_verify( |  | ||||||
|                             asymmetric.load_certificate(cert), |  | ||||||
|                             renewal_signature, buf + body, "sha512") |  | ||||||
|                     except SignatureError: |  | ||||||
|                         logger.error("Renewal failed, invalid signature supplied for %s", common_name) |  | ||||||
|                         reasons.append("Renewal failed, invalid signature supplied") |  | ||||||
|                     else: |  | ||||||
|                         # At this point renewal signature was valid but we need to perform some extra checks |  | ||||||
|                         if datetime.utcnow() > expires: |  | ||||||
|                             logger.error("Renewal failed, current certificate for %s has expired", common_name) |  | ||||||
|                             reasons.append("Renewal failed, current certificate expired") |  | ||||||
|                         elif not config.CERTIFICATE_RENEWAL_ALLOWED: |  | ||||||
|                             logger.error("Renewal requested for %s, but not allowed by authority settings", common_name) |  | ||||||
|                             reasons.append("Renewal requested, but not allowed by authority settings") |  | ||||||
|                         else: |  | ||||||
|                             resp.set_header("Content-Type", "application/x-x509-user-cert") |  | ||||||
|                             _, resp.body = self.authority._sign(csr, body, overwrite=True) |  | ||||||
|                             logger.info("Renewed certificate for %s", common_name) |  | ||||||
|                             return |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         """ |         """ | ||||||
|         Process automatic signing if the IP address is whitelisted, |         Process automatic signing if the IP address is whitelisted, | ||||||
|   | |||||||
| @@ -21,8 +21,6 @@ from xattr import getxattr, listxattr, setxattr | |||||||
|  |  | ||||||
| random = SystemRandom() | random = SystemRandom() | ||||||
|  |  | ||||||
| RE_HOSTNAME =  "^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])(@(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9]))?$" |  | ||||||
|  |  | ||||||
| # https://securityblog.redhat.com/2014/06/18/openssl-privilege-separation-analysis/ | # https://securityblog.redhat.com/2014/06/18/openssl-privilege-separation-analysis/ | ||||||
| # https://jamielinux.com/docs/openssl-certificate-authority/ | # https://jamielinux.com/docs/openssl-certificate-authority/ | ||||||
| # http://pycopia.googlecode.com/svn/trunk/net/pycopia/ssl/certs.py | # http://pycopia.googlecode.com/svn/trunk/net/pycopia/ssl/certs.py | ||||||
| @@ -84,7 +82,7 @@ def self_enroll(): | |||||||
|  |  | ||||||
|  |  | ||||||
| def get_request(common_name): | def get_request(common_name): | ||||||
|     if not re.match(RE_HOSTNAME, common_name): |     if not re.match(const.RE_HOSTNAME, common_name): | ||||||
|         raise ValueError("Invalid common name %s" % repr(common_name)) |         raise ValueError("Invalid common name %s" % repr(common_name)) | ||||||
|     path = os.path.join(config.REQUESTS_DIR, common_name + ".pem") |     path = os.path.join(config.REQUESTS_DIR, common_name + ".pem") | ||||||
|     try: |     try: | ||||||
| @@ -97,7 +95,7 @@ def get_request(common_name): | |||||||
|         raise errors.RequestDoesNotExist("Certificate signing request file %s does not exist" % path) |         raise errors.RequestDoesNotExist("Certificate signing request file %s does not exist" % path) | ||||||
|  |  | ||||||
| def get_signed(common_name): | def get_signed(common_name): | ||||||
|     if not re.match(RE_HOSTNAME, common_name): |     if not re.match(const.RE_HOSTNAME, common_name): | ||||||
|         raise ValueError("Invalid common name %s" % repr(common_name)) |         raise ValueError("Invalid common name %s" % repr(common_name)) | ||||||
|     path = os.path.join(config.SIGNED_DIR, common_name + ".pem") |     path = os.path.join(config.SIGNED_DIR, common_name + ".pem") | ||||||
|     with open(path, "rb") as fh: |     with open(path, "rb") as fh: | ||||||
| @@ -160,7 +158,7 @@ def store_request(buf, overwrite=False, address="", user=""): | |||||||
|  |  | ||||||
|     common_name = csr["certification_request_info"]["subject"].native["common_name"] |     common_name = csr["certification_request_info"]["subject"].native["common_name"] | ||||||
|  |  | ||||||
|     if not re.match(RE_HOSTNAME, common_name): |     if not re.match(const.RE_HOSTNAME, common_name): | ||||||
|         raise ValueError("Invalid common name") |         raise ValueError("Invalid common name") | ||||||
|  |  | ||||||
|     request_path = os.path.join(config.REQUESTS_DIR, common_name + ".pem") |     request_path = os.path.join(config.REQUESTS_DIR, common_name + ".pem") | ||||||
| @@ -298,7 +296,7 @@ def export_crl(pem=True): | |||||||
|  |  | ||||||
| def delete_request(common_name): | def delete_request(common_name): | ||||||
|     # Validate CN |     # Validate CN | ||||||
|     if not re.match(RE_HOSTNAME, common_name): |     if not re.match(const.RE_HOSTNAME, common_name): | ||||||
|         raise ValueError("Invalid common name") |         raise ValueError("Invalid common name") | ||||||
|  |  | ||||||
|     path, buf, csr, submitted = get_request(common_name) |     path, buf, csr, submitted = get_request(common_name) | ||||||
|   | |||||||
| @@ -5,11 +5,13 @@ import hashlib | |||||||
| import logging | import logging | ||||||
| import os | import os | ||||||
| import random | import random | ||||||
|  | import re | ||||||
| import signal | import signal | ||||||
| import string | import string | ||||||
| import subprocess | import subprocess | ||||||
| import sys | import sys | ||||||
| from asn1crypto import pem, x509 | from asn1crypto import pem, x509 | ||||||
|  | from asn1crypto.csr import CertificationRequest | ||||||
| from base64 import b64encode | from base64 import b64encode | ||||||
| from certbuilder import CertificateBuilder, pem_armor_certificate | from certbuilder import CertificateBuilder, pem_armor_certificate | ||||||
| from certidude import const | from certidude import const | ||||||
| @@ -177,17 +179,6 @@ def certidude_enroll(fork, renew, no_wait, kerberos, skip_self): | |||||||
|         with open(pid_path, "w") as fh: |         with open(pid_path, "w") as fh: | ||||||
|             fh.write("%d\n" % os.getpid()) |             fh.write("%d\n" % os.getpid()) | ||||||
|  |  | ||||||
|         try: |  | ||||||
|             scheme = "http" if clients.getboolean(authority_name, "insecure") else "https" |  | ||||||
|         except NoOptionError: |  | ||||||
|             scheme = "https" |  | ||||||
|  |  | ||||||
|         # Expand ca.example.com |  | ||||||
|         authority_url = "%s://%s/api/certificate/" % (scheme, authority_name) |  | ||||||
|         request_url = "%s://%s/api/request/" % (scheme, authority_name) |  | ||||||
|         revoked_url = "%s://%s/api/revoked/" % (scheme, authority_name) |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         try: |         try: | ||||||
|             authority_path = clients.get(authority_name, "authority path") |             authority_path = clients.get(authority_name, "authority path") | ||||||
|         except NoOptionError: |         except NoOptionError: | ||||||
| @@ -201,6 +192,7 @@ def certidude_enroll(fork, renew, no_wait, kerberos, skip_self): | |||||||
|             else: |             else: | ||||||
|                 if not os.path.exists(os.path.dirname(authority_path)): |                 if not os.path.exists(os.path.dirname(authority_path)): | ||||||
|                     os.makedirs(os.path.dirname(authority_path)) |                     os.makedirs(os.path.dirname(authority_path)) | ||||||
|  |                 authority_url = "http://%s/api/certificate/" % authority_name | ||||||
|                 click.echo("Attempting to fetch authority certificate from %s" % authority_url) |                 click.echo("Attempting to fetch authority certificate from %s" % authority_url) | ||||||
|                 try: |                 try: | ||||||
|                     r = requests.get(authority_url, |                     r = requests.get(authority_url, | ||||||
| @@ -260,15 +252,21 @@ def certidude_enroll(fork, renew, no_wait, kerberos, skip_self): | |||||||
|             revocations_path = None |             revocations_path = None | ||||||
|         else: |         else: | ||||||
|             # Fetch certificate revocation list |             # Fetch certificate revocation list | ||||||
|  |             revoked_url = "http://%s/api/revoked/" % authority_name | ||||||
|             click.echo("Fetching CRL from %s to %s" % (revoked_url, revocations_path)) |             click.echo("Fetching CRL from %s to %s" % (revoked_url, revocations_path)) | ||||||
|             r = requests.get(revoked_url, headers={'accept': 'application/x-pem-file'}) |             r = requests.get(revoked_url, headers={'accept': 'application/x-pem-file'}) | ||||||
|             assert r.status_code == 200, "Failed to fetch CRL from %s, got %s" % (revoked_url, r.text) |  | ||||||
|  |  | ||||||
|             #revocations = crl.CertificateList.load(pem.unarmor(r.content)) |             if r.status_code == 200: | ||||||
|  |                 revocations = crl.CertificateList.load(pem.unarmor(r.content)) | ||||||
|                 # TODO: check signature, parse reasons, remove keys if revoked |                 # TODO: check signature, parse reasons, remove keys if revoked | ||||||
|                 revocations_partial = revocations_path + ".part" |                 revocations_partial = revocations_path + ".part" | ||||||
|                 with open(revocations_partial, 'wb') as f: |                 with open(revocations_partial, 'wb') as f: | ||||||
|                     f.write(r.content) |                     f.write(r.content) | ||||||
|  |             elif r.status_code == 404: | ||||||
|  |                 click.echo("CRL disabled, server said 404") | ||||||
|  |             else: | ||||||
|  |                 click.echo("Failed to fetch CRL from %s, got %s" % (revoked_url, r.text)) | ||||||
|  |  | ||||||
|  |  | ||||||
|         try: |         try: | ||||||
|             common_name = clients.get(authority_name, "common name") |             common_name = clients.get(authority_name, "common name") | ||||||
| @@ -279,6 +277,13 @@ def certidude_enroll(fork, renew, no_wait, kerberos, skip_self): | |||||||
|         # If deriving common name from *current* hostname is preferred |         # If deriving common name from *current* hostname is preferred | ||||||
|         if common_name == "$HOSTNAME": |         if common_name == "$HOSTNAME": | ||||||
|             common_name = const.HOSTNAME |             common_name = const.HOSTNAME | ||||||
|  |         elif common_name == "$FQDN": | ||||||
|  |             common_name = const.FQDN | ||||||
|  |         elif "$" in common_name: | ||||||
|  |             raise ValueError("Invalid variable '%s' supplied, only $HOSTNAME and $FQDN allowed" % common_name) | ||||||
|  |         if not re.match(const.RE_HOSTNAME, common_name): | ||||||
|  |             raise ValueError("Invalid common name '%s' supplied" % common_name) | ||||||
|  |  | ||||||
|  |  | ||||||
|         ################################ |         ################################ | ||||||
|         ### Generate keypair and CSR ### |         ### Generate keypair and CSR ### | ||||||
| @@ -291,6 +296,14 @@ def certidude_enroll(fork, renew, no_wait, kerberos, skip_self): | |||||||
|             key_path = "/var/lib/certidude/%s/client_key.pem" % authority_name |             key_path = "/var/lib/certidude/%s/client_key.pem" % authority_name | ||||||
|             request_path = "/var/lib/certidude/%s/client_csr.pem" % authority_name |             request_path = "/var/lib/certidude/%s/client_csr.pem" % authority_name | ||||||
|  |  | ||||||
|  |         if os.path.exists(request_path): | ||||||
|  |             with open(request_path, "rb") as fh: | ||||||
|  |                 header, _, der_bytes = pem.unarmor(fh.read()) | ||||||
|  |                 csr = CertificationRequest.load(der_bytes) | ||||||
|  |                 if csr["certification_request_info"]["subject"].native["common_name"] != common_name: | ||||||
|  |                     click.echo("Stored request's common name differs from currently requested one, deleting old request") | ||||||
|  |                     os.remove(request_path) | ||||||
|  |  | ||||||
|         if not os.path.exists(request_path): |         if not os.path.exists(request_path): | ||||||
|             key_partial = key_path + ".part" |             key_partial = key_path + ".part" | ||||||
|             request_partial = request_path + ".part" |             request_partial = request_path + ".part" | ||||||
| @@ -312,7 +325,7 @@ def certidude_enroll(fork, renew, no_wait, kerberos, skip_self): | |||||||
|             selinux_fixup(request_partial) |             selinux_fixup(request_partial) | ||||||
|             os.rename(key_partial, key_path) |             os.rename(key_partial, key_path) | ||||||
|             os.rename(request_partial, request_path) |             os.rename(request_partial, request_path) | ||||||
|         # else: check that CSR has correct CN |  | ||||||
|  |  | ||||||
|         ############################################## |         ############################################## | ||||||
|         ### Submit CSR and save signed certificate ### |         ### Submit CSR and save signed certificate ### | ||||||
| @@ -323,14 +336,7 @@ def certidude_enroll(fork, renew, no_wait, kerberos, skip_self): | |||||||
|         except NoOptionError: |         except NoOptionError: | ||||||
|             certificate_path = "/var/lib/certidude/%s/client_cert.pem" % authority_name |             certificate_path = "/var/lib/certidude/%s/client_cert.pem" % authority_name | ||||||
|  |  | ||||||
|         headers={ |  | ||||||
|             "Content-Type": "application/pkcs10", |  | ||||||
|             "Accept": "application/x-x509-user-cert,application/x-pem-file" |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         try: |         try: | ||||||
|             # Attach renewal signature if renewal requested and cert exists |  | ||||||
|             renewal_overlap = clients.getint(authority_name, "renewal overlap") |             renewal_overlap = clients.getint(authority_name, "renewal overlap") | ||||||
|         except NoOptionError: # Renewal not specified in config |         except NoOptionError: # Renewal not specified in config | ||||||
|             renewal_overlap = None |             renewal_overlap = None | ||||||
| @@ -343,15 +349,8 @@ def certidude_enroll(fork, renew, no_wait, kerberos, skip_self): | |||||||
|                 if renewal_overlap and NOW > expires - timedelta(days=renewal_overlap): |                 if renewal_overlap and NOW > expires - timedelta(days=renewal_overlap): | ||||||
|                     click.echo("Certificate will expire %s, will attempt to renew" % expires) |                     click.echo("Certificate will expire %s, will attempt to renew" % expires) | ||||||
|                     renew = True |                     renew = True | ||||||
|                 headers["X-Renewal-Signature"] = b64encode( |  | ||||||
|                     asymmetric.rsa_pss_sign( |  | ||||||
|                         asymmetric.load_private_key(kh.read()), |  | ||||||
|                         cert_buf + rh.read(), |  | ||||||
|                         "sha384")) |  | ||||||
|         except EnvironmentError: # Certificate missing, can't renew |         except EnvironmentError: # Certificate missing, can't renew | ||||||
|             pass |             pass | ||||||
|         else: |  | ||||||
|             click.echo("Attached renewal signature %s" % headers["X-Renewal-Signature"]) |  | ||||||
|  |  | ||||||
|         if not os.path.exists(certificate_path) or renew: |         if not os.path.exists(certificate_path) or renew: | ||||||
|             # Set up URL-s |             # Set up URL-s | ||||||
| @@ -359,11 +358,27 @@ def certidude_enroll(fork, renew, no_wait, kerberos, skip_self): | |||||||
|             request_params.add("autosign=true") |             request_params.add("autosign=true") | ||||||
|             if not no_wait: |             if not no_wait: | ||||||
|                 request_params.add("wait=forever") |                 request_params.add("wait=forever") | ||||||
|             if request_params: |  | ||||||
|                 request_url = request_url + "?" + "&".join(request_params) |  | ||||||
|  |  | ||||||
|  |             kwargs = { | ||||||
|  |                 "data": open(request_path), | ||||||
|  |                 "verify": authority_path, | ||||||
|  |                 "headers": { | ||||||
|  |                     "Content-Type": "application/pkcs10", | ||||||
|  |                     "Accept": "application/x-x509-user-cert,application/x-pem-file" | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if renew: # Do mutually authenticated TLS handshake | ||||||
|  |                 request_url = "https://%s:8443/api/request/" % authority_name | ||||||
|  |                 kwargs["cert"] = certificate_path, key_path | ||||||
|  |             else: | ||||||
|                 # If machine is joined to domain attempt to present machine credentials for authentication |                 # If machine is joined to domain attempt to present machine credentials for authentication | ||||||
|                 if kerberos: |                 if kerberos: | ||||||
|  |                     try: | ||||||
|  |                         from requests_kerberos import HTTPKerberosAuth, OPTIONAL | ||||||
|  |                     except ImportError: | ||||||
|  |                         click.echo("Kerberos bindings not available, please install requests-kerberos") | ||||||
|  |                     else: | ||||||
|                         os.environ["KRB5CCNAME"]="/tmp/ca.ticket" |                         os.environ["KRB5CCNAME"]="/tmp/ca.ticket" | ||||||
|  |  | ||||||
|                         # Mac OS X has keytab with lowercase hostname |                         # Mac OS X has keytab with lowercase hostname | ||||||
| @@ -374,16 +389,17 @@ def certidude_enroll(fork, renew, no_wait, kerberos, skip_self): | |||||||
|                             cmd = "kinit -S HTTP/%s -k %s$" % (authority_name, const.HOSTNAME.upper()) |                             cmd = "kinit -S HTTP/%s -k %s$" % (authority_name, const.HOSTNAME.upper()) | ||||||
|                             if os.system(cmd): |                             if os.system(cmd): | ||||||
|                                 # Failed, probably /etc/krb5.keytab contains spaghetti |                                 # Failed, probably /etc/krb5.keytab contains spaghetti | ||||||
|                         raise ValueError("Failed to initialize TGT using machine keytab") |                                 raise ValueError("Failed to initialize Kerberos service ticket using machine keytab") | ||||||
|                         assert os.path.exists("/tmp/ca.ticket"), "Ticket not created!" |                         assert os.path.exists("/tmp/ca.ticket"), "Ticket not created!" | ||||||
|                 click.echo("Initialized Kerberos TGT using machine keytab") |                         click.echo("Initialized Kerberos service ticket using machine keytab") | ||||||
|                 from requests_kerberos import HTTPKerberosAuth, OPTIONAL |                         kwargs["auth"] = HTTPKerberosAuth(mutual_authentication=OPTIONAL, force_preemptive=True) | ||||||
|                 auth = HTTPKerberosAuth(mutual_authentication=OPTIONAL, force_preemptive=True) |  | ||||||
|                 else: |                 else: | ||||||
|                     click.echo("Not using machine keytab") |                     click.echo("Not using machine keytab") | ||||||
|                 auth = None |                 request_url = "https://%s/api/request/" % authority_name | ||||||
|  |  | ||||||
|             submission = requests.post(request_url, auth=auth, data=open(request_path), headers=headers) |             if request_params: | ||||||
|  |                 request_url = request_url + "?" + "&".join(request_params) | ||||||
|  |             submission = requests.post(request_url, **kwargs) | ||||||
|  |  | ||||||
|             # Destroy service ticket |             # Destroy service ticket | ||||||
|             if os.path.exists("/tmp/ca.ticket"): |             if os.path.exists("/tmp/ca.ticket"): | ||||||
|   | |||||||
| @@ -35,6 +35,8 @@ OCSP_SUBNETS = set([ipaddress.ip_network(j) for j in | |||||||
|     cp.get("authorization", "ocsp subnets").split(" ") if j]) |     cp.get("authorization", "ocsp subnets").split(" ") if j]) | ||||||
| CRL_SUBNETS = set([ipaddress.ip_network(j) for j in | CRL_SUBNETS = set([ipaddress.ip_network(j) for j in | ||||||
|     cp.get("authorization", "crl subnets").split(" ") if j]) |     cp.get("authorization", "crl subnets").split(" ") if j]) | ||||||
|  | RENEWAL_SUBNETS = set([ipaddress.ip_network(j) for j in | ||||||
|  |     cp.get("authorization", "renewal subnets").split(" ") if j]) | ||||||
|  |  | ||||||
| AUTHORITY_DIR = "/var/lib/certidude" | AUTHORITY_DIR = "/var/lib/certidude" | ||||||
| AUTHORITY_PRIVATE_KEY_PATH = cp.get("authority", "private key path") | AUTHORITY_PRIVATE_KEY_PATH = cp.get("authority", "private key path") | ||||||
| @@ -64,7 +66,6 @@ REQUEST_SUBMISSION_ALLOWED = cp.getboolean("authority", "request submission allo | |||||||
| AUTHORITY_CERTIFICATE_URL = cp.get("signature", "authority certificate url") | AUTHORITY_CERTIFICATE_URL = cp.get("signature", "authority certificate url") | ||||||
| AUTHORITY_CRL_URL = cp.get("signature", "revoked url") | AUTHORITY_CRL_URL = cp.get("signature", "revoked url") | ||||||
| AUTHORITY_OCSP_URL = cp.get("signature", "responder url") | AUTHORITY_OCSP_URL = cp.get("signature", "responder url") | ||||||
| CERTIFICATE_RENEWAL_ALLOWED = cp.getboolean("signature", "renewal allowed") |  | ||||||
|  |  | ||||||
| REVOCATION_LIST_LIFETIME = cp.getint("signature", "revocation list lifetime") | REVOCATION_LIST_LIFETIME = cp.getint("signature", "revocation list lifetime") | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ import sys | |||||||
|  |  | ||||||
| KEY_SIZE = 1024 if os.getenv("TRAVIS") else 4096 | KEY_SIZE = 1024 if os.getenv("TRAVIS") else 4096 | ||||||
| CURVE_NAME = "secp384r1" | CURVE_NAME = "secp384r1" | ||||||
|  | RE_HOSTNAME =  "^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])(@(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9]))?$" | ||||||
|  |  | ||||||
| RUN_DIR = "/run/certidude" | RUN_DIR = "/run/certidude" | ||||||
| CONFIG_DIR = "/etc/certidude" | CONFIG_DIR = "/etc/certidude" | ||||||
|   | |||||||
| @@ -119,14 +119,21 @@ server { | |||||||
|         nchan_channel_id $1; |         nchan_channel_id $1; | ||||||
|         nchan_subscriber eventsource; |         nchan_subscriber eventsource; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     # Long poll for CSR submission | ||||||
|  |     location ~ "^/lp/sub/(.*)" { | ||||||
|  |         nchan_channel_id $1; | ||||||
|  |         nchan_subscriber longpoll; | ||||||
|  |     } | ||||||
|     {% endif %} |     {% endif %} | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| server { | server { | ||||||
|     # Section for certificate authenticated HTTPS clients, |     # Section for certificate authenticated HTTPS clients, | ||||||
|     # for submitting information to CA eg. leases |     # for submitting information to CA eg. leases, | ||||||
|     # and for delivering scripts to clients |     # renewing certificates and | ||||||
|  |     # for delivering scripts to clients | ||||||
|  |  | ||||||
|     server_name {{ common_name }}; |     server_name {{ common_name }}; | ||||||
|     listen 8443 ssl http2; |     listen 8443 ssl http2; | ||||||
|   | |||||||
| @@ -70,6 +70,12 @@ ocsp subnets = | |||||||
| ;crl subnets = | ;crl subnets = | ||||||
| crl subnets = 0.0.0.0/0 | crl subnets = 0.0.0.0/0 | ||||||
|  |  | ||||||
|  | # If certificate renewal is attempted from whitelisted subnets, clients can | ||||||
|  | # request a certificate for the same public key with extended lifetime. | ||||||
|  | # To disable set to none | ||||||
|  | renewal subnets = | ||||||
|  | ;renewal subnets = 0.0.0.0/0 | ||||||
|  |  | ||||||
| [logging] | [logging] | ||||||
| # Disable logging | # Disable logging | ||||||
| ;backend = | ;backend = | ||||||
| @@ -107,11 +113,6 @@ revoked url = {{ revoked_url }} | |||||||
| responder url = | responder url = | ||||||
| ;responder url = {{ responder_url }} | ;responder url = {{ responder_url }} | ||||||
|  |  | ||||||
| # If certificate renewal is allowed clients can request a certificate |  | ||||||
| # for the same public key with extended lifetime |  | ||||||
| renewal allowed = false |  | ||||||
| ;renewal allowed = true |  | ||||||
|  |  | ||||||
|  |  | ||||||
| [push] | [push] | ||||||
| # This should occasionally be regenerated | # This should occasionally be regenerated | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user