def generate_bad_key_usage_cert(domain, base_year, quiet=False): if not quiet: write('Generating bad-key-usage cert ... ', end='') full_domain = 'bad-key-usage.{}'.format(domain) ca_private_key = load_private('ca') ca_cert = load_cert('ca') public_key = load_public('host') builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Bad TLS Limited', 'common_name': full_domain, }, public_key ) builder.issuer = ca_cert builder.subject_alt_domains = [full_domain] builder.begin_date = datetime(base_year, 1, 1, 0, 0, 0, tzinfo=timezone.utc) builder.end_date = datetime(base_year + 3, 1, 1, 0, 0, 0, tzinfo=timezone.utc) builder.key_usage = set(['crl_sign']) builder.extended_key_usage = set(['email_protection']) certificate = builder.build(ca_private_key) dump_cert('bad-key-usage', certificate) if not quiet: write('done')
def generate_certificate(self, domain, save_model): """This function takes a domain name as a parameter and then creates a certificate and key with the domain name (replacing dots by underscores), finally signing the certificate using specified CA and returns the path of key and cert files. If you are yet to generate a CA then check the top comments""" logger.info("SimpleCA: certificate creation request %s" % (domain,)) ca_private_key = asymmetric.load_private_key( self.ca_key, password=settings.CA_KEY_PASSWD) ca_certificate = asymmetric.load_certificate(self.ca_crt) end_entity_public_key, end_entity_private_key = \ asymmetric.generate_pair('rsa', bit_size=2048) builder = CertificateBuilder( { 'country_name': 'CR', 'state_or_province_name': 'San Jose', 'locality_name': 'Costa Rica', 'organization_name': save_model.name, "organizational_unit_name": save_model.institution_unit, 'common_name': domain, }, end_entity_public_key ) now = timezone.now() builder.issuer = ca_certificate builder.begin_date = now builder.end_date = now+timedelta(settings.CA_CERT_DURATION) builder.key_usage = set(['digital_signature']) end_entity_certificate = builder.build(ca_private_key) # settings.CA_CERT_DURATION server_public_key, server_private_key = \ asymmetric.generate_pair('rsa', bit_size=2048) save_model.private_key = asymmetric.dump_private_key( end_entity_private_key, None) save_model.public_key = asymmetric.dump_public_key( end_entity_public_key) save_model.public_certificate = pem_armor_certificate( end_entity_certificate) save_model.server_sign_key = asymmetric.dump_private_key( server_private_key, None) save_model.server_public_key = asymmetric.dump_public_key( server_public_key) logger.debug("SimpleCA: New certificate for %s is %r" % (domain, save_model.public_certificate)) return save_model
def generate_self_signed(cls, cn, key_usage, private_key=None): if private_key is None: private_key = cls.generate_pair() builder = CertificateBuilder({ u'common_name': six.text_type(cn), }, private_key.public_key.to_asn1_public_key()) builder.key_usage = key_usage #[u'digital_signature', u'key_encipherment'] builder.self_signed = True certificate = builder.build(private_key.to_asn1_private_key()) return Certificate(certificate=certificate), private_key
def generate_bad_key_usage_cert(domain, base_year, quiet=False): if not quiet: write('Generating bad-key-usage cert ... ', end='') full_domain = 'bad-key-usage.{}'.format(domain) ca_private_key = load_private('ca') ca_cert = load_cert('ca') public_key = load_public('host') builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Bad TLS Limited', 'common_name': full_domain, }, public_key) builder.issuer = ca_cert builder.subject_alt_domains = [full_domain] builder.begin_date = datetime(base_year, 1, 1, 0, 0, 0, tzinfo=timezone.utc) builder.end_date = datetime(base_year + 3, 1, 1, 0, 0, 0, tzinfo=timezone.utc) builder.key_usage = set(['crl_sign']) builder.extended_key_usage = set(['email_protection']) certificate = builder.build(ca_private_key) dump_cert('bad-key-usage', certificate) if not quiet: write('done')
builder.self_signed = True builder.end_entity = False root_ca_certificate = builder.build(root_ca_private_key) with open(os.path.join(fixtures_dir, "root.crt"), "wb") as f: f.write(asymmetric.dump_certificate(root_ca_certificate)) root_crl_public_key, root_crl_private_key = asymmetric.generate_pair("rsa", bit_size=2048) with open(os.path.join(fixtures_dir, "crl_issuer.key"), "wb") as f: f.write(asymmetric.dump_private_key(root_crl_private_key, "password123", target_ms=20)) builder = CertificateBuilder( { "country_name": "US", "state_or_province_name": "Massachusetts", "locality_name": "Newbury", "organization_name": "Codex Non Sufficit LC", "common_name": "CodexNS Root CA 1 CRL Issuer", }, root_crl_public_key, ) builder.key_usage = set(["crl_signing"]) builder.extended_key_usage = None builder.issuer = root_ca_certificate root_crl_certificate = builder.build(root_ca_private_key) with open(os.path.join(fixtures_dir, "crl_issuer.crt"), "wb") as f: f.write(asymmetric.dump_certificate(root_crl_certificate))
def _sign(csr, buf, profile, skip_notify=False, skip_push=False, overwrite=False, signer=None): # TODO: CRLDistributionPoints, OCSP URL, Certificate URL assert buf.startswith(b"-----BEGIN ") assert isinstance(csr, CertificationRequest) csr_pubkey = asymmetric.load_public_key( csr["certification_request_info"]["subject_pk_info"]) common_name = csr["certification_request_info"]["subject"].native[ "common_name"] cert_path = os.path.join(config.SIGNED_DIR, "%s.pem" % common_name) renew = False attachments = [ (buf, "application/x-pem-file", common_name + ".csr"), ] revoked_path = None overwritten = False # Move existing certificate if necessary if os.path.exists(cert_path): with open(cert_path, "rb") as fh: prev_buf = fh.read() header, _, der_bytes = pem.unarmor(prev_buf) prev = x509.Certificate.load(der_bytes) # TODO: assert validity here again? renew = \ asymmetric.load_public_key(prev["tbs_certificate"]["subject_public_key_info"]) == \ csr_pubkey # BUGBUG: is this enough? if overwrite: # TODO: is this the best approach? # TODO: why didn't unittest detect bugs here? prev_serial_hex = "%x" % prev.serial_number revoked_path = os.path.join(config.REVOKED_DIR, "%040x.pem" % prev.serial_number) os.rename(cert_path, revoked_path) attachments += [(prev_buf, "application/x-pem-file", "deprecated.crt" if renew else "overwritten.crt")] overwritten = True else: raise FileExistsError("Will not overwrite existing certificate") builder = CertificateBuilder( cn_to_dn(common_name, const.FQDN, o=certificate["tbs_certificate"]["subject"].native.get( "organization_name"), ou=profile.ou), csr_pubkey) builder.serial_number = generate_serial() now = datetime.utcnow() builder.begin_date = now - const.CLOCK_SKEW_TOLERANCE builder.end_date = now + timedelta(days=profile.lifetime) builder.issuer = certificate builder.ca = profile.ca builder.key_usage = profile.key_usage builder.extended_key_usage = profile.extended_key_usage builder.subject_alt_domains = [common_name] builder.ocsp_url = profile.responder_url builder.crl_url = profile.revoked_url end_entity_cert = builder.build(private_key) end_entity_cert_buf = asymmetric.dump_certificate(end_entity_cert) with open(cert_path + ".part", "wb") as fh: fh.write(end_entity_cert_buf) os.rename(cert_path + ".part", cert_path) attachments.append( (end_entity_cert_buf, "application/x-pem-file", common_name + ".crt")) cert_serial_hex = "%x" % end_entity_cert.serial_number # Create symlink link_name = os.path.join(config.SIGNED_BY_SERIAL_DIR, "%040x.pem" % end_entity_cert.serial_number) assert not os.path.exists( link_name ), "Certificate with same serial number already exists: %s" % link_name os.symlink("../%s.pem" % common_name, link_name) # Copy filesystem attributes to newly signed certificate if revoked_path: for key in listxattr(revoked_path): if not key.startswith(b"user."): continue setxattr(cert_path, key, getxattr(revoked_path, key)) # Attach signer username if signer: setxattr(cert_path, "user.signature.username", signer) if not skip_notify: # Send mail if renew: # Same keypair mailer.send("certificate-renewed.md", **locals()) else: # New keypair mailer.send("certificate-signed.md", **locals()) if not skip_push: url = config.LONG_POLL_PUBLISH % hashlib.sha256(buf).hexdigest() click.echo("Publishing certificate at %s ..." % url) requests.post(url, data=end_entity_cert_buf, headers={ "User-Agent": "Certidude API", "Content-Type": "application/x-x509-user-cert" }) if renew: # TODO: certificate-renewed event push.publish("certificate-revoked", common_name) push.publish("request-signed", common_name) else: push.publish("request-signed", common_name) return end_entity_cert, end_entity_cert_buf
def generate_client_certs(domain, base_year, quiet=False): ca_private_key = load_private('ca') ca_cert = load_cert('ca') ca2_private_key = load_private('ca2') ca2_cert = load_cert('ca2') public_key = load_public('client') crl_url = 'http://crls.{}:9991/client.crl'.format(domain) # Certificate that is valid if not quiet: write('Generating good client cert ... ', end='') builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'TLS Client Certificates Limited', 'common_name': 'Good TLS Client Certificate', }, public_key) builder.issuer = ca_cert builder.crl_url = crl_url builder.begin_date = datetime(base_year, 1, 1, 0, 0, 0, tzinfo=timezone.utc) builder.end_date = datetime(base_year + 3, 1, 1, 0, 0, 0, tzinfo=timezone.utc) certificate = builder.build(ca_private_key) dump_cert('client-good', certificate) if not quiet: write('done') # Certificate that has expired if not quiet: write('Generating expired client cert ... ', end='') builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'TLS Client Certificates Limited', 'common_name': 'Expired TLS Client Certificate', }, public_key) builder.issuer = ca_cert builder.crl_url = crl_url builder.begin_date = datetime(base_year - 1, 1, 1, 0, 0, 0, tzinfo=timezone.utc) builder.end_date = datetime(base_year, 1, 1, 0, 0, 0, tzinfo=timezone.utc) certificate = builder.build(ca_private_key) dump_cert('client-expired', certificate) if not quiet: write('done') # Certificate that is not yet valid if not quiet: write('Generating future client cert ... ', end='') builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'TLS Client Certificates Limited', 'common_name': 'Future TLS Client Certificate', }, public_key) builder.issuer = ca_cert builder.crl_url = crl_url builder.begin_date = datetime(base_year + 3, 1, 1, 0, 0, 0, tzinfo=timezone.utc) builder.end_date = datetime(base_year + 4, 1, 1, 0, 0, 0, tzinfo=timezone.utc) certificate = builder.build(ca_private_key) dump_cert('client-future', certificate) if not quiet: write('done') # Certificate issued by untrusted CA if not quiet: write('Generating untrusted client cert ... ', end='') builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'TLS Client Certificates Limited', 'common_name': 'Untrusted TLS Client Certificate', }, public_key) builder.issuer = ca2_cert builder.begin_date = datetime(base_year, 1, 1, 0, 0, 0, tzinfo=timezone.utc) builder.end_date = datetime(base_year + 3, 1, 1, 0, 0, 0, tzinfo=timezone.utc) certificate = builder.build(ca2_private_key) dump_cert('client-untrusted', certificate) if not quiet: write('done') # Certificate that has a weak signature if not quiet: write('Generating weak client cert ... ', end='') builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'TLS Client Certificates Limited', 'common_name': 'Weak TLS Client Certificate', }, public_key) builder.issuer = ca_cert builder.crl_url = crl_url # Hack since API doesn't allow selection of weak algo builder._hash_algo = 'md5' builder.begin_date = datetime(base_year, 1, 1, 0, 0, 0, tzinfo=timezone.utc) builder.end_date = datetime(base_year + 3, 1, 1, 0, 0, 0, tzinfo=timezone.utc) certificate = builder.build(ca_private_key) dump_cert('client-weak', certificate) if not quiet: write('done') # Certificate that has bad key usage if not quiet: write('Generating bad key usage client cert ... ', end='') builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'TLS Client Certificates Limited', 'common_name': 'Bad Key Usage TLS Client Certificate', }, public_key) builder.issuer = ca_cert builder.crl_url = crl_url builder.begin_date = datetime(base_year, 1, 1, 0, 0, 0, tzinfo=timezone.utc) builder.end_date = datetime(base_year + 3, 1, 1, 0, 0, 0, tzinfo=timezone.utc) builder.key_usage = set(['crl_sign']) builder.extended_key_usage = set(['email_protection']) certificate = builder.build(ca_private_key) dump_cert('client-bad-key-usage', certificate) if not quiet: write('done') # Certificate that has been revoked if not quiet: write('Generating revoked client cert ... ', end='') builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'TLS Client Certificates Limited', 'common_name': 'Revoked TLS Client Certificate', }, public_key) builder.issuer = ca_cert builder.crl_url = crl_url builder.begin_date = datetime(base_year, 1, 1, 0, 0, 0, tzinfo=timezone.utc) builder.end_date = datetime(base_year + 3, 1, 1, 0, 0, 0, tzinfo=timezone.utc) revoked_certificate = builder.build(ca_private_key) dump_cert('client-revoked', revoked_certificate) if not quiet: write('done') crl_number = 1000 crl_builder = CertificateListBuilder(crl_url, ca_cert, crl_number) crl_builder.add_certificate( revoked_certificate.serial_number, datetime(base_year, 1, 2, 0, 0, 0, tzinfo=timezone.utc), 'key_compromise') certificate_list = crl_builder.build(ca_private_key) dump_crl('client', certificate_list)
def _sign(csr, buf, overwrite=False): # TODO: CRLDistributionPoints, OCSP URL, Certificate URL assert buf.startswith("-----BEGIN CERTIFICATE REQUEST-----\n") assert isinstance(csr, CertificationRequest) csr_pubkey = asymmetric.load_public_key( csr["certification_request_info"]["subject_pk_info"]) common_name = csr["certification_request_info"]["subject"].native[ "common_name"] cert_path = os.path.join(config.SIGNED_DIR, "%s.pem" % common_name) renew = False attachments = [ (buf, "application/x-pem-file", common_name + ".csr"), ] revoked_path = None overwritten = False # Move existing certificate if necessary if os.path.exists(cert_path): with open(cert_path) as fh: prev_buf = fh.read() header, _, der_bytes = pem.unarmor(prev_buf) prev = x509.Certificate.load(der_bytes) # TODO: assert validity here again? renew = \ asymmetric.load_public_key(prev["tbs_certificate"]["subject_public_key_info"]) == \ csr_pubkey # BUGBUG: is this enough? if overwrite: # TODO: is this the best approach? prev_serial_hex = "%x" % prev.serial_number revoked_path = os.path.join(config.REVOKED_DIR, "%s.pem" % prev_serial_hex) os.rename(cert_path, revoked_path) attachments += [(prev_buf, "application/x-pem-file", "deprecated.crt" if renew else "overwritten.crt")] overwritten = True else: raise EnvironmentError("Will not overwrite existing certificate") # Sign via signer process builder = CertificateBuilder({u'common_name': common_name}, csr_pubkey) builder.serial_number = random.randint( 0x1000000000000000000000000000000000000000, 0xffffffffffffffffffffffffffffffffffffffff) now = datetime.utcnow() builder.begin_date = now - timedelta(minutes=5) builder.end_date = now + timedelta( days=config.SERVER_CERTIFICATE_LIFETIME if server_flags(common_name) else config.CLIENT_CERTIFICATE_LIFETIME) builder.issuer = certificate builder.ca = False builder.key_usage = set([u"digital_signature", u"key_encipherment"]) # OpenVPN uses CN while StrongSwan uses SAN if server_flags(common_name): builder.subject_alt_domains = [common_name] builder.extended_key_usage = set( [u"server_auth", u"1.3.6.1.5.5.8.2.2", u"client_auth"]) else: builder.extended_key_usage = set([u"client_auth"]) end_entity_cert = builder.build(private_key) end_entity_cert_buf = asymmetric.dump_certificate(end_entity_cert) with open(cert_path + ".part", "wb") as fh: fh.write(end_entity_cert_buf) os.rename(cert_path + ".part", cert_path) attachments.append( (end_entity_cert_buf, "application/x-pem-file", common_name + ".crt")) cert_serial_hex = "%x" % end_entity_cert.serial_number # Create symlink link_name = os.path.join(config.SIGNED_BY_SERIAL_DIR, "%x.pem" % end_entity_cert.serial_number) assert not os.path.exists( link_name ), "Certificate with same serial number already exists: %s" % link_name os.symlink("../%s.pem" % common_name, link_name) # Copy filesystem attributes to newly signed certificate if revoked_path: for key in listxattr(revoked_path): if not key.startswith("user."): continue setxattr(cert_path, key, getxattr(revoked_path, key)) # Send mail if renew: # Same keypair mailer.send("certificate-renewed.md", **locals()) else: # New keypair mailer.send("certificate-signed.md", **locals()) url = config.LONG_POLL_PUBLISH % hashlib.sha256(buf).hexdigest() click.echo("Publishing certificate at %s ..." % url) requests.post(url, data=end_entity_cert_buf, headers={ "User-Agent": "Certidude API", "Content-Type": "application/x-x509-user-cert" }) push.publish("request-signed", common_name) return end_entity_cert, end_entity_cert_buf
def _sign(csr, buf, skip_notify=False, skip_push=False, overwrite=False, profile="default", signer=None): # TODO: CRLDistributionPoints, OCSP URL, Certificate URL if profile not in config.PROFILES: raise ValueError("Invalid profile supplied '%s'" % profile) assert buf.startswith(b"-----BEGIN ") assert isinstance(csr, CertificationRequest) csr_pubkey = asymmetric.load_public_key( csr["certification_request_info"]["subject_pk_info"]) common_name = csr["certification_request_info"]["subject"].native[ "common_name"] cert_path = os.path.join(config.SIGNED_DIR, "%s.pem" % common_name) renew = False attachments = [ (buf, "application/x-pem-file", common_name + ".csr"), ] revoked_path = None overwritten = False # Move existing certificate if necessary if os.path.exists(cert_path): with open(cert_path, "rb") as fh: prev_buf = fh.read() header, _, der_bytes = pem.unarmor(prev_buf) prev = x509.Certificate.load(der_bytes) # TODO: assert validity here again? renew = \ asymmetric.load_public_key(prev["tbs_certificate"]["subject_public_key_info"]) == \ csr_pubkey # BUGBUG: is this enough? if overwrite: # TODO: is this the best approach? prev_serial_hex = "%x" % prev.serial_number revoked_path = os.path.join(config.REVOKED_DIR, "%s.pem" % prev_serial_hex) os.rename(cert_path, revoked_path) attachments += [(prev_buf, "application/x-pem-file", "deprecated.crt" if renew else "overwritten.crt")] overwritten = True else: raise FileExistsError("Will not overwrite existing certificate") # Sign via signer process dn = {u'common_name': common_name} profile_server_flags, lifetime, dn[ "organizational_unit_name"], _ = config.PROFILES[profile] lifetime = int(lifetime) builder = CertificateBuilder(dn, csr_pubkey) builder.serial_number = random.randint( 0x1000000000000000000000000000000000000000, 0x7fffffffffffffffffffffffffffffffffffffff) now = datetime.utcnow() builder.begin_date = now - timedelta(minutes=5) builder.end_date = now + timedelta(days=lifetime) builder.issuer = certificate builder.ca = False builder.key_usage = set(["digital_signature", "key_encipherment"]) # If we have FQDN and profile suggests server flags, enable them if server_flags(common_name) and profile_server_flags: builder.subject_alt_domains = [ common_name ] # OpenVPN uses CN while StrongSwan uses SAN to match hostname of the server builder.extended_key_usage = set( ["server_auth", "1.3.6.1.5.5.8.2.2", "client_auth"]) else: builder.subject_alt_domains = [common_name ] # iOS demands SAN also for clients builder.extended_key_usage = set(["client_auth"]) end_entity_cert = builder.build(private_key) end_entity_cert_buf = asymmetric.dump_certificate(end_entity_cert) with open(cert_path + ".part", "wb") as fh: fh.write(end_entity_cert_buf) os.rename(cert_path + ".part", cert_path) attachments.append( (end_entity_cert_buf, "application/x-pem-file", common_name + ".crt")) cert_serial_hex = "%x" % end_entity_cert.serial_number # Create symlink link_name = os.path.join(config.SIGNED_BY_SERIAL_DIR, "%x.pem" % end_entity_cert.serial_number) assert not os.path.exists( link_name ), "Certificate with same serial number already exists: %s" % link_name os.symlink("../%s.pem" % common_name, link_name) # Copy filesystem attributes to newly signed certificate if revoked_path: for key in listxattr(revoked_path): if not key.startswith(b"user."): continue setxattr(cert_path, key, getxattr(revoked_path, key)) # Attach signer username if signer: setxattr(cert_path, "user.signature.username", signer) if not skip_notify: # Send mail if renew: # Same keypair mailer.send("certificate-renewed.md", **locals()) else: # New keypair mailer.send("certificate-signed.md", **locals()) if not skip_push: url = config.LONG_POLL_PUBLISH % hashlib.sha256(buf).hexdigest() click.echo("Publishing certificate at %s ..." % url) requests.post(url, data=end_entity_cert_buf, headers={ "User-Agent": "Certidude API", "Content-Type": "application/x-x509-user-cert" }) push.publish("request-signed", common_name) return end_entity_cert, end_entity_cert_buf
builder.end_entity = False root_ca_certificate = builder.build(root_ca_private_key) with open(os.path.join(fixtures_dir, 'root.crt'), 'wb') as f: f.write(asymmetric.dump_certificate(root_ca_certificate)) root_crl_public_key, root_crl_private_key = asymmetric.generate_pair( 'rsa', bit_size=2048) with open(os.path.join(fixtures_dir, 'crl_issuer.key'), 'wb') as f: f.write( asymmetric.dump_private_key(root_crl_private_key, 'password123', target_ms=20)) builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Codex Non Sufficit LC', 'common_name': 'CodexNS Root CA 1 CRL Issuer', }, root_crl_public_key) builder.key_usage = set(['crl_signing']) builder.extended_key_usage = None builder.issuer = root_ca_certificate root_crl_certificate = builder.build(root_ca_private_key) with open(os.path.join(fixtures_dir, 'crl_issuer.crt'), 'wb') as f: f.write(asymmetric.dump_certificate(root_crl_certificate))