Fix CRL distriution points and add authority information access extensions

This commit is contained in:
Lauri Võsandi 2016-03-29 12:29:15 +03:00
parent e721648328
commit 1475828899
4 changed files with 82 additions and 36 deletions

View File

@ -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))

View File

@ -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"))

View File

@ -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()),

View File

@ -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 }}