mirror of
https://github.com/laurivosandi/certidude
synced 2024-12-22 16:25:17 +00:00
Migrate renewal to mutually authenticated TLS connection
This commit is contained in:
parent
1493c0f4a0
commit
b9aaec7fa6
@ -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)
|
||||||
|
126
certidude/cli.py
126
certidude/cli.py
@ -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:
|
||||||
# TODO: check signature, parse reasons, remove keys if revoked
|
revocations = crl.CertificateList.load(pem.unarmor(r.content))
|
||||||
revocations_partial = revocations_path + ".part"
|
# TODO: check signature, parse reasons, remove keys if revoked
|
||||||
with open(revocations_partial, 'wb') as f:
|
revocations_partial = revocations_path + ".part"
|
||||||
f.write(r.content)
|
with open(revocations_partial, 'wb') as f:
|
||||||
|
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,31 +358,48 @@ 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")
|
||||||
|
|
||||||
|
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 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"
|
||||||
|
|
||||||
|
# Mac OS X has keytab with lowercase hostname
|
||||||
|
cmd = "kinit -S HTTP/%s -k %s$" % (authority_name, const.HOSTNAME.lower())
|
||||||
|
click.echo("Executing: %s" % cmd)
|
||||||
|
if os.system(cmd):
|
||||||
|
# Fedora /w SSSD has keytab with uppercase hostname
|
||||||
|
cmd = "kinit -S HTTP/%s -k %s$" % (authority_name, const.HOSTNAME.upper())
|
||||||
|
if os.system(cmd):
|
||||||
|
# Failed, probably /etc/krb5.keytab contains spaghetti
|
||||||
|
raise ValueError("Failed to initialize Kerberos service ticket using machine keytab")
|
||||||
|
assert os.path.exists("/tmp/ca.ticket"), "Ticket not created!"
|
||||||
|
click.echo("Initialized Kerberos service ticket using machine keytab")
|
||||||
|
kwargs["auth"] = HTTPKerberosAuth(mutual_authentication=OPTIONAL, force_preemptive=True)
|
||||||
|
else:
|
||||||
|
click.echo("Not using machine keytab")
|
||||||
|
request_url = "https://%s/api/request/" % authority_name
|
||||||
|
|
||||||
if request_params:
|
if request_params:
|
||||||
request_url = request_url + "?" + "&".join(request_params)
|
request_url = request_url + "?" + "&".join(request_params)
|
||||||
|
submission = requests.post(request_url, **kwargs)
|
||||||
# If machine is joined to domain attempt to present machine credentials for authentication
|
|
||||||
if kerberos:
|
|
||||||
os.environ["KRB5CCNAME"]="/tmp/ca.ticket"
|
|
||||||
|
|
||||||
# Mac OS X has keytab with lowercase hostname
|
|
||||||
cmd = "kinit -S HTTP/%s -k %s$" % (authority_name, const.HOSTNAME.lower())
|
|
||||||
click.echo("Executing: %s" % cmd)
|
|
||||||
if os.system(cmd):
|
|
||||||
# Fedora /w SSSD has keytab with uppercase hostname
|
|
||||||
cmd = "kinit -S HTTP/%s -k %s$" % (authority_name, const.HOSTNAME.upper())
|
|
||||||
if os.system(cmd):
|
|
||||||
# Failed, probably /etc/krb5.keytab contains spaghetti
|
|
||||||
raise ValueError("Failed to initialize TGT using machine keytab")
|
|
||||||
assert os.path.exists("/tmp/ca.ticket"), "Ticket not created!"
|
|
||||||
click.echo("Initialized Kerberos TGT using machine keytab")
|
|
||||||
from requests_kerberos import HTTPKerberosAuth, OPTIONAL
|
|
||||||
auth = HTTPKerberosAuth(mutual_authentication=OPTIONAL, force_preemptive=True)
|
|
||||||
else:
|
|
||||||
click.echo("Not using machine keytab")
|
|
||||||
auth = None
|
|
||||||
|
|
||||||
submission = requests.post(request_url, auth=auth, data=open(request_path), headers=headers)
|
|
||||||
|
|
||||||
# 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
|
||||||
|
Loading…
Reference in New Issue
Block a user