def test_sign_with_revoked_certificates(self, backend): private_key = RSA_KEY_2048.private_key(backend) last_update = datetime.datetime(2002, 1, 1, 12, 1) next_update = datetime.datetime(2030, 1, 1, 12, 1) invalidity_date = x509.InvalidityDate( datetime.datetime(2002, 1, 1, 0, 0)) revoked_cert0 = ( x509.RevokedCertificateBuilder().serial_number(38).revocation_date( datetime.datetime(2011, 1, 1, 1, 1)).build(backend)) revoked_cert1 = ( x509.RevokedCertificateBuilder().serial_number(2).revocation_date( datetime.datetime(2012, 1, 1, 1, 1)).add_extension(invalidity_date, False).build(backend)) builder = (x509.CertificateRevocationListBuilder().issuer_name( x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA") ])).last_update(last_update).next_update( next_update).add_revoked_certificate( revoked_cert0).add_revoked_certificate(revoked_cert1)) crl = builder.sign(private_key, hashes.SHA256(), backend) assert len(crl) == 2 assert crl.last_update == last_update assert crl.next_update == next_update assert crl[0].serial_number == revoked_cert0.serial_number assert crl[0].revocation_date == revoked_cert0.revocation_date assert len(crl[0].extensions) == 0 assert crl[1].serial_number == revoked_cert1.serial_number assert crl[1].revocation_date == revoked_cert1.revocation_date assert len(crl[1].extensions) == 1 ext = crl[1].extensions.get_extension_for_class(x509.InvalidityDate) assert ext.critical is False assert ext.value == invalidity_date
def test_revoke_certificates_create_or_update_crl(ca_cert, ca_key): revoked_batch_1 = [ x509.RevokedCertificateBuilder() \ .revocation_date(time=datetime.datetime.today()) \ .serial_number(x509.random_serial_number()) \ .build(default_backend()) for x in range(10) ] revoked_batch_2 = [ x509.RevokedCertificateBuilder() \ .revocation_date(time=datetime.datetime.today()) \ .serial_number(x509.random_serial_number()) \ .build(default_backend()) for x in range(10) ] new_crl = revoke_certificates_create_or_update_crl(ca_cert, ca_key, revoked_batch_1) assert all([ c.serial_number == r.serial_number for c, r in zip(new_crl, revoked_batch_1) ]) updated_crl = revoke_certificates_create_or_update_crl( ca_cert, ca_key, revoked_batch_2, crl_to_update=new_crl) revoked_serial_numbers = { rc.serial_number for rc in [*revoked_batch_1, *revoked_batch_2] } updated_serial_numers = {rc.serial_number for rc in updated_crl} assert revoked_serial_numbers == updated_serial_numers
def get_crl(self): """Generates a Certificate Revocation List. Returns: A Certificate Revocation List. """ ca_pkey = self.get_ca_key() ca_cert = self.get_ca_cert(ca_pkey) crl = (x509.CertificateRevocationListBuilder().issuer_name( ca_cert.subject).last_update( datetime.datetime.utcnow()).next_update( datetime.datetime.utcnow() + datetime.timedelta(minutes=15))) for cert in self.storage.get_revoked_certs(): # Convert the string cert into a cryptography cert object cert = x509.load_pem_x509_certificate(bytes(str(cert), "UTF-8"), backend=default_backend()) # Add the certificate to the CRL crl = crl.add_revoked_certificate( x509.RevokedCertificateBuilder().serial_number( cert.serial_number).revocation_date( datetime.datetime.utcnow()).build( backend=default_backend())) # Sign the CRL crl = crl.sign(private_key=ca_pkey, algorithm=hashes.SHA256(), backend=default_backend()) return crl
def revocation_builder(pem: str, timestamp: datetime.datetime) -> RevokedCertificate: certificate = x509.load_pem_x509_certificate(pem.encode("utf8"), backend=default_backend()) revoked_cert = (x509.RevokedCertificateBuilder().serial_number( certificate.serial_number).revocation_date(timestamp).build()) return revoked_cert
def test_no_serial_number(self, backend): builder = x509.RevokedCertificateBuilder().revocation_date( datetime.datetime(2002, 1, 1, 12, 1) ) with pytest.raises(ValueError): builder.build(backend)
def test_sign_ed448_key(self, backend): private_key = ed448.Ed448PrivateKey.generate() invalidity_date = x509.InvalidityDate( datetime.datetime(2002, 1, 1, 0, 0)) ian = x509.IssuerAlternativeName( [x509.UniformResourceIdentifier("https://cryptography.io")]) revoked_cert0 = ( x509.RevokedCertificateBuilder().serial_number(2).revocation_date( datetime.datetime(2012, 1, 1, 1, 1)).add_extension(invalidity_date, False).build(backend)) last_update = datetime.datetime(2002, 1, 1, 12, 1) next_update = datetime.datetime(2030, 1, 1, 12, 1) builder = (x509.CertificateRevocationListBuilder().issuer_name( x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, "cryptography.io CA") ])).last_update(last_update).next_update(next_update). add_revoked_certificate(revoked_cert0).add_extension( ian, False)) crl = builder.sign(private_key, None, backend) assert crl.signature_hash_algorithm is None assert crl.signature_algorithm_oid == SignatureAlgorithmOID.ED448 assert (crl.extensions.get_extension_for_class( x509.IssuerAlternativeName).value == ian) assert crl[0].serial_number == revoked_cert0.serial_number assert crl[0].revocation_date == revoked_cert0.revocation_date assert len(crl[0].extensions) == 1 ext = crl[0].extensions.get_extension_for_class(x509.InvalidityDate) assert ext.critical is False assert ext.value == invalidity_date
def test_minimal_serial_number(self, backend): revocation_date = datetime.datetime(2002, 1, 1, 12, 1) builder = (x509.RevokedCertificateBuilder().serial_number( 1).revocation_date(revocation_date)) revoked_certificate = builder.build(backend) assert revoked_certificate.serial_number == 1
def test_biggest_serial_number(self, backend): revocation_date = datetime.datetime(2002, 1, 1, 12, 1) builder = x509.RevokedCertificateBuilder().serial_number( (1 << 159) - 1).revocation_date(revocation_date) revoked_certificate = builder.build(backend) assert revoked_certificate.serial_number == (1 << 159) - 1
def test_add_extension_checks_for_duplicates(self): builder = x509.RevokedCertificateBuilder().add_extension( x509.CRLReason(x509.ReasonFlags.ca_compromise), False) with pytest.raises(ValueError): builder.add_extension( x509.CRLReason(x509.ReasonFlags.ca_compromise), False)
def create_crl(*serials): """ Returns a new certificate revocation list that contains all of the revoked certificates with the given list of serial numbers. :return: str """ signer = certificate_authority() builder = x509.CertificateRevocationListBuilder( last_update=datetime.now() - timedelta(days=1), next_update=datetime.now() + timedelta(days=3650), issuer_name=signer.crt.subject, ) # iterate over each serial number and create a new revoked certificate # that is added to the CRL builder for serial in serials: revoked = x509.RevokedCertificateBuilder( serial_number=int(serial), revocation_date=datetime.now() - timedelta(days=1), ) revoked = revoked.build(default_backend()) builder = builder.add_revoked_certificate(revoked) # sign the CRL with the certificate authority private key crl = builder.sign( private_key=signer.key, algorithm=hashes.SHA512(), backend=default_backend(), ) return encode_certificate(crl)
def regenerate_certificate_revocation_list(self, certification_authority): logger.info("Updating CRL for CA %s" % certification_authority.common_name) one_day = datetime.timedelta(1, 0, 0) ca_cert = x509.load_pem_x509_certificate( str(certification_authority.certificate), default_backend()) ca_key = serialization.load_pem_private_key( str(certification_authority.private_key), None, default_backend()) builder = x509.CertificateRevocationListBuilder() builder = builder.issuer_name(ca_cert.subject) builder = builder.last_update(datetime.datetime.today()) builder = builder.next_update(datetime.datetime.today() + one_day) for certificate in SSLRevokedCertificate.objects.filter( certification_authority=certification_authority): logger.info("Adding certificate 0x%X" % certificate.serial_number) revoked_cert = x509.RevokedCertificateBuilder().serial_number( certificate.serial_number).revocation_date( certificate.revocation_date.replace(tzinfo=None)).build( default_backend()) builder = builder.add_revoked_certificate(revoked_cert) crl = builder.sign(private_key=ca_key, algorithm=hashes.SHA256(), backend=default_backend()) logger.info('Saving models') certification_authority.revocation_list = crl.public_bytes( serialization.Encoding.PEM) print certification_authority.revocation_list certification_authority.save()
def test_add_multiple_extensions(self, backend): serial_number = 333 revocation_date = datetime.datetime(2002, 1, 1, 12, 1) invalidity_date = x509.InvalidityDate( datetime.datetime(2015, 1, 1, 0, 0) ) certificate_issuer = x509.CertificateIssuer( [x509.DNSName(u"cryptography.io")] ) crl_reason = x509.CRLReason(x509.ReasonFlags.aa_compromise) builder = ( x509.RevokedCertificateBuilder() .serial_number(serial_number) .revocation_date(revocation_date) .add_extension(invalidity_date, True) .add_extension(crl_reason, True) .add_extension(certificate_issuer, True) ) revoked_certificate = builder.build(backend) assert len(revoked_certificate.extensions) == 3 for ext_data in [invalidity_date, certificate_issuer, crl_reason]: ext = revoked_certificate.extensions.get_extension_for_class( type(ext_data) ) assert ext.critical is True assert ext.value == ext_data
def test_sign_dsa_key(self, backend): if backend._lib.OPENSSL_VERSION_NUMBER < 0x10001000: pytest.skip("Requires a newer OpenSSL. Must be >= 1.0.1") private_key = DSA_KEY_2048.private_key(backend) invalidity_date = x509.InvalidityDate( datetime.datetime(2002, 1, 1, 0, 0)) ian = x509.IssuerAlternativeName([ x509.UniformResourceIdentifier(u"https://cryptography.io"), ]) revoked_cert0 = x509.RevokedCertificateBuilder().serial_number( 2).revocation_date(datetime.datetime(2012, 1, 1, 1, 1)).add_extension( invalidity_date, False).build(backend) last_update = datetime.datetime(2002, 1, 1, 12, 1) next_update = datetime.datetime(2030, 1, 1, 12, 1) builder = x509.CertificateRevocationListBuilder().issuer_name( x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA") ])).last_update(last_update).next_update( next_update).add_revoked_certificate( revoked_cert0).add_extension(ian, False) crl = builder.sign(private_key, hashes.SHA256(), backend) assert crl.extensions.get_extension_for_class( x509.IssuerAlternativeName).value == ian assert crl[0].serial_number == revoked_cert0.serial_number assert crl[0].revocation_date == revoked_cert0.revocation_date assert len(crl[0].extensions) == 1 ext = crl[0].extensions.get_extension_for_class(x509.InvalidityDate) assert ext.critical is False assert ext.value == invalidity_date
def generate_crl(self, ca, certs, next_update=1): # There is a tricky case here - what happens if the root CA is compromised ? # In normal world scenarios, that CA is removed from app's trust store and any # subsequent certs it had issues wouldn't be validated by the app then. Making a CRL # for a revoked root CA in normal cases doesn't make sense as the thief can sign a # counter CRL saying that everything is fine. As our environment is controlled, # i think we are safe to create a crl for root CA as well which we can publish for # services which make use of it i.e openvpn and they'll know that the certs/ca's have been # compromised. # # `ca` is root ca from where the chain `certs` starts. # `certs` is a list of all certs ca inclusive which are to be # included in the CRL ( if root ca is compromised, it will be in `certs` as well ). private_key = load_private_key(ca['privatekey']) ca_cert = x509.load_pem_x509_certificate(ca['certificate'].encode(), default_backend()) if not private_key: return None ca_data = self.middleware.call_sync('cryptokey.load_certificate', ca['certificate']) issuer = {k: ca_data.get(v) for k, v in CERT_BACKEND_MAPPINGS.items()} crl_builder = x509.CertificateRevocationListBuilder().issuer_name( x509.Name([ x509.NameAttribute(getattr(NameOID, k.upper()), v) for k, v in issuer.items() if v ])).last_update(datetime.datetime.utcnow()).next_update( datetime.datetime.utcnow() + datetime.timedelta(next_update, 300, 0)) for cert in certs: crl_builder = crl_builder.add_revoked_certificate( x509.RevokedCertificateBuilder().serial_number( self.middleware.call_sync( 'cryptokey.load_certificate', cert['certificate'])['serial']).revocation_date( cert['revoked_date']).build(default_backend())) # https://www.ietf.org/rfc/rfc5280.txt # We should add AuthorityKeyIdentifier and CRLNumber at the very least crl = crl_builder.add_extension( x509.AuthorityKeyIdentifier( x509.SubjectKeyIdentifier.from_public_key( ca_cert.public_key()).digest, [ x509.DirectoryName( x509.Name([ x509.NameAttribute(getattr(NameOID, k.upper()), v) for k, v in issuer.items() if v ])) ], ca_cert.serial_number), False).add_extension(x509.CRLNumber(1), False).sign( private_key=private_key, algorithm=retrieve_signing_algorithm({}, private_key), backend=default_backend()) return crl.public_bytes(serialization.Encoding.PEM).decode()
def create_crl(crl_path, ca_key, ca_cert): now = datetime.utcnow() builder = ( x509.CertificateRevocationListBuilder() .last_update(now) .next_update(now + timedelta(days=1)) .issuer_name(ca_cert.subject) ) for i in [3,4,5]: cert = ( x509.RevokedCertificateBuilder() .revocation_date(now) .serial_number(i) .add_extension( x509.CRLReason(x509.ReasonFlags.key_compromise), critical=False) .build(default_backend()) ) builder = builder.add_revoked_certificate(cert) cert = builder.sign( private_key=ca_key, algorithm=hashes.SHA256(), backend=default_backend()) write_public(cert, crl_path)
def build_crl(): #from cryptography import x509 # from cryptography.hazmat.backends import default_backend #from cryptography.hazmat.primitives import hashes # from cryptography.hazmat.primitives.asymmetric import rsa #from cryptography.x509.oid import NameOID #import datetime ca = get_newest_ca() one_day = datetime.timedelta(1, 0, 0) builder = x509.CertificateRevocationListBuilder() builder = builder.issuer_name( x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, ca.common_name), ])) builder = builder.last_update(datetime.datetime.today()) builder = builder.next_update(datetime.datetime.today() + one_day) revoked_list = Certificate.objects.filter( issuer_serial_number=ca.serial_number, revoked=True) for revoked_cert in revoked_list: logger.debug("revoked serial_number: %s", revoked_cert.serial_number) revoked_cert = x509.RevokedCertificateBuilder().serial_number( int(revoked_cert.serial_number)).revocation_date( datetime.datetime.today()).build(default_backend()) builder = builder.add_revoked_certificate(revoked_cert) crl = builder.sign(private_key=loadPEMKey(keyStorePath(ca.serial_number)), algorithm=hashes.SHA256(), backend=default_backend()) dataStream = crl.public_bytes(serialization.Encoding.PEM) return dataStream
def test_sign_ec_key(self, backend): _skip_curve_unsupported(backend, ec.SECP256R1()) private_key = ec.generate_private_key(ec.SECP256R1(), backend) invalidity_date = x509.InvalidityDate( datetime.datetime(2002, 1, 1, 0, 0)) ian = x509.IssuerAlternativeName( [x509.UniformResourceIdentifier("https://cryptography.io")]) revoked_cert0 = ( x509.RevokedCertificateBuilder().serial_number(2).revocation_date( datetime.datetime(2012, 1, 1, 1, 1)).add_extension(invalidity_date, False).build(backend)) last_update = datetime.datetime(2002, 1, 1, 12, 1) next_update = datetime.datetime(2030, 1, 1, 12, 1) builder = (x509.CertificateRevocationListBuilder().issuer_name( x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, "cryptography.io CA") ])).last_update(last_update).next_update(next_update). add_revoked_certificate(revoked_cert0).add_extension( ian, False)) crl = builder.sign(private_key, hashes.SHA256(), backend) assert (crl.extensions.get_extension_for_class( x509.IssuerAlternativeName).value == ian) assert crl[0].serial_number == revoked_cert0.serial_number assert crl[0].revocation_date == revoked_cert0.revocation_date assert len(crl[0].extensions) == 1 ext = crl[0].extensions.get_extension_for_class(x509.InvalidityDate) assert ext.critical is False assert ext.value == invalidity_date
def create_revocation_object(self): if not self.revocation: return None revoked_cert = x509.RevokedCertificateBuilder().serial_number( self.get_certificate().serial_number).revocation_date( datetime.datetime.strptime( str(self.revocation.revocation_date), '%Y-%m-%d')).build(default_backend()) return revoked_cert
def _revoke_cert(self, ca_private_key, cert): crl = self._load_ca_crl(cert.ca_name) builder = self._builder_crl(cert.ca_name, crl) revoked_certificate = x509.RevokedCertificateBuilder().serial_number( cert.raw.serial_number).revocation_date( datetime.datetime.now(tz.tzlocal())).build(default_backend()) builder = builder.add_revoked_certificate(revoked_certificate) crl = self._crl_save(cert.ca_name, ca_private_key, builder) foobar = crl.get_revoked_certificate_by_serial_number( cert.raw.serial_number)
def test_create_revoked(self, backend): serial_number = 333 revocation_date = datetime.datetime(2002, 1, 1, 12, 1) builder = x509.RevokedCertificateBuilder().serial_number( serial_number).revocation_date(revocation_date) revoked_certificate = builder.build(backend) assert revoked_certificate.serial_number == serial_number assert revoked_certificate.revocation_date == revocation_date assert len(revoked_certificate.extensions) == 0
def test_aware_revocation_date(self, backend): time = datetime.datetime(2012, 1, 16, 22, 43) tz = pytz.timezone("US/Pacific") time = tz.localize(time) utc_time = datetime.datetime(2012, 1, 17, 6, 43) serial_number = 333 builder = (x509.RevokedCertificateBuilder().serial_number( serial_number).revocation_date(time)) revoked_certificate = builder.build(backend) assert revoked_certificate.revocation_date == utc_time
def revoke(self, cert, save=True): ''' Revoke certificate ''' revoked_cert = x509.RevokedCertificateBuilder().serial_number( cert.serial_number).revocation_date( datetime.datetime.now(tz=tz)).build(default_backend()) self.builder = self.builder.add_revoked_certificate(revoked_cert) if save: self.save()
def new_crl(path, issuer, cert): issuer_cert, signing_key = issuer revoked_cert = (x509.RevokedCertificateBuilder().serial_number( cert[0].serial_number).revocation_date( datetime.datetime.today()).build()) builder = (x509.CertificateRevocationListBuilder().issuer_name( issuer_cert.subject).last_update( datetime.datetime.today()).next_update(datetime.datetime.today() + datetime.timedelta(days=1)). add_revoked_certificate(revoked_cert)) crl = builder.sign(private_key=signing_key, algorithm=hashes.SHA256()) with open(path + ".crl.pem", "wb") as f: f.write(crl.public_bytes(encoding=serialization.Encoding.PEM))
def get_revocation(self): """Get a crypto.Revoked object or None if the cert is not revoked.""" if self.revoked is False: raise ValueError('Certificate is not revoked.') revoked_cert = x509.RevokedCertificateBuilder().serial_number( self.x509.serial).revocation_date(self.revoked_date) if self.revoked_reason: reason_flag = getattr(x509.ReasonFlags, self.revoked_reason) revoked_cert = revoked_cert.add_extension( x509.CRLReason(reason_flag), critical=False) return revoked_cert.build(default_backend())
def test_add_unsupported_entry_extension(self, backend): private_key = RSA_KEY_2048.private_key(backend) last_update = datetime.datetime(2002, 1, 1, 12, 1) next_update = datetime.datetime(2030, 1, 1, 12, 1) builder = (x509.CertificateRevocationListBuilder().issuer_name( x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, "cryptography.io CA") ])).last_update(last_update).next_update( next_update).add_revoked_certificate( x509.RevokedCertificateBuilder().serial_number( 1234).revocation_date( datetime.datetime.utcnow()).add_extension( DummyExtension(), critical=False).build())) with pytest.raises(NotImplementedError): builder.sign(private_key, hashes.SHA256(), backend)
def test_add_extensions(self, backend, extension): serial_number = 333 revocation_date = datetime.datetime(2002, 1, 1, 12, 1) builder = x509.RevokedCertificateBuilder().serial_number( serial_number).revocation_date(revocation_date).add_extension( extension, False) revoked_certificate = builder.build(backend) assert revoked_certificate.serial_number == serial_number assert revoked_certificate.revocation_date == revocation_date assert len(revoked_certificate.extensions) == 1 ext = revoked_certificate.extensions.get_extension_for_class( type(extension)) assert ext.critical is False assert ext.value == extension
def normalize(self, active=[]): ''' Mark all sequence not in active as Revoked return all active sequence numbers ''' for i in range(1, self.ca.sequence_number): if i not in active and i not in self.revoked_numbers: self.revoked_numbers.append(i) revoked_cert = x509.RevokedCertificateBuilder().serial_number( i).revocation_date(datetime.datetime.now(tz=tz)).build( default_backend()) self.builder = self.builder.add_revoked_certificate( revoked_cert) self.save() return [i for i in active if i not in self.revoked_numbers]
def revoke_certificate(cert: x509.Certificate) -> x509.RevokedCertificate: """ Revokes certificate. Parameters ---------- cert Certificate to revoke. Returns ------- Revoked certificate. """ builder = x509.RevokedCertificateBuilder() builder = builder.revocation_date(datetime.datetime.today()) builder = builder.serial_number(cert.serial_number) revoked_certificate = builder.build(default_backend()) return revoked_certificate
def revoke_certificate(certificate): """ Revoke a certificate Parameters ---------- certificate: Certificate certificate to revoke Returns ------- RevokedCertificate """ builder = x509.RevokedCertificateBuilder() builder = builder.revocation_date(datetime.datetime.today()) builder = builder.serial_number(certificate.serial_number) return builder.build(default_backend())
def test_generate_crl(ca_cert, ca_key): revoked_certs = [ x509.RevokedCertificateBuilder() \ .revocation_date(time=datetime.datetime.today()) \ .serial_number(x509.random_serial_number()) \ .build(default_backend()) for x in range(10) ] crl = generate_crl(ca_cert, ca_key, revoked_certs[0]) crl2 = generate_crl(ca_cert, ca_key, *revoked_certs) assert crl[0].serial_number == revoked_certs[0].serial_number assert all([ c.serial_number == r.serial_number for c, r in zip(crl2, revoked_certs) ])