1
0
mirror of https://github.com/laurivosandi/certidude synced 2024-11-16 18:06:44 +00:00

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("--organization", "-o", default=None, help="Company or organization name")
@click.option("--organizational-unit", "-ou", default=None) @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("--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("--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("--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("--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) @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 # Make sure common_name is valid
if not re.match(r"^[\.\-_a-zA-Z0-9]+$", common_name): 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 = crypto.PKey()
key.generate_key(crypto.TYPE_RSA, 4096) key.generate_key(crypto.TYPE_RSA, 4096)
if not crl_distribution_url: if not revoked_url:
crl_distribution_url = "http://%s/api/revoked/" % common_name revoked_url = "http://%s/api/revoked/" % common_name
if not certificate_url:
certificate_url = "http://%s/api/certificate/" % common_name
# File paths # File paths
ca_key = os.path.join(directory, "ca_key.pem") ca_key = os.path.join(directory, "ca_key.pem")
ca_crt = os.path.join(directory, "ca_crt.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 = crypto.X509()
ca.set_version(2) # This corresponds to X.509v3 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( crypto.X509Extension(
b"keyUsage", b"keyUsage",
True, True,
b"keyCertSign, cRLSign"), b"digitalSignature, keyCertSign, cRLSign"),
crypto.X509Extension( crypto.X509Extension(
b"extendedKeyUsage", b"extendedKeyUsage",
False, False,
@ -856,10 +857,6 @@ def certidude_setup_authority(parent, country, state, locality, organization, or
False, False,
b"hash", b"hash",
subject = ca), subject = ca),
crypto.X509Extension(
b"crlDistributionPoints",
False,
crl_distribution_points.encode("ascii")),
crypto.X509Extension( crypto.X509Extension(
b"subjectAltName", b"subjectAltName",
False, False,
@ -905,18 +902,10 @@ def certidude_setup_authority(parent, country, state, locality, organization, or
# Create subdirectories with 770 permissions # Create subdirectories with 770 permissions
os.umask(0o007) 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)): if not os.path.exists(os.path.join(directory, subdir)):
os.mkdir(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 # Set permission bits to 640
os.umask(0o137) os.umask(0o137)
with open(certidude_conf, "w") as fh: 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()
click.echo("Use following commands to inspect the newly created files:") click.echo("Use following commands to inspect the newly created files:")
click.echo() 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 x509 -text -noout -in %s | less" % ca_crt)
click.echo(" openssl rsa -check -in %s" % ca_key) click.echo(" openssl rsa -check -in %s" % ca_key)
click.echo(" openssl verify -CAfile %s %s" % (ca_crt, ca_crt)) 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") REVOKED_DIR = cp.get("authority", "revoked dir")
OUTBOX = cp.get("authority", "outbox") OUTBOX = cp.get("authority", "outbox")
CERTIFICATE_BASIC_CONSTRAINTS = "CA:FALSE" CERTIFICATE_BASIC_CONSTRAINTS = "CA:FALSE"
CERTIFICATE_KEY_USAGE_FLAGS = "digitalSignature,keyEncipherment" CERTIFICATE_KEY_USAGE_FLAGS = "digitalSignature,keyEncipherment"
CERTIFICATE_EXTENDED_KEY_USAGE_FLAGS = "clientAuth" CERTIFICATE_EXTENDED_KEY_USAGE_FLAGS = "clientAuth"
CERTIFICATE_LIFETIME = int(cp.get("signature", "certificate lifetime")) 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")) 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 import hashes, serialization
from cryptography.hazmat.primitives.serialization import Encoding from cryptography.hazmat.primitives.serialization import Encoding
from datetime import datetime, timedelta from datetime import datetime, timedelta
from cryptography.x509.oid import NameOID, ExtendedKeyUsageOID from cryptography.x509.oid import NameOID, ExtendedKeyUsageOID, AuthorityInformationAccessOID
import random import random
DN_WHITELIST = NameOID.COMMON_NAME, NameOID.GIVEN_NAME, NameOID.SURNAME, \ 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", b"authorityKeyIdentifier",
False, False,
b"keyid:always", 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 # Generate random serial
cert.set_serial_number(random.randint(SERIAL_MIN, SERIAL_MAX)) cert.set_serial_number(random.randint(SERIAL_MIN, SERIAL_MAX))
cert.sign(private_key, 'sha256') cert.sign(private_key, 'sha512')
return cert return cert
@ -175,6 +183,26 @@ class SignHandler(asynchat.async_chat):
).add_extension( ).add_extension(
x509.SubjectKeyIdentifier.from_public_key(request.public_key()), x509.SubjectKeyIdentifier.from_public_key(request.public_key()),
critical=False 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( ).add_extension(
x509.AuthorityKeyIdentifier.from_issuer_public_key( x509.AuthorityKeyIdentifier.from_issuer_public_key(
self.server.certificate.public_key()), self.server.certificate.public_key()),

View File

@ -1,26 +1,49 @@
[authentication] [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 = pam
#backends = kerberos ;backends = kerberos
#backends = ldap ;backends = ldap
#backends = kerberos ldap ;backends = kerberos ldap
#backends = kerberos pam ;backends = kerberos pam
[accounts] [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 = posix
#backend = ldap ;backend = ldap
ldap gssapi credential cache = /run/certidude/krb5cc
[authorization] [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 = 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 user group = users
posix admin group = sudo 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 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 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 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 autosign subnets = 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16
[logging] [logging]
@ -39,14 +62,18 @@ database = sqlite://{{ directory }}/db.sqlite
[signature] [signature]
certificate lifetime = 1825 certificate lifetime = 1825
revocation list lifetime = 1 revocation list lifetime = 1
certificate url = {{ certificate_url }}
revoked url = {{ revoked_url }}
[push] [push]
server = server = {{ push_server }}
[authority] [authority]
private key path = {{ ca_key }} private key path = {{ ca_key }}
certificate path = {{ ca_crt }} certificate path = {{ ca_crt }}
requests dir = {{ directory }}/requests/ requests dir = {{ directory }}/requests/
signed dir = {{ directory }}/signed/ signed dir = {{ directory }}/signed/
revoked dir = {{ directory }}/revoked/ revoked dir = {{ directory }}/revoked/
expired dir = {{ directory }}/expired/
outbox = {{ outbox }} outbox = {{ outbox }}