def test_ocsp_cert_parent_is_not_intermediate_parent(self): ca = CertificateFactory(type=CertificateTypes.ROOT) ca.save() cert = CertificateFactory(type=CertificateTypes.OCSP, parent=ca, crl_distribution_url=None, ocsp_distribution_host=None) with self.assertRaises(ValidationError) as c: cert.save() self.assertEqual( c.exception.message, "OCSP certificate can only be generated for intermediate CA parent" )
def test_serialize_root_certificate(self): certificate_request = CertificateFactory() certhandler = Certificate() certhandler.create_certificate(certificate_request, self.key.serialize()) pem = certhandler.serialize() crt = certhandler.load(pem).certificate self.assert_basic_information(crt, certificate_request)
def root_ca_missing_attribute(self, dn, attribute_name): with self.assertRaises(PolicyError) as context: certificate_request = CertificateFactory(dn=dn) certhandler = Certificate() certhandler.create_certificate(certificate_request, self.key.serialize()) self.assertEqual( { f"dn__{attribute_name}": f"Attribute '{attribute_name}' is required" }, context.exception.args[0])
def test_generate_client_certificate(self): client_subject = DistinguishedNameFactory( subjectAltNames=["jeroen", "*****@*****.**"]) certificate = CertificateFactory(type=CertificateTypes.CLIENT_CERT, parent=self.int_certificate, dn=client_subject) certhandler = Certificate() certhandler.create_certificate(certificate, self.key.serialize()) crt = certhandler.certificate # basicConstraints = CA:FALSE # keyUsage = critical, digitalSignature, keyEncipherment self.assert_user_certificate(crt, content_commitment=True) # authorityKeyIdentifier = keyid:always, issuer self.assert_authority_key(crt, self.int_key, issuer_certificate=self.int_certificate, critical=False) # subjectKeyIdentifier = hash self.assert_hash(crt, critical=False) # extendedKeyUsage = clientAuth, emailProtection self.assert_extension( crt, ExtensionOID.EXTENDED_KEY_USAGE, [ ExtendedKeyUsageOID.CLIENT_AUTH, ExtendedKeyUsageOID.EMAIL_PROTECTION ], ) # subjectAltName = @alt_names self.assert_extension( crt, ExtensionOID.SUBJECT_ALTERNATIVE_NAME, [RFC822Name("jeroen"), RFC822Name("*****@*****.**")]) # crlDistributionPoints self.assert_crl_distribution(crt, self.int_certificate) # OCSP # authorityInfoAccess = OCSP;URI:{{cert.ocsp_distribution_host}} self.assert_oscp(crt, self.int_certificate) # subject self.assert_subject(crt.subject, certificate) # issuer self.assert_subject(crt.issuer, self.int_certificate)
def test_certificate_factory(self): cert = CertificateFactory() self.assertIsNotNone(cert.type) self.assertIsNotNone(cert.name) self.assertIsNotNone(cert.dn) self.assertIsNone(cert.parent) self.assertIsNotNone(cert.crl_distribution_url) self.assertIsNotNone(cert.ocsp_distribution_host) self.assertIsNotNone(cert.owner) self.assertIsNotNone(cert.serial) self.assertIsNotNone(cert.created_at) self.assertIsNotNone(cert.expires_at) self.assertIsNone(cert.revoked_at) self.assertIsNotNone(cert.revoked_uuid)
def test_passphrase_out_not_matching(self): cert = CertificateFactory(type=CertificateTypes.ROOT) cert.passphrase_out = "test" cert.passphrase_out_confirmation = "test2" with self.assertRaises(ValidationError) as c: cert.save() self.assertEqual(c.exception.message, "The two passphrase fields didn't match.")
def test_generate_server_certificate_minimal(self): server_subject = DistinguishedNameFactory( countryName=None, stateOrProvinceName=None, localityName=None, organizationName=None, organizationalUnitName=None, emailAddress=None, subjectAltNames=None, ) certificate = CertificateFactory( type=CertificateTypes.SERVER_CERT, name="test_generate_server_certificate_minimal", parent=self.int_certificate, dn=server_subject, ) certhandler = Certificate() certhandler.create_certificate(certificate, self.key.serialize()) crt = certhandler.certificate # basicConstraints = CA:FALSE # keyUsage = critical, digitalSignature, keyEncipherment self.assert_user_certificate(crt) # authorityKeyIdentifier = keyid:always, issuer self.assert_authority_key(crt, self.int_key, issuer_certificate=self.int_certificate, critical=False) # subjectKeyIdentifier = hash self.assert_hash(crt, critical=False) # extendedKeyUsage = serverAuth self.assert_extension(crt, ExtensionOID.EXTENDED_KEY_USAGE, [ExtendedKeyUsageOID.SERVER_AUTH]) # crlDistributionPoints self.assert_crl_distribution(crt, self.int_certificate) # OCSP # authorityInfoAccess = OCSP;URI:{{cert.ocsp_distribution_host}} self.assert_oscp(crt, self.int_certificate) # subject self.assert_subject(crt.subject, certificate) # issuer self.assert_subject(crt.issuer, self.int_certificate)
def test_generate_server_certificate_no_parent(self): server_subject = DistinguishedNameFactory() with self.assertRaises(CertificateError) as context: certificate_request = CertificateFactory( type=CertificateTypes.SERVER_CERT, name="test_generate_server_certificate_no_parent", parent=None, dn=server_subject, ) certhandler = Certificate() certhandler.create_certificate(certificate_request, self.key.serialize()) self.assertEqual("A parent certificate is expected", str(context.exception))
def test_child_expire_date_exceeds_parent_expire_date(self): dn_ca = DistinguishedNameFactory( countryName="NL", stateOrProvinceName="Noord-Holland", localityName="Amsterdam", organizationName="Repleo", organizationalUnitName="IT Department", emailAddress="*****@*****.**", commonName="test.bounca.org", subjectAltNames=["demo.bounca.org"], ) dn_im = DistinguishedNameFactory( countryName="NL", stateOrProvinceName="Noord-Holland", localityName="Amsterdam", organizationName="Repleo", organizationalUnitName="IT Department", emailAddress="*****@*****.**", commonName="test.bounca.org", subjectAltNames=["demo.bounca.org"], ) ca = CertificateFactory(type=CertificateTypes.ROOT, dn=dn_ca) ca.expires_at = arrow.get(timezone.now()).shift(years=+10).date() ca.save() cert = CertificateFactory(type=CertificateTypes.INTERMEDIATE, parent=ca, dn=dn_im) cert.expires_at = arrow.get(timezone.now()).shift(years=+20).date() with self.assertRaises(ValidationError) as c: cert.save() self.assertEqual( c.exception.message, "Child Certificate (expire date: {}) should not " "expire later than parent CA (expire date: {})".format( cert.expires_at, ca.expires_at), )
def test_generate_intermediate_certificate_minimal(self): key = Key().create_key("rsa", 4096) subject = DistinguishedNameFactory( organizationalUnitName=None, emailAddress=None, localityName=None, countryName=self.root_certificate.dn.countryName, stateOrProvinceName=self.root_certificate.dn.stateOrProvinceName, organizationName=self.root_certificate.dn.organizationName, ) certificate_request = CertificateFactory( type=CertificateTypes.INTERMEDIATE, name="test_generate_intermediate_certificate_minimal", parent=self.root_certificate, dn=subject, ) certificate_request.save() certhandler = Certificate() certhandler.create_certificate(certificate_request, key.serialize()) crt = certhandler.certificate self.assertEqual(crt.public_key().public_numbers(), key.key.public_key().public_numbers()) # subject self.assert_subject(crt.subject, certificate_request) self.assertListEqual([], crt.subject.get_attributes_for_oid( NameOID.LOCALITY_NAME)) # issuer self.assert_subject(crt.issuer, self.root_certificate) self.assertListEqual([], crt.subject.get_attributes_for_oid( NameOID.LOCALITY_NAME))
def test_parent_not_set(self): subject = DistinguishedNameFactory( countryName=self.root_certificate.dn.countryName, stateOrProvinceName=self.root_certificate.dn.stateOrProvinceName, organizationName=self.root_certificate.dn.organizationName, localityName=self.root_certificate.dn.localityName, ) certificate = CertificateFactory(type=CertificateTypes.INTERMEDIATE, name="test_parent_object_not_set", parent=None, dn=subject) with self.assertRaises(RuntimeError) as context: certhandler = Certificate() certhandler.create_certificate(certificate, self.key.serialize()) self.assertEqual("Parent certificate is required", str(context.exception))
def test_generate_server_certificate_no_subject_altnames(self): server_subject = DistinguishedNameFactory(subjectAltNames=None) certificate = CertificateFactory(type=CertificateTypes.SERVER_CERT, parent=self.int_certificate, dn=server_subject) certhandler = Certificate() certhandler.create_certificate(certificate, self.key.serialize()) crt = certhandler.certificate self.assertEqual(crt.serial_number, int(certificate.serial)) self.assertEqual(crt.public_key().public_numbers(), self.key.key.public_key().public_numbers()) with self.assertRaises(ExtensionNotFound): crt.extensions.get_extension_for_oid( ExtensionOID.SUBJECT_ALTERNATIVE_NAME)
def test_generate_client_certificate_no_intermediate_ca(self): client_subject = DistinguishedNameFactory(subjectAltNames=None) certificate = CertificateFactory(type=CertificateTypes.CLIENT_CERT, parent=self.root_certificate, dn=client_subject) certhandler = Certificate() certhandler.create_certificate(certificate, self.key.serialize()) crt = certhandler.certificate self.assertEqual(crt.serial_number, int(certificate.serial)) self.assertEqual( crt.public_key().public_bytes( encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw), self.key.key.public_key().public_bytes( encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw), ) # extendedKeyUsage = serverAuth self.assert_extension( crt, ExtensionOID.EXTENDED_KEY_USAGE, [ ExtendedKeyUsageOID.CLIENT_AUTH, ExtendedKeyUsageOID.EMAIL_PROTECTION ], ) # subject self.assert_subject(crt.subject, certificate) # issuer self.assert_subject(crt.issuer, self.root_certificate) # authorityKeyIdentifier = keyid:always, issuer self.assert_authority_key(crt, self.root_key, issuer_certificate=self.root_certificate, critical=False) # subjectKeyIdentifier = hash self.assert_hash(crt, critical=False)
def test_generate_root_ca_passphrase(self): certificate_request = CertificateFactory() certhandler = Certificate() certhandler.create_certificate( certificate_request, self.key.serialize(passphrase="superSecret"), passphrase="superSecret") crt = certhandler.certificate # subject self.assert_subject(crt.subject, certificate_request) # issuer self.assert_subject(crt.issuer, certificate_request) self.assert_root_authority(crt) self.assertEqual(crt.serial_number, int(certificate_request.serial)) self.assertEqual(crt.public_key().public_numbers(), self.key.key.public_key().public_numbers())
def test_days_valid(self): dn_ca = DistinguishedNameFactory( countryName="NL", stateOrProvinceName="Noord-Holland", localityName="Amsterdam", organizationName="Repleo", organizationalUnitName="IT Department", emailAddress="*****@*****.**", commonName="test.bounca.org", subjectAltNames=["demo.bounca.org"], ) cert = CertificateFactory(dn=dn_ca, type=CertificateTypes.ROOT) cert.expires_at = arrow.get(timezone.now()).shift(years=+10).date() self.assertEqual(cert.days_valid, 3652) cert.save() cert.refresh_from_db() self.assertEqual(cert.days_valid, 3652)
def make_server_certificate(self): server_subject = DistinguishedNameFactory(subjectAltNames=[ "www.repleo.nl", "*.bounca.org", "www.mac-usb-serial.com", "127.0.0.1" ]) certificate = CertificateFactory( type=CertificateTypes.SERVER_CERT, name="test_generate_server_certificate", parent=self.int_certificate, dn=server_subject, crl_distribution_url=None, ocsp_distribution_host=None, ) certhandler = Certificate() certhandler.create_certificate(certificate, self.key.serialize()) crt = certhandler.certificate return crt, crt.public_bytes( encoding=serialization.Encoding.PEM).decode("utf8")
def setUpTestData(cls): with mute_signals(signals.post_save): cls.root_key = Key().create_key("rsa", 4096) subject = DistinguishedNameFactory( countryName="NL", stateOrProvinceName="Noord Holland", organizationName="Repleo") cls.root_certificate = CertificateFactory( dn=subject, expires_at=arrow.get(timezone.now()).shift(days=+3).date()) cls.root_certificate.save() certificate = Certificate() key = cls.root_key.serialize() certificate.create_certificate(cls.root_certificate, key) keystore = KeyStore(certificate=cls.root_certificate) keystore.crt = certificate.serialize() keystore.key = key keystore.save() cls.key = Key().create_key("rsa", 4096)
def root_ca_not_matching_attribute(self, subject, attribute_name): with self.assertRaises(PolicyError) as context: certificate_request = CertificateFactory( type=CertificateTypes.INTERMEDIATE, name="root_ca_not_matching_attribute", parent=self.root_certificate, dn=subject, ) certhandler = Certificate() certhandler.create_certificate(certificate_request, self.key.serialize()) self.assertEqual( "Certificate should match field '{}' " "(issuer certificate: {}, certificate: {})".format( attribute_name, getattr(self.root_certificate.dn, attribute_name), getattr(subject, attribute_name)), str(context.exception), )
def test_generate_server_certificate_duplicate_commonname_root(self): server_subject = DistinguishedNameFactory( commonName=self.root_certificate.dn.commonName) with self.assertRaises(PolicyError) as context: certificate_request = CertificateFactory( type=CertificateTypes.SERVER_CERT, name="test_certificate_duplicate_commonName_root", parent=self.int_certificate, dn=server_subject, ) certhandler = Certificate() certhandler.create_certificate(certificate_request, self.key.serialize()) self.assertEqual( "CommonName '{}' should not be equal to common " "name of parent".format(self.root_certificate.dn.commonName), str(context.exception), )
def test_generate_ocsp_certificate(self): ocsp_subject = DistinguishedNameFactory(commonName="ocsp.example.com") certificate = CertificateFactory(type=CertificateTypes.OCSP, parent=self.int_certificate, dn=ocsp_subject) certhandler = Certificate() certhandler.create_certificate(certificate, self.key.serialize()) crt = certhandler.certificate # basicConstraints = CA:FALSE # keyUsage = critical, digitalSignature self.assert_ocsp_certificate(crt) # authorityKeyIdentifier = keyid:always, issuer self.assert_authority_key(crt, self.int_key, issuer_certificate=self.int_certificate, critical=False) # subjectKeyIdentifier = hash self.assert_hash(crt, critical=False) # extendedKeyUsage = critical, OCSPSigning self.assert_extension(crt, ExtensionOID.EXTENDED_KEY_USAGE, [ExtendedKeyUsageOID.OCSP_SIGNING], critical=True) # subject self.assert_subject(crt.subject, certificate) # issuer self.assert_subject(crt.issuer, self.int_certificate) # crlDistributionPoints self.assert_crl_distribution(crt, self.int_certificate) # OCSP # authorityInfoAccess = OCSP;URI:{{cert.ocsp_distribution_host}} self.assert_oscp(crt, self.int_certificate)
def test_generate_root_ca(self): subject = DistinguishedNameFactory( localityName="Amsterdam", organizationalUnitName="BounCA Root", ) certificate_request = CertificateFactory(dn=subject) certhandler = Certificate() certhandler.create_certificate(certificate_request, self.key.serialize()) crt = certhandler.certificate self.assert_basic_information(crt, certificate_request) # subject self.assert_subject(crt.subject, certificate_request) self.assertEqual( "Amsterdam", crt.subject.get_attributes_for_oid(NameOID.LOCALITY_NAME)[0].value) # issuer self.assert_subject(crt.issuer, certificate_request) self.assertEqual( "Amsterdam", crt.issuer.get_attributes_for_oid(NameOID.LOCALITY_NAME)[0].value) self.assert_subject(crt.issuer, certificate_request) self.assertEqual( "BounCA Root", crt.issuer.get_attributes_for_oid( NameOID.ORGANIZATIONAL_UNIT_NAME)[0].value) self.assert_root_authority(crt) # authorityKeyIdentifier = keyid:always, issuer self.assert_authority_key(crt, self.key) # subjectKeyIdentifier = hash self.assert_hash(crt)
def setUpTestData(cls): cls.root_key = Key().create_key("rsa", 4096) subject = DistinguishedNameFactory( countryName="NL", stateOrProvinceName="Noord Holland", organizationName="Repleo", commonName="BounCA test CA", ) cls.root_certificate = CertificateFactory( dn=subject, name="test_server_root_certificate", expires_at=arrow.get(timezone.now()).shift(days=+30).date()) with mute_signals(signals.post_save): cls.root_certificate.save() root_certhandler = Certificate() root_certhandler.create_certificate(cls.root_certificate, cls.root_key.serialize()) keystore = KeyStore(certificate=cls.root_certificate) keystore.crt = root_certhandler.serialize() keystore.key = cls.root_key.serialize() keystore.save()
def test_generate_intermediate_certificate_duplicate_commonName(self): subject = DistinguishedNameFactory( countryName=self.root_certificate.dn.countryName, stateOrProvinceName=self.root_certificate.dn.stateOrProvinceName, organizationName=self.root_certificate.dn.organizationName, commonName=self.root_certificate.dn.commonName, ) with self.assertRaises(PolicyError) as context: certificate_request = CertificateFactory( type=CertificateTypes.INTERMEDIATE, name="test_certificate_duplicate_commonName", parent=self.root_certificate, dn=subject, ) certhandler = Certificate() certhandler.create_certificate(certificate_request, self.key.serialize()) self.assertEqual( "CommonName '{}' should not be equal to common " "name of parent".format(self.root_certificate.dn.commonName), str(context.exception), )
def test_serialize_pkcs12_nopassphrase(self): subject = DistinguishedNameFactory( localityName="Amsterdam", organizationalUnitName="BounCA Root", ) key = Key() key.create_key("rsa", 4096) certificate_request = CertificateFactory(dn=subject) certhandler = Certificate() certhandler.create_certificate(certificate_request, key.serialize()) crt = certhandler.certificate pkcs12 = key.serialize_pkcs12("test_pkcs12", crt) pkcs12_obj = load_pkcs12(pkcs12, None) self.assertEqual(pkcs12_obj.key.key_size, 4096) self.assertEqual(pkcs12_obj.cert.friendly_name.decode("utf-8"), "test_pkcs12") self.assertEqual(pkcs12_obj.cert.certificate.serial_number, crt.serial_number)
def test_generate_client_certificate_no_subject_altnames(self): client_subject = DistinguishedNameFactory(subjectAltNames=None) certificate = CertificateFactory(type=CertificateTypes.CLIENT_CERT, parent=self.int_certificate, dn=client_subject) certhandler = Certificate() certhandler.create_certificate(certificate, self.key.serialize()) crt = certhandler.certificate self.assertEqual(crt.serial_number, int(certificate.serial)) self.assertEqual( crt.public_key().public_bytes( encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw), self.key.key.public_key().public_bytes( encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw), ) with self.assertRaises(ExtensionNotFound): crt.extensions.get_extension_for_oid( ExtensionOID.SUBJECT_ALTERNATIVE_NAME)
def test_set_name_to_common_name(self): dn_ca = DistinguishedNameFactory( countryName="NL", stateOrProvinceName="Noord-Holland", localityName="Amsterdam", organizationName="Repleo", organizationalUnitName="IT Department", emailAddress="*****@*****.**", commonName="test.bounca.org", subjectAltNames=["demo.bounca.org"], ) cert = CertificateFactory(name="", dn=dn_ca, type=CertificateTypes.ROOT) cert.save() cert.refresh_from_db() self.assertEqual(cert.name, cert.dn.commonName) self.assertEqual(cert.slug_name, "testbouncaorg")
def test_generate_root_ca_no_crl_distribution(self): certificate_request = CertificateFactory() certhandler = Certificate() certhandler.create_certificate(certificate_request, self.key.serialize()) crt = certhandler.certificate # subject self.assert_subject(crt.subject, certificate_request) # issuer self.assert_subject(crt.issuer, certificate_request) self.assert_root_authority(crt) self.assertEqual(crt.serial_number, int(certificate_request.serial)) self.assertEqual(crt.public_key().public_numbers(), self.key.key.public_key().public_numbers()) # crlDistributionspoints with self.assertRaisesMessage( ExtensionNotFound, "No <ObjectIdentifier(oid=2.5.29.31, name=c" "RLDistributionPoints)> extension was found"): crt.extensions.get_extension_for_oid( ExtensionOID.CRL_DISTRIBUTION_POINTS)
def test_generate_root_certificate_unique_violate_dn(self): dn_ca = DistinguishedNameFactory( countryName="NL", stateOrProvinceName="Noord-Holland", localityName="Amsterdam", organizationName="Repleo", organizationalUnitName="IT Department", emailAddress="*****@*****.**", commonName="test.bounca.org", subjectAltNames=["demo.bounca.org"], ) cert = CertificateFactory() cert.dn = dn_ca cert.type = CertificateTypes.ROOT cert.name = "repleo root ca 1" cert.save() cert = CertificateFactory() cert.dn = dn_ca cert.type = CertificateTypes.ROOT cert.name = "repleo root ca 2" with self.assertRaises(ValidationError): cert.save()
def test_serialize_pkcs12_cas_nopassphrase(self): root_key = Key().create_key("ed25519", None) subject = DistinguishedNameFactory(countryName="NL", stateOrProvinceName="Noord Holland", organizationName="Repleo") root_certificate = CertificateFactory( dn=subject, name="test_server_root_certificate", expires_at=arrow.get(timezone.now()).shift(days=+30).date()) with mute_signals(signals.post_save): root_certificate.save() root_certhandler = Certificate() root_certhandler.create_certificate(root_certificate, root_key.serialize()) keystore = KeyStore(certificate=root_certificate) keystore.crt = root_certhandler.serialize() keystore.key = root_key.serialize() keystore.save() int_key = Key().create_key("rsa", 2048) subject = DistinguishedNameFactory( countryName=root_certificate.dn.countryName, stateOrProvinceName=root_certificate.dn.stateOrProvinceName, organizationName=root_certificate.dn.organizationName, ) int_certificate = CertificateFactory( expires_at=arrow.get(timezone.now()).shift(days=+5).date(), name="test_server_intermediate_certificate", type=CertificateTypes.INTERMEDIATE, parent=root_certificate, dn=subject, crl_distribution_url="https://example.com/crl/cert.crl.pem", ocsp_distribution_host="https://example.com/ocsp/", ) with mute_signals(signals.post_save): int_certificate.save() int_certhandler = Certificate() int_certhandler.create_certificate(int_certificate, int_key.serialize()) keystore = KeyStore(certificate=int_certificate) keystore.crt = int_certhandler.serialize() keystore.key = int_key.serialize() keystore.save() pkcs12 = int_key.serialize_pkcs12("test_pkcs12_cas", int_certhandler.certificate, cas=[root_certhandler.certificate]) pkcs12_obj = load_pkcs12(pkcs12, None) self.assertEqual(pkcs12_obj.key.key_size, 2048) self.assertEqual(pkcs12_obj.cert.friendly_name.decode("utf-8"), "test_pkcs12_cas") self.assertEqual(pkcs12_obj.cert.certificate.serial_number, int_certhandler.certificate.serial_number) self.assertEqual( pkcs12_obj.additional_certs[0].certificate.serial_number, root_certhandler.certificate.serial_number)
def test_parent_intermediate_has_no_root_parent(self): cert = CertificateFactory(type=CertificateTypes.INTERMEDIATE) with self.assertRaises(ValidationError) as c: cert.save() self.assertEqual(c.exception.message, "Non Root certificate should have a parent")