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_sign_multiple_extensions_critical(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) ian = x509.IssuerAlternativeName([ x509.UniformResourceIdentifier(u"https://cryptography.io"), ]) crl_number = x509.CRLNumber(13) 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_extension( crl_number, False ).add_extension( ian, True ) crl = builder.sign(private_key, hashes.SHA256(), backend) assert len(crl) == 0 assert len(crl.extensions) == 2 ext1 = crl.extensions.get_extension_for_class(x509.CRLNumber) assert ext1.critical is False assert ext1.value == crl_number ext2 = crl.extensions.get_extension_for_class( x509.IssuerAlternativeName ) assert ext2.critical is True assert ext2.value == ian
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 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 create_x509_cert(privkey, pubkey, subject_info, issuer_info, days): """Main cert creation code. """ if not isinstance(subject_info, CertInfo): info = CertInfo() info.load_from_existing(subject_info) subject_info = info if not isinstance(issuer_info, CertInfo): info = CertInfo() info.load_from_existing(issuer_info) issuer_info = info dt_now = datetime.utcnow() dt_start = dt_now - timedelta(hours=1) dt_end = dt_now + timedelta(days=days) builder = (x509.CertificateBuilder() .subject_name(subject_info.get_name()) .issuer_name(issuer_info.get_name()) .not_valid_before(dt_start) .not_valid_after(dt_end) .serial_number(int(uuid.uuid4())) .public_key(pubkey)) builder = subject_info.install_extensions(builder) # SubjectKeyIdentifier ext = x509.SubjectKeyIdentifier.from_public_key(pubkey) builder = builder.add_extension(ext, critical=False) # AuthorityKeyIdentifier ext = x509.AuthorityKeyIdentifier.from_issuer_public_key(privkey.public_key()) builder = builder.add_extension(ext, critical=False) # IssuerAlternativeName if issuer_info.san: ext = x509.IssuerAlternativeName(issuer_info.get_san_gnames()) builder = builder.add_extension(ext, critical=False) # final cert cert = builder.sign(private_key=privkey, algorithm=SHA256(), backend=get_backend()) return cert
def _decode_issuer_alt_name(backend, ext): return x509.IssuerAlternativeName( _decode_general_names_extension(backend, ext))
class TestCertificateRevocationListBuilder(object): def test_issuer_name_invalid(self): builder = x509.CertificateRevocationListBuilder() with pytest.raises(TypeError): builder.issuer_name("notanx509name") def test_set_issuer_name_twice(self): builder = x509.CertificateRevocationListBuilder().issuer_name( x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')]) ) with pytest.raises(ValueError): builder.issuer_name( x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')]) ) @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) def test_aware_last_update(self, backend): last_time = datetime.datetime(2012, 1, 16, 22, 43) tz = pytz.timezone("US/Pacific") last_time = tz.localize(last_time) utc_last = datetime.datetime(2012, 1, 17, 6, 43) next_time = datetime.datetime(2022, 1, 17, 6, 43) private_key = RSA_KEY_2048.private_key(backend) builder = x509.CertificateRevocationListBuilder().issuer_name( x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA") ]) ).last_update(last_time).next_update(next_time) crl = builder.sign(private_key, hashes.SHA256(), backend) assert crl.last_update == utc_last def test_last_update_invalid(self): builder = x509.CertificateRevocationListBuilder() with pytest.raises(TypeError): builder.last_update("notadatetime") def test_last_update_before_unix_epoch(self): builder = x509.CertificateRevocationListBuilder() with pytest.raises(ValueError): builder.last_update(datetime.datetime(1960, 8, 10)) def test_set_last_update_twice(self): builder = x509.CertificateRevocationListBuilder().last_update( datetime.datetime(2002, 1, 1, 12, 1) ) with pytest.raises(ValueError): builder.last_update(datetime.datetime(2002, 1, 1, 12, 1)) @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) def test_aware_next_update(self, backend): next_time = datetime.datetime(2022, 1, 16, 22, 43) tz = pytz.timezone("US/Pacific") next_time = tz.localize(next_time) utc_next = datetime.datetime(2022, 1, 17, 6, 43) last_time = datetime.datetime(2012, 1, 17, 6, 43) private_key = RSA_KEY_2048.private_key(backend) builder = x509.CertificateRevocationListBuilder().issuer_name( x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA") ]) ).last_update(last_time).next_update(next_time) crl = builder.sign(private_key, hashes.SHA256(), backend) assert crl.next_update == utc_next def test_next_update_invalid(self): builder = x509.CertificateRevocationListBuilder() with pytest.raises(TypeError): builder.next_update("notadatetime") def test_next_update_before_unix_epoch(self): builder = x509.CertificateRevocationListBuilder() with pytest.raises(ValueError): builder.next_update(datetime.datetime(1960, 8, 10)) def test_set_next_update_twice(self): builder = x509.CertificateRevocationListBuilder().next_update( datetime.datetime(2002, 1, 1, 12, 1) ) with pytest.raises(ValueError): builder.next_update(datetime.datetime(2002, 1, 1, 12, 1)) def test_last_update_after_next_update(self): builder = x509.CertificateRevocationListBuilder() builder = builder.next_update( datetime.datetime(2002, 1, 1, 12, 1) ) with pytest.raises(ValueError): builder.last_update(datetime.datetime(2003, 1, 1, 12, 1)) def test_next_update_after_last_update(self): builder = x509.CertificateRevocationListBuilder() builder = builder.last_update( datetime.datetime(2002, 1, 1, 12, 1) ) with pytest.raises(ValueError): builder.next_update(datetime.datetime(2001, 1, 1, 12, 1)) def test_add_extension_checks_for_duplicates(self): builder = x509.CertificateRevocationListBuilder().add_extension( x509.CRLNumber(1), False ) with pytest.raises(ValueError): builder.add_extension(x509.CRLNumber(2), False) def test_add_invalid_extension(self): builder = x509.CertificateRevocationListBuilder() with pytest.raises(TypeError): builder.add_extension( object(), False ) def test_add_invalid_revoked_certificate(self): builder = x509.CertificateRevocationListBuilder() with pytest.raises(TypeError): builder.add_revoked_certificate(object()) @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) def test_no_issuer_name(self, backend): private_key = RSA_KEY_2048.private_key(backend) builder = x509.CertificateRevocationListBuilder().last_update( datetime.datetime(2002, 1, 1, 12, 1) ).next_update( datetime.datetime(2030, 1, 1, 12, 1) ) with pytest.raises(ValueError): builder.sign(private_key, hashes.SHA256(), backend) @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) def test_no_last_update(self, backend): private_key = RSA_KEY_2048.private_key(backend) builder = x509.CertificateRevocationListBuilder().issuer_name( x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')]) ).next_update( datetime.datetime(2030, 1, 1, 12, 1) ) with pytest.raises(ValueError): builder.sign(private_key, hashes.SHA256(), backend) @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) def test_no_next_update(self, backend): private_key = RSA_KEY_2048.private_key(backend) builder = x509.CertificateRevocationListBuilder().issuer_name( x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')]) ).last_update( datetime.datetime(2030, 1, 1, 12, 1) ) with pytest.raises(ValueError): builder.sign(private_key, hashes.SHA256(), backend) @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) def test_sign_empty_list(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, u"cryptography.io CA") ]) ).last_update(last_update).next_update(next_update) crl = builder.sign(private_key, hashes.SHA256(), backend) assert len(crl) == 0 assert crl.last_update == last_update assert crl.next_update == next_update @pytest.mark.parametrize( "extension", [ x509.CRLNumber(13), x509.AuthorityKeyIdentifier( b"\xc3\x9c\xf3\xfc\xd3F\x084\xbb\xceF\x7f\xa0|[\xf3\xe2\x08" b"\xcbY", None, None ), x509.AuthorityInformationAccess([ x509.AccessDescription( AuthorityInformationAccessOID.CA_ISSUERS, x509.DNSName(u"cryptography.io") ) ]), x509.IssuerAlternativeName([ x509.UniformResourceIdentifier(u"https://cryptography.io"), ]) ] ) @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) def test_sign_extensions(self, backend, extension): 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, u"cryptography.io CA") ]) ).last_update( last_update ).next_update( next_update ).add_extension( extension, False ) crl = builder.sign(private_key, hashes.SHA256(), backend) assert len(crl) == 0 assert len(crl.extensions) == 1 ext = crl.extensions.get_extension_for_class(type(extension)) assert ext.critical is False assert ext.value == extension @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) def test_sign_multiple_extensions_critical(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) ian = x509.IssuerAlternativeName([ x509.UniformResourceIdentifier(u"https://cryptography.io"), ]) crl_number = x509.CRLNumber(13) 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_extension( crl_number, False ).add_extension( ian, True ) crl = builder.sign(private_key, hashes.SHA256(), backend) assert len(crl) == 0 assert len(crl.extensions) == 2 ext1 = crl.extensions.get_extension_for_class(x509.CRLNumber) assert ext1.critical is False assert ext1.value == crl_number ext2 = crl.extensions.get_extension_for_class( x509.IssuerAlternativeName ) assert ext2.critical is True assert ext2.value == ian @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) def test_add_unsupported_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, u"cryptography.io CA") ]) ).last_update( last_update ).next_update( next_update ).add_extension( x509.OCSPNoCheck(), False ) with pytest.raises(NotImplementedError): builder.sign(private_key, hashes.SHA256(), backend) @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) def test_sign_rsa_key_too_small(self, backend): private_key = RSA_KEY_512.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, u"cryptography.io CA") ]) ).last_update( last_update ).next_update( next_update ) with pytest.raises(ValueError): builder.sign(private_key, hashes.SHA512(), backend) @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) def test_sign_with_invalid_hash(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, u"cryptography.io CA") ]) ).last_update( last_update ).next_update( next_update ) with pytest.raises(TypeError): builder.sign(private_key, object(), backend) @pytest.mark.requires_backend_interface(interface=DSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) def test_sign_dsa_key(self, backend): 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 @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) @pytest.mark.requires_backend_interface(interface=X509Backend) 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(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 @pytest.mark.requires_backend_interface(interface=DSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) def test_dsa_key_sign_md5(self, backend): private_key = DSA_KEY_2048.private_key(backend) last_time = datetime.datetime(2012, 1, 16, 22, 43) next_time = datetime.datetime(2022, 1, 17, 6, 43) builder = x509.CertificateRevocationListBuilder().issuer_name( x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA") ]) ).last_update(last_time).next_update(next_time) with pytest.raises(ValueError): builder.sign(private_key, hashes.MD5(), backend) @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) @pytest.mark.requires_backend_interface(interface=X509Backend) def test_ec_key_sign_md5(self, backend): _skip_curve_unsupported(backend, ec.SECP256R1()) private_key = EC_KEY_SECP256R1.private_key(backend) last_time = datetime.datetime(2012, 1, 16, 22, 43) next_time = datetime.datetime(2022, 1, 17, 6, 43) builder = x509.CertificateRevocationListBuilder().issuer_name( x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA") ]) ).last_update(last_time).next_update(next_time) with pytest.raises(ValueError): builder.sign(private_key, hashes.MD5(), backend) @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) 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 sign_cert(self, ca, csr, expires, algorithm, subject=None, cn_in_san=True, csr_format=Encoding.PEM, subjectAltName=None, keyUsage=None, extendedKeyUsage=None, tls_features=None, password=None): """Create a signed certificate from a CSR. X509 extensions (`key_usage`, `ext_key_usage`) may either be None (in which case they are not added) or a tuple with the first value being a bool indicating if the value is critical and the second value being a byte-array indicating the extension value. Example:: (True, b'value') Parameters ---------- ca : :py:class:`~django_ca.models.CertificateAuthority` The certificate authority to sign the certificate with. csr : str A valid CSR. The format is given by the ``csr_format`` parameter. expires : int When the certificate should expire (passed to :py:func:`~django_ca.utils.get_cert_builder`). algorithm : {'sha512', 'sha256', ...} Algorithm used to sign the certificate. The default is the CA_DIGEST_ALGORITHM setting. subject : dict, optional The Subject to use in the certificate. The keys of this dict are the fields of an X509 subject, that is `"C"`, `"ST"`, `"L"`, `"OU"` and `"CN"`. If ommited or if the value does not contain a `"CN"` key, the first value of the `subjectAltName` parameter is used as CommonName (and is obviously mandatory in this case). cn_in_san : bool, optional Wether the CommonName should also be included as subjectAlternativeName. The default is `True`, but the parameter is ignored if no CommonName is given. This is typically set to `False` when creating a client certificate, where the subjects CommonName has no meaningful value as subjectAltName. csr_format : :py:class:`~cryptography:cryptography.hazmat.primitives.serialization.Encoding`, optional The format of the CSR. The default is ``PEM``. subjectAltName : list of str, optional A list of values for the subjectAltName extension. Values are passed to :py:func:`~django_ca.utils.parse_general_name`, see function documentation for how this value is parsed. keyUsage : tuple or None Value for the `keyUsage` X509 extension. See description for format details. extendedKeyUsage : tuple or None Value for the `extendedKeyUsage` X509 extension. See description for format details. tls_features : tuple Value for the `TLS Feature` X509 extension. See description for format details. password : bytes, optional Password used to load the private key of the certificate authority. If not passed, the private key is assumed to be unencrypted. Returns ------- cryptography.x509.Certificate The signed certificate. """ if subject is None: subject = {} if not subject.get('CN') and not subjectAltName: raise ValueError("Must name at least a CN or a subjectAltName.") if subjectAltName: subjectAltName = [ parse_general_name(san) for san in subjectAltName ] else: subjectAltName = [] # so we can append the CN if requested if not subject.get('CN'): # use first SAN as CN if CN is not set subject['CN'] = subjectAltName[0].value elif cn_in_san and subject.get( 'CN'): # add CN to SAN if cn_in_san is True (default) try: cn_name = parse_general_name(subject['CN']) except idna.IDNAError: raise ValueError( '%s: Could not parse CommonName as subjectAltName.' % subject['CN']) else: if cn_name not in subjectAltName: subjectAltName.insert(0, cn_name) if csr_format == Encoding.PEM: req = x509.load_pem_x509_csr(force_bytes(csr), default_backend()) elif csr_format == Encoding.DER: req = x509.load_der_x509_csr(force_bytes(csr), default_backend()) else: raise ValueError('Unknown CSR format passed: %s' % csr_format) public_key = req.public_key() builder = get_cert_builder(expires) builder = builder.public_key(public_key) builder = builder.issuer_name(ca.x509.subject) builder = builder.subject_name(x509_name(subject)) # Add extensions builder = builder.add_extension(x509.BasicConstraints( ca=False, path_length=None), critical=True) builder = builder.add_extension( x509.SubjectKeyIdentifier.from_public_key(public_key), critical=False) # Get authorityKeyIdentifier from subjectKeyIdentifier from signing CA ca_subject_key_id = ca.x509.extensions.get_extension_for_oid( ExtensionOID.SUBJECT_KEY_IDENTIFIER) auth_key_id = x509.AuthorityKeyIdentifier( key_identifier=ca_subject_key_id.value.digest, authority_cert_issuer=None, authority_cert_serial_number=None) builder = builder.add_extension(auth_key_id, critical=False) for critical, ext in self.get_common_extensions( ca.issuer_url, ca.crl_url, ca.ocsp_url): builder = builder.add_extension(ext, critical=critical) if subjectAltName: builder = builder.add_extension( x509.SubjectAlternativeName(subjectAltName), critical=False) if keyUsage: critical, values = keyUsage params = {v: False for v in KEY_USAGE_MAPPING.values()} for value in [KEY_USAGE_MAPPING[k] for k in values.split(',')]: params[value] = True builder = builder.add_extension(x509.KeyUsage(**params), critical=critical) if extendedKeyUsage: critical, usages = extendedKeyUsage usages = [EXTENDED_KEY_USAGE_MAPPING[u] for u in usages.split(',')] builder = builder.add_extension(x509.ExtendedKeyUsage(usages), critical=critical) if tls_features: critical, features = tls_features features = [TLS_FEATURE_MAPPING[f] for f in features.split(',')] builder = builder.add_extension(TLSFeature(features), critical=critical) if ca.issuer_alt_name: builder = builder.add_extension(x509.IssuerAlternativeName( [parse_general_name(ca.issuer_alt_name)]), critical=False) return builder.sign(private_key=ca.key(password), algorithm=algorithm, backend=default_backend()), req
class TestCertificateRevocationListBuilder: def test_issuer_name_invalid(self): builder = x509.CertificateRevocationListBuilder() with pytest.raises(TypeError): builder.issuer_name("notanx509name") # type:ignore[arg-type] def test_set_issuer_name_twice(self): builder = x509.CertificateRevocationListBuilder().issuer_name( x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")])) with pytest.raises(ValueError): builder.issuer_name( x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")])) def test_aware_last_update(self, backend): last_time = datetime.datetime(2012, 1, 16, 22, 43) tz = pytz.timezone("US/Pacific") last_time = tz.localize(last_time) utc_last = datetime.datetime(2012, 1, 17, 6, 43) next_time = datetime.datetime(2022, 1, 17, 6, 43) private_key = RSA_KEY_2048.private_key(backend) builder = (x509.CertificateRevocationListBuilder().issuer_name( x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, "cryptography.io CA") ])).last_update(last_time).next_update(next_time)) crl = builder.sign(private_key, hashes.SHA256(), backend) assert crl.last_update == utc_last def test_last_update_invalid(self): builder = x509.CertificateRevocationListBuilder() with pytest.raises(TypeError): builder.last_update("notadatetime") # type:ignore[arg-type] def test_last_update_before_1950(self): builder = x509.CertificateRevocationListBuilder() with pytest.raises(ValueError): builder.last_update(datetime.datetime(1940, 8, 10)) def test_set_last_update_twice(self): builder = x509.CertificateRevocationListBuilder().last_update( datetime.datetime(2002, 1, 1, 12, 1)) with pytest.raises(ValueError): builder.last_update(datetime.datetime(2002, 1, 1, 12, 1)) def test_aware_next_update(self, backend): next_time = datetime.datetime(2022, 1, 16, 22, 43) tz = pytz.timezone("US/Pacific") next_time = tz.localize(next_time) utc_next = datetime.datetime(2022, 1, 17, 6, 43) last_time = datetime.datetime(2012, 1, 17, 6, 43) private_key = RSA_KEY_2048.private_key(backend) builder = (x509.CertificateRevocationListBuilder().issuer_name( x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, "cryptography.io CA") ])).last_update(last_time).next_update(next_time)) crl = builder.sign(private_key, hashes.SHA256(), backend) assert crl.next_update == utc_next def test_next_update_invalid(self): builder = x509.CertificateRevocationListBuilder() with pytest.raises(TypeError): builder.next_update("notadatetime") # type:ignore[arg-type] def test_next_update_before_1950(self): builder = x509.CertificateRevocationListBuilder() with pytest.raises(ValueError): builder.next_update(datetime.datetime(1940, 8, 10)) def test_set_next_update_twice(self): builder = x509.CertificateRevocationListBuilder().next_update( datetime.datetime(2002, 1, 1, 12, 1)) with pytest.raises(ValueError): builder.next_update(datetime.datetime(2002, 1, 1, 12, 1)) def test_last_update_after_next_update(self): builder = x509.CertificateRevocationListBuilder() builder = builder.next_update(datetime.datetime(2002, 1, 1, 12, 1)) with pytest.raises(ValueError): builder.last_update(datetime.datetime(2003, 1, 1, 12, 1)) def test_next_update_after_last_update(self): builder = x509.CertificateRevocationListBuilder() builder = builder.last_update(datetime.datetime(2002, 1, 1, 12, 1)) with pytest.raises(ValueError): builder.next_update(datetime.datetime(2001, 1, 1, 12, 1)) def test_add_extension_checks_for_duplicates(self): builder = x509.CertificateRevocationListBuilder().add_extension( x509.CRLNumber(1), False) with pytest.raises(ValueError): builder.add_extension(x509.CRLNumber(2), False) def test_add_invalid_extension(self): builder = x509.CertificateRevocationListBuilder() with pytest.raises(TypeError): builder.add_extension(object(), False) # type:ignore[arg-type] def test_add_invalid_revoked_certificate(self): builder = x509.CertificateRevocationListBuilder() with pytest.raises(TypeError): builder.add_revoked_certificate(object()) # type:ignore[arg-type] def test_no_issuer_name(self, backend): private_key = RSA_KEY_2048.private_key(backend) builder = (x509.CertificateRevocationListBuilder().last_update( datetime.datetime(2002, 1, 1, 12, 1)).next_update( datetime.datetime(2030, 1, 1, 12, 1))) with pytest.raises(ValueError): builder.sign(private_key, hashes.SHA256(), backend) def test_no_last_update(self, backend): private_key = RSA_KEY_2048.private_key(backend) builder = (x509.CertificateRevocationListBuilder().issuer_name( x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US") ])).next_update(datetime.datetime(2030, 1, 1, 12, 1))) with pytest.raises(ValueError): builder.sign(private_key, hashes.SHA256(), backend) def test_no_next_update(self, backend): private_key = RSA_KEY_2048.private_key(backend) builder = (x509.CertificateRevocationListBuilder().issuer_name( x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US") ])).last_update(datetime.datetime(2030, 1, 1, 12, 1))) with pytest.raises(ValueError): builder.sign(private_key, hashes.SHA256(), backend) def test_sign_empty_list(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)) crl = builder.sign(private_key, hashes.SHA256(), backend) assert len(crl) == 0 assert crl.last_update == last_update assert crl.next_update == next_update @pytest.mark.parametrize( "extension", [ x509.CRLNumber(13), x509.DeltaCRLIndicator(12345678901234567890), x509.AuthorityKeyIdentifier( b"\xc3\x9c\xf3\xfc\xd3F\x084\xbb\xceF\x7f\xa0|[\xf3\xe2\x08" b"\xcbY", None, None, ), x509.AuthorityInformationAccess([ x509.AccessDescription( AuthorityInformationAccessOID.CA_ISSUERS, x509.DNSName("cryptography.io"), ) ]), x509.IssuerAlternativeName( [x509.UniformResourceIdentifier("https://cryptography.io")]), ], ) def test_sign_extensions(self, backend, extension): 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_extension(extension, False)) crl = builder.sign(private_key, hashes.SHA256(), backend) assert len(crl) == 0 assert len(crl.extensions) == 1 ext = crl.extensions.get_extension_for_class(type(extension)) assert ext.critical is False assert ext.value == extension def test_sign_multiple_extensions_critical(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) ian = x509.IssuerAlternativeName( [x509.UniformResourceIdentifier("https://cryptography.io")]) crl_number = x509.CRLNumber(13) builder = (x509.CertificateRevocationListBuilder().issuer_name( x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, "cryptography.io CA") ])).last_update(last_update).next_update( next_update).add_extension(crl_number, False).add_extension(ian, True)) crl = builder.sign(private_key, hashes.SHA256(), backend) assert len(crl) == 0 assert len(crl.extensions) == 2 ext1 = crl.extensions.get_extension_for_class(x509.CRLNumber) assert ext1.critical is False assert ext1.value == crl_number ext2 = crl.extensions.get_extension_for_class( x509.IssuerAlternativeName) assert ext2.critical is True assert ext2.value == ian def test_freshestcrl_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) freshest = x509.FreshestCRL([ x509.DistributionPoint( [x509.UniformResourceIdentifier("http://d.om/delta")], None, None, None, ) ]) builder = (x509.CertificateRevocationListBuilder().issuer_name( x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, "cryptography.io CA") ])).last_update(last_update).next_update( next_update).add_extension(freshest, False)) crl = builder.sign(private_key, hashes.SHA256(), backend) assert len(crl) == 0 assert len(crl.extensions) == 1 ext1 = crl.extensions.get_extension_for_class(x509.FreshestCRL) assert ext1.critical is False assert isinstance(ext1.value, x509.FreshestCRL) assert isinstance(ext1.value[0], x509.DistributionPoint) assert ext1.value[0].full_name is not None uri = ext1.value[0].full_name[0] assert isinstance(uri, x509.UniformResourceIdentifier) assert uri.value == "http://d.om/delta" def test_add_unsupported_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_extension(DummyExtension(), False)) with pytest.raises(NotImplementedError): builder.sign(private_key, hashes.SHA256(), 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_sign_rsa_key_too_small(self, backend): private_key = RSA_KEY_512.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)) with pytest.raises(ValueError): builder.sign(private_key, hashes.SHA512(), backend) def test_sign_with_invalid_hash(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)) with pytest.raises(TypeError): builder.sign( private_key, object(), backend # type: ignore[arg-type] ) @pytest.mark.supported( only_if=lambda backend: backend.ed25519_supported(), skip_message="Requires OpenSSL with Ed25519 support", ) def test_sign_with_invalid_hash_ed25519(self, backend): private_key = ed25519.Ed25519PrivateKey.generate() 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)) with pytest.raises(TypeError): builder.sign( private_key, object(), # type:ignore[arg-type] backend, ) with pytest.raises(ValueError): builder.sign(private_key, hashes.SHA256(), backend) @pytest.mark.supported( only_if=lambda backend: backend.ed448_supported(), skip_message="Requires OpenSSL with Ed448 support", ) def test_sign_with_invalid_hash_ed448(self, backend): private_key = ed448.Ed448PrivateKey.generate() 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)) with pytest.raises(TypeError): builder.sign( private_key, object(), # type:ignore[arg-type] backend, ) with pytest.raises(ValueError): builder.sign(private_key, hashes.SHA256(), backend) def test_sign_dsa_key(self, backend): private_key = DSA_KEY_2048.private_key(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 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 @pytest.mark.supported( only_if=lambda backend: backend.ed25519_supported(), skip_message="Requires OpenSSL with Ed25519 support", ) def test_sign_ed25519_key(self, backend): private_key = ed25519.Ed25519PrivateKey.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.ED25519 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 @pytest.mark.supported( only_if=lambda backend: backend.ed448_supported(), skip_message="Requires OpenSSL with Ed448 support", ) 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_dsa_key_sign_md5(self, backend): private_key = DSA_KEY_2048.private_key(backend) last_time = datetime.datetime(2012, 1, 16, 22, 43) next_time = datetime.datetime(2022, 1, 17, 6, 43) builder = (x509.CertificateRevocationListBuilder().issuer_name( x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, "cryptography.io CA") ])).last_update(last_time).next_update(next_time)) with pytest.raises(ValueError): builder.sign(private_key, hashes.MD5(), backend) def test_ec_key_sign_md5(self, backend): _skip_curve_unsupported(backend, ec.SECP256R1()) private_key = EC_KEY_SECP256R1.private_key(backend) last_time = datetime.datetime(2012, 1, 16, 22, 43) next_time = datetime.datetime(2022, 1, 17, 6, 43) builder = (x509.CertificateRevocationListBuilder().issuer_name( x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, "cryptography.io CA") ])).last_update(last_time).next_update(next_time)) with pytest.raises(ValueError): builder.sign(private_key, hashes.MD5(), backend) 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).add_extension( x509.CRLReason(x509.ReasonFlags.ca_compromise), False).build(backend)) ci = x509.CertificateIssuer([x509.DNSName("cryptography.io")]) revoked_cert2 = ( x509.RevokedCertificateBuilder().serial_number(40).revocation_date( datetime.datetime(2011, 1, 1, 1, 1)).add_extension(ci, False).build(backend)) 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_revoked_certificate( revoked_cert1).add_revoked_certificate(revoked_cert2)) crl = builder.sign(private_key, hashes.SHA256(), backend) assert len(crl) == 3 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) == 2 ext = crl[1].extensions.get_extension_for_class(x509.InvalidityDate) assert ext.critical is False assert ext.value == invalidity_date assert (crl[2].extensions.get_extension_for_class( x509.CertificateIssuer).value == ci)
def extension_type(self) -> x509.IssuerAlternativeName: return x509.IssuerAlternativeName(self.value)
def generate_ca_cert(ca_crt: str, ca_key: str, organization: str, unit: str, locality: str, state: str, country: str, validity: int, key_length: int, verbose: bool): today = datetime.datetime.today() one_day = datetime.timedelta(days=1) one_year = datetime.timedelta(days=validity) ca_cn = f'CA-{uuid.uuid1()}' email = f'nobody@{ca_cn}' serial = x509.random_serial_number() name = x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, ca_cn), x509.NameAttribute(NameOID.ORGANIZATION_NAME, organization), x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, unit), x509.NameAttribute(NameOID.LOCALITY_NAME, locality), x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, state), x509.NameAttribute(NameOID.COUNTRY_NAME, country), x509.NameAttribute(NameOID.EMAIL_ADDRESS, email), ]) # Generate private key private_key = rsa.generate_private_key(public_exponent=65537, key_size=key_length, backend=default_backend()) # Generate public key public_key = private_key.public_key() builder = x509.CertificateBuilder() builder = builder.subject_name( x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, ca_cn), x509.NameAttribute(NameOID.ORGANIZATION_NAME, organization), x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, unit), x509.NameAttribute(NameOID.LOCALITY_NAME, locality), x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, state), x509.NameAttribute(NameOID.COUNTRY_NAME, country), x509.NameAttribute(NameOID.EMAIL_ADDRESS, email), ])) builder = builder.issuer_name(name) builder = builder.not_valid_before(today - one_day) builder = builder.not_valid_after(today + one_year) builder = builder.serial_number(serial) builder = builder.public_key(public_key) # X509v3 Basic Constraints builder = builder.add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True) # X509v3 Subject Key Identifier builder = builder.add_extension( x509.SubjectKeyIdentifier.from_public_key(public_key), critical=False) # X509v3 Authority Key Identifier ki = x509.SubjectKeyIdentifier.from_public_key(private_key.public_key()) builder = builder.add_extension(x509.AuthorityKeyIdentifier( key_identifier=ki.digest, authority_cert_issuer=[x509.DirectoryName(name)], authority_cert_serial_number=serial), critical=False) # X509v3 Key Usage: critical builder = builder.add_extension(x509.KeyUsage(digital_signature=True, key_encipherment=True, content_commitment=False, data_encipherment=False, key_agreement=False, encipher_only=False, decipher_only=False, key_cert_sign=True, crl_sign=False), critical=True) # X509v3 Extended Key Usage # ekus = [ExtendedKeyUsageOID.SERVER_AUTH, ExtendedKeyUsageOID.CLIENT_AUTH] # builder = builder.add_extension(x509.ExtendedKeyUsage(ekus), critical=False) # X509v3 Subject Alternative Name builder = builder.add_extension(x509.SubjectAlternativeName( [x509.DNSName(ca_cn)]), critical=False) # X509v3 Issuer Alternative Name builder = builder.add_extension(x509.IssuerAlternativeName( [x509.RFC822Name(email)]), critical=False) certificate = builder.sign(private_key=private_key, algorithm=hashes.SHA256(), backend=default_backend()) with Path(ca_key) as file: ca_key_bytes = private_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption()) file.write_bytes(ca_key_bytes) with Path(ca_crt) as file: ca_crt_bytes = certificate.public_bytes( encoding=serialization.Encoding.PEM) file.write_bytes(ca_crt_bytes)