mirror of
https://github.com/laurivosandi/certidude
synced 2024-12-22 16:25:17 +00:00
Fix CRL distriution points and add authority information access extensions
This commit is contained in:
parent
e721648328
commit
1475828899
@ -777,13 +777,14 @@ def certidude_setup_production(username, hostname, push_server, nginx_config, uw
|
||||
@click.option("--organization", "-o", default=None, help="Company or organization name")
|
||||
@click.option("--organizational-unit", "-ou", default=None)
|
||||
@click.option("--pkcs11", default=False, is_flag=True, help="Use PKCS#11 token instead of files")
|
||||
@click.option("--crl-distribution-url", default=None, help="CRL distribution URL")
|
||||
@click.option("--revoked-url", default=None, help="CRL distribution URL")
|
||||
@click.option("--certificate-url", default=None, help="Authority certificate URL")
|
||||
@click.option("--ocsp-responder-url", default=None, help="OCSP responder URL")
|
||||
@click.option("--push-server", default="", help="Streaming nginx push server")
|
||||
@click.option("--push-server", default="http://push.%s" % constants.DOMAIN, help="Push server, http://push.%s by default" % constants.DOMAIN)
|
||||
@click.option("--email-address", default="certidude@" + FQDN, help="E-mail address of the CA")
|
||||
@click.option("--directory", default=os.path.join("/var/lib/certidude", FQDN), help="Directory for authority files, /var/lib/certidude/ by default")
|
||||
@click.option("--outbox", default="smtp://smtp.%s" % constants.DOMAIN, help="SMTP server, smtp://smtp.%s by default" % constants.DOMAIN)
|
||||
def certidude_setup_authority(parent, country, state, locality, organization, organizational_unit, common_name, directory, certificate_lifetime, authority_lifetime, revocation_list_lifetime, pkcs11, crl_distribution_url, ocsp_responder_url, push_server, email_address, outbox):
|
||||
def certidude_setup_authority(parent, country, state, locality, organization, organizational_unit, common_name, directory, certificate_lifetime, authority_lifetime, revocation_list_lifetime, pkcs11, revoked_url, certificate_url, ocsp_responder_url, push_server, email_address, outbox):
|
||||
|
||||
# Make sure common_name is valid
|
||||
if not re.match(r"^[\.\-_a-zA-Z0-9]+$", common_name):
|
||||
@ -806,14 +807,14 @@ def certidude_setup_authority(parent, country, state, locality, organization, or
|
||||
key = crypto.PKey()
|
||||
key.generate_key(crypto.TYPE_RSA, 4096)
|
||||
|
||||
if not crl_distribution_url:
|
||||
crl_distribution_url = "http://%s/api/revoked/" % common_name
|
||||
if not revoked_url:
|
||||
revoked_url = "http://%s/api/revoked/" % common_name
|
||||
if not certificate_url:
|
||||
certificate_url = "http://%s/api/certificate/" % common_name
|
||||
|
||||
# File paths
|
||||
ca_key = os.path.join(directory, "ca_key.pem")
|
||||
ca_crt = os.path.join(directory, "ca_crt.pem")
|
||||
ca_crl = os.path.join(directory, "ca_crl.pem")
|
||||
crl_distribution_points = "URI:%s" % crl_distribution_url
|
||||
|
||||
ca = crypto.X509()
|
||||
ca.set_version(2) # This corresponds to X.509v3
|
||||
@ -846,7 +847,7 @@ def certidude_setup_authority(parent, country, state, locality, organization, or
|
||||
crypto.X509Extension(
|
||||
b"keyUsage",
|
||||
True,
|
||||
b"keyCertSign, cRLSign"),
|
||||
b"digitalSignature, keyCertSign, cRLSign"),
|
||||
crypto.X509Extension(
|
||||
b"extendedKeyUsage",
|
||||
False,
|
||||
@ -856,10 +857,6 @@ def certidude_setup_authority(parent, country, state, locality, organization, or
|
||||
False,
|
||||
b"hash",
|
||||
subject = ca),
|
||||
crypto.X509Extension(
|
||||
b"crlDistributionPoints",
|
||||
False,
|
||||
crl_distribution_points.encode("ascii")),
|
||||
crypto.X509Extension(
|
||||
b"subjectAltName",
|
||||
False,
|
||||
@ -905,18 +902,10 @@ def certidude_setup_authority(parent, country, state, locality, organization, or
|
||||
|
||||
# Create subdirectories with 770 permissions
|
||||
os.umask(0o007)
|
||||
for subdir in ("signed", "requests", "revoked"):
|
||||
for subdir in ("signed", "requests", "revoked", "expired"):
|
||||
if not os.path.exists(os.path.join(directory, subdir)):
|
||||
os.mkdir(os.path.join(directory, subdir))
|
||||
|
||||
# Create CRL and serial file with 644 permissions
|
||||
os.umask(0o133)
|
||||
with open(ca_crl, "wb") as fh:
|
||||
crl = crypto.CRL()
|
||||
fh.write(crl.export(ca, key, days=revocation_list_lifetime))
|
||||
with open(os.path.join(directory, "serial"), "w") as fh:
|
||||
fh.write("1")
|
||||
|
||||
# Set permission bits to 640
|
||||
os.umask(0o137)
|
||||
with open(certidude_conf, "w") as fh:
|
||||
@ -932,7 +921,6 @@ def certidude_setup_authority(parent, country, state, locality, organization, or
|
||||
click.echo()
|
||||
click.echo("Use following commands to inspect the newly created files:")
|
||||
click.echo()
|
||||
click.echo(" openssl crl -inform PEM -text -noout -in %s | less" % ca_crl)
|
||||
click.echo(" openssl x509 -text -noout -in %s | less" % ca_crt)
|
||||
click.echo(" openssl rsa -check -in %s" % ca_key)
|
||||
click.echo(" openssl verify -CAfile %s %s" % (ca_crt, ca_crt))
|
||||
|
@ -39,10 +39,13 @@ SIGNED_DIR = cp.get("authority", "signed dir")
|
||||
REVOKED_DIR = cp.get("authority", "revoked dir")
|
||||
OUTBOX = cp.get("authority", "outbox")
|
||||
|
||||
|
||||
CERTIFICATE_BASIC_CONSTRAINTS = "CA:FALSE"
|
||||
CERTIFICATE_KEY_USAGE_FLAGS = "digitalSignature,keyEncipherment"
|
||||
CERTIFICATE_EXTENDED_KEY_USAGE_FLAGS = "clientAuth"
|
||||
CERTIFICATE_LIFETIME = int(cp.get("signature", "certificate lifetime"))
|
||||
CERTIFICATE_AUTHORITY_URL = cp.get("signature", "certificate url")
|
||||
CERTIFICATE_CRL_URL = cp.get("signature", "revoked url")
|
||||
|
||||
REVOCATION_LIST_LIFETIME = int(cp.get("signature", "revocation list lifetime"))
|
||||
|
||||
|
@ -14,7 +14,7 @@ from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives import hashes, serialization
|
||||
from cryptography.hazmat.primitives.serialization import Encoding
|
||||
from datetime import datetime, timedelta
|
||||
from cryptography.x509.oid import NameOID, ExtendedKeyUsageOID
|
||||
from cryptography.x509.oid import NameOID, ExtendedKeyUsageOID, AuthorityInformationAccessOID
|
||||
import random
|
||||
|
||||
DN_WHITELIST = NameOID.COMMON_NAME, NameOID.GIVEN_NAME, NameOID.SURNAME, \
|
||||
@ -49,7 +49,15 @@ def raw_sign(private_key, ca_cert, request, basic_constraints, lifetime, key_usa
|
||||
b"authorityKeyIdentifier",
|
||||
False,
|
||||
b"keyid:always",
|
||||
issuer = ca_cert)
|
||||
issuer = ca_cert),
|
||||
crypto.X509Extension(
|
||||
b"authorityInfoAccess",
|
||||
False,
|
||||
("caIssuers;URI: %s" % config.CERTIFICATE_AUTHORITY_URL).encode("ascii")),
|
||||
crypto.X509Extension(
|
||||
b"crlDistributionPoints",
|
||||
False,
|
||||
("URI: %s" % config.CERTIFICATE_CRL_URL).encode("ascii"))
|
||||
])
|
||||
|
||||
|
||||
@ -101,7 +109,7 @@ def raw_sign(private_key, ca_cert, request, basic_constraints, lifetime, key_usa
|
||||
|
||||
# Generate random serial
|
||||
cert.set_serial_number(random.randint(SERIAL_MIN, SERIAL_MAX))
|
||||
cert.sign(private_key, 'sha256')
|
||||
cert.sign(private_key, 'sha512')
|
||||
return cert
|
||||
|
||||
|
||||
@ -175,6 +183,26 @@ class SignHandler(asynchat.async_chat):
|
||||
).add_extension(
|
||||
x509.SubjectKeyIdentifier.from_public_key(request.public_key()),
|
||||
critical=False
|
||||
).add_extension(
|
||||
x509.AuthorityInformationAccess([
|
||||
x509.AccessDescription(
|
||||
AuthorityInformationAccessOID.CA_ISSUERS,
|
||||
x509.UniformResourceIdentifier(
|
||||
config.CERTIFICATE_AUTHORITY_URL)
|
||||
)
|
||||
]),
|
||||
critical=False
|
||||
).add_extension(
|
||||
x509.CRLDistributionPoints([
|
||||
x509.DistributionPoint(
|
||||
full_name=[
|
||||
x509.UniformResourceIdentifier(
|
||||
config.CERTIFICATE_CRL_URL)],
|
||||
relative_name=None,
|
||||
crl_issuer=None,
|
||||
reasons=None)
|
||||
]),
|
||||
critical=False
|
||||
).add_extension(
|
||||
x509.AuthorityKeyIdentifier.from_issuer_public_key(
|
||||
self.server.certificate.public_key()),
|
||||
|
@ -1,26 +1,49 @@
|
||||
[authentication]
|
||||
# The authentiction backend specifies how the user is authenticated,
|
||||
# in case of 'pam' simplepam.authenticate is used to authenticate against
|
||||
# sshd PAM service. In case of 'kerberos' SPNEGO is used to authenticate
|
||||
# user against eg. Active Directory or Samba4.
|
||||
|
||||
backends = pam
|
||||
#backends = kerberos
|
||||
#backends = ldap
|
||||
#backends = kerberos ldap
|
||||
#backends = kerberos pam
|
||||
;backends = kerberos
|
||||
;backends = ldap
|
||||
;backends = kerberos ldap
|
||||
;backends = kerberos pam
|
||||
|
||||
[accounts]
|
||||
# The accounts backend specifies how the user's given name, surname and e-mail
|
||||
# address are looked up. In case of 'posix' basically 'getent passwd' is performed,
|
||||
# in case of 'ldap' a search is performed on LDAP server specified in /etc/ldap/ldap.conf
|
||||
# with Kerberos credential cache initialized at path specified by 'ldap gssapi credential cache'
|
||||
|
||||
backend = posix
|
||||
#backend = ldap
|
||||
;backend = ldap
|
||||
ldap gssapi credential cache = /run/certidude/krb5cc
|
||||
|
||||
[authorization]
|
||||
# The authorization backend specifies how the users are authorized.
|
||||
# In case of 'posix' simply group membership is asserted,
|
||||
# in case of 'ldap' search filter with username as placeholder is applied.
|
||||
|
||||
backend = posix
|
||||
#backend = ldap
|
||||
ldap gssapi credential cache = /run/certidude/krb5cc
|
||||
ldap computer filter = (&(objectclass=user)(objectclass=computer)(samaccountname=%s))
|
||||
ldap user filter = (&(objectclass=user)(objectclass=person)(samaccountname=%s))
|
||||
ldap admins filter = (&(memberOf=cn=Domain Admins,cn=Users,dc=example,dc=com)(samaccountname=%s))
|
||||
posix user group = users
|
||||
posix admin group = sudo
|
||||
|
||||
;backend = ldap
|
||||
ldap computer filter = (&(objectclass=user)(objectclass=computer)(samaccountname=%s))
|
||||
ldap user filter = (&(objectclass=user)(objectclass=person)(samaccountname=%s))
|
||||
ldap admin filter = (&(memberOf=cn=Domain Admins,cn=Users,dc=example,dc=com)(samaccountname=%s))
|
||||
|
||||
# Users are allowed to log in from user subnets
|
||||
user subnets = 0.0.0.0/0
|
||||
|
||||
# Authority administrators are allowed to sign and revoke certificates from these subnets
|
||||
admin subnets = 0.0.0.0/0
|
||||
|
||||
# Certificate signing requests are allowed to be submitted from these subnets
|
||||
request subnets = 0.0.0.0/0
|
||||
|
||||
# Certificates are automatically signed for these subnets
|
||||
autosign subnets = 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16
|
||||
|
||||
[logging]
|
||||
@ -39,14 +62,18 @@ database = sqlite://{{ directory }}/db.sqlite
|
||||
[signature]
|
||||
certificate lifetime = 1825
|
||||
revocation list lifetime = 1
|
||||
certificate url = {{ certificate_url }}
|
||||
revoked url = {{ revoked_url }}
|
||||
|
||||
[push]
|
||||
server =
|
||||
server = {{ push_server }}
|
||||
|
||||
[authority]
|
||||
private key path = {{ ca_key }}
|
||||
certificate path = {{ ca_crt }}
|
||||
|
||||
requests dir = {{ directory }}/requests/
|
||||
signed dir = {{ directory }}/signed/
|
||||
revoked dir = {{ directory }}/revoked/
|
||||
expired dir = {{ directory }}/expired/
|
||||
outbox = {{ outbox }}
|
||||
|
Loading…
Reference in New Issue
Block a user