mirror of
				https://github.com/laurivosandi/certidude
				synced 2025-10-31 01:19:11 +00:00 
			
		
		
		
	Fix CRL distriution points and add authority information access extensions
This commit is contained in:
		| @@ -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 }} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user