mirror of
https://github.com/laurivosandi/certidude
synced 2024-12-23 00:25:18 +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("--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))
|
||||||
|
@ -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"))
|
||||||
|
|
||||||
|
@ -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()),
|
||||||
|
@ -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 }}
|
||||||
|
Loading…
Reference in New Issue
Block a user