def validate_cert_private_key_chain(self, data): cert = None key = None if data.get('body'): try: cert = utils.parse_certificate(data['body']) except ValueError: raise ValidationError("Public certificate presented is not valid.", field_names=['body']) if data.get('private_key'): try: key = utils.parse_private_key(data['private_key']) except ValueError: raise ValidationError("Private key presented is not valid.", field_names=['private_key']) if cert and key: # Throws ValidationError validators.verify_private_key_match(key, cert) if data.get('chain'): try: chain = utils.parse_cert_chain(data['chain']) except ValueError: raise ValidationError("Invalid certificate in certificate chain.", field_names=['chain']) # Throws ValidationError validators.verify_cert_chain([cert] + chain)
def validate_cert_private_key_chain(self, data): cert = None key = None if data.get("body"): try: cert = utils.parse_certificate(data["body"]) except ValueError: raise ValidationError( "Public certificate presented is not valid.", field_names=["body"]) if data.get("private_key"): try: key = utils.parse_private_key(data["private_key"]) except ValueError: raise ValidationError("Private key presented is not valid.", field_names=["private_key"]) if cert and key: # Throws ValidationError validators.verify_private_key_match(key, cert) if data.get("chain"): try: chain = utils.parse_cert_chain(data["chain"]) except ValueError: raise ValidationError( "Invalid certificate in certificate chain.", field_names=["chain"]) # Throws ValidationError validators.verify_cert_chain([cert] + chain)
def test_validate_private_key(session): key = parse_private_key(SAN_CERT_KEY) verify_private_key_match(key, SAN_CERT) with pytest.raises(ValidationError): # Wrong key for certificate verify_private_key_match(key, INTERMEDIATE_CERT)
def test_validate_private_key(session): key = parse_private_key(SAN_CERT_KEY) verify_private_key_match(key, SAN_CERT) with pytest.raises(ValidationError): # Wrong key for certificate verify_private_key_match(key, INTERMEDIATE_CERT)
def check_integrity(self): """ Integrity checks: Does the cert have a matching private key? """ if self.private_key: validators.verify_private_key_match(utils.parse_private_key( self.private_key), self.parsed_cert, error_class=AssertionError)
def create_keystore(cert, chain, key, alias, passphrase): certs_bytes = cert_chain_as_der(cert, chain) key_bytes = parse_private_key(key).private_bytes( encoding=serialization.Encoding.DER, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption()) entry = PrivateKeyEntry.new(alias, certs_bytes, key_bytes) return KeyStore.new('jks', [entry]).saves(passphrase)
def create_keystore(cert, chain, key, alias, passphrase): certs_bytes = cert_chain_as_der(cert, chain) key_bytes = parse_private_key(key).private_bytes( encoding=serialization.Encoding.DER, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption() ) entry = PrivateKeyEntry.new(alias, certs_bytes, key_bytes) return KeyStore.new('jks', [entry]).saves(passphrase)
def check_integrity(self): """ Integrity checks: Does the cert have a valid chain and matching private key? """ if self.private_key: validators.verify_private_key_match(utils.parse_private_key(self.private_key), self.parsed_cert, error_class=AssertionError) if self.chain: chain = [self.parsed_cert] + utils.parse_cert_chain(self.chain) validators.verify_cert_chain(chain, error_class=AssertionError)
def upload(self, name, body, private_key, cert_chain, options, **kwargs): """ Upload certificate and private key :param private_key: :param cert_chain: :return: """ # we use the common name to identify the certificate # Azure does not allow "." in the certificate name we replace them with "-" cert = parse_certificate(body) certificate_name = common_name(cert).replace(".", "-") vault_URI = self.get_option("vaultUrl", options) tenant = self.get_option("azureTenant", options) app_id = self.get_option("appID", options) password = self.get_option("azurePassword", options) access_token = get_access_token(tenant, app_id, password, self) cert_url = f"{vault_URI}/certificates/{certificate_name}/import?api-version=7.1" post_header = {"Authorization": f"Bearer {access_token}"} key_pkcs8 = parse_private_key(private_key).private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption(), ) key_pkcs8 = key_pkcs8.decode("utf-8").replace('\\n', '\n') cert_package = f"{body}\n{key_pkcs8}" post_body = { "value": cert_package, "policy": { "key_props": { "exportable": True, "kty": "RSA", "key_size": bitstrength(cert), "reuse_key": True }, "secret_props": { "contentType": "application/x-pem-file" } } } try: response = self.session.post(cert_url, headers=post_header, json=post_body) except requests.exceptions.RequestException as e: current_app.logger.exception(f"AZURE: Error for POST {e}") return_value = handle_response(response)
def check_integrity(self): """ Integrity checks: Does the cert have a valid chain and matching private key? """ if self.private_key: validators.verify_private_key_match(utils.parse_private_key( self.private_key), self.parsed_cert, error_class=AssertionError) if self.chain: chain = [self.parsed_cert] + utils.parse_cert_chain(self.chain) validators.verify_cert_chain(chain, error_class=AssertionError)
def validate_cert_private_key(self, data): cert = None key = None if data.get('body'): try: cert = utils.parse_certificate(data['body']) except ValueError: raise ValidationError( "Public certificate presented is not valid.", field_names=['body']) if data.get('private_key'): try: key = utils.parse_private_key(data['private_key']) except ValueError: raise ValidationError("Private key presented is not valid.", field_names=['private_key']) if cert and key: # Throws ValidationError validators.verify_private_key_match(key, cert)
def issuer_private_key(): return parse_private_key(INTERMEDIATE_KEY)
def private_key(): return parse_private_key(SAN_CERT_KEY)
def issue_certificate(csr, options, private_key=None): csr = x509.load_pem_x509_csr(csr.encode("utf-8"), default_backend()) if options.get("parent"): # creating intermediate authorities will have options['parent'] to specify the issuer # creating certificates will have options['authority'] to specify the issuer # This works around that by making sure options['authority'] can be referenced for either options["authority"] = options["parent"] if options.get("authority"): # Issue certificate signed by an existing lemur_certificates authority issuer_subject = options["authority"].authority_certificate.subject if not "parent" in options: assert ( private_key is None ), "Private would be ignored, authority key used instead" private_key = options["authority"].authority_certificate.private_key chain_cert_pem = options["authority"].authority_certificate.body authority_key_identifier_public = options[ "authority" ].authority_certificate.public_key authority_key_identifier_subject = x509.SubjectKeyIdentifier.from_public_key( authority_key_identifier_public ) authority_key_identifier_issuer = issuer_subject authority_key_identifier_serial = int( options["authority"].authority_certificate.serial ) # TODO figure out a better way to increment serial # New authorities have a value at options['serial_number'] that is being ignored here. serial = int(uuid.uuid4()) else: # Issue certificate that is self-signed (new lemur_certificates root authority) issuer_subject = csr.subject chain_cert_pem = "" authority_key_identifier_public = csr.public_key() authority_key_identifier_subject = None authority_key_identifier_issuer = csr.subject authority_key_identifier_serial = options["serial_number"] # TODO figure out a better way to increment serial serial = int(uuid.uuid4()) extensions = normalize_extensions(csr) builder = x509.CertificateBuilder( issuer_name=issuer_subject, subject_name=csr.subject, public_key=csr.public_key(), not_valid_before=options["validity_start"], not_valid_after=options["validity_end"], serial_number=serial, extensions=extensions, ) for k, v in options.get("extensions", {}).items(): if k == "authority_key_identifier": # One or both of these options may be present inside the aki extension (authority_key_identifier, authority_identifier) = (False, False) for k2, v2 in v.items(): if k2 == "use_key_identifier" and v2: authority_key_identifier = True if k2 == "use_authority_cert" and v2: authority_identifier = True if authority_key_identifier: if authority_key_identifier_subject: # FIXME in python-cryptography. # from_issuer_subject_key_identifier(cls, ski) is looking for ski.value.digest # but the digest of the ski is at just ski.digest. Until that library is fixed, # this function won't work. The second line has the same result. # aki = x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(authority_key_identifier_subject) aki = x509.AuthorityKeyIdentifier( authority_key_identifier_subject.digest, None, None ) else: aki = x509.AuthorityKeyIdentifier.from_issuer_public_key( authority_key_identifier_public ) elif authority_identifier: aki = x509.AuthorityKeyIdentifier( None, [x509.DirectoryName(authority_key_identifier_issuer)], authority_key_identifier_serial, ) builder = builder.add_extension(aki, critical=False) if k == "certificate_info_access": # FIXME: Implement the AuthorityInformationAccess extension # descriptions = [ # x509.AccessDescription(x509.oid.AuthorityInformationAccessOID.OCSP, x509.UniformResourceIdentifier(u"http://FIXME")), # x509.AccessDescription(x509.oid.AuthorityInformationAccessOID.CA_ISSUERS, x509.UniformResourceIdentifier(u"http://FIXME")) # ] # for k2, v2 in v.items(): # if k2 == 'include_aia' and v2 == True: # builder = builder.add_extension( # x509.AuthorityInformationAccess(descriptions), # critical=False # ) pass if k == "crl_distribution_points": # FIXME: Implement the CRLDistributionPoints extension # FIXME: Not implemented in lemur/schemas.py yet https://github.com/Netflix/lemur/issues/662 pass private_key = parse_private_key(private_key) cert = builder.sign(private_key, hashes.SHA256(), default_backend()) cert_pem = cert.public_bytes(encoding=serialization.Encoding.PEM).decode("utf-8") return cert_pem, chain_cert_pem
def test_private_key(session): parse_private_key(SAN_CERT_KEY) with pytest.raises(ValueError): parse_private_key('invalid_private_key')
def test_private_key(session): parse_private_key(SAN_CERT_KEY) with pytest.raises(ValueError): parse_private_key("invalid_private_key")
def issue_certificate(csr, options, private_key=None): csr = x509.load_pem_x509_csr(csr.encode('utf-8'), default_backend()) if options.get("parent"): # creating intermediate authorities will have options['parent'] to specify the issuer # creating certificates will have options['authority'] to specify the issuer # This works around that by making sure options['authority'] can be referenced for either options['authority'] = options['parent'] if options.get("authority"): # Issue certificate signed by an existing lemur_certificates authority issuer_subject = options['authority'].authority_certificate.subject assert private_key is None, "Private would be ignored, authority key used instead" private_key = options['authority'].authority_certificate.private_key chain_cert_pem = options['authority'].authority_certificate.body authority_key_identifier_public = options['authority'].authority_certificate.public_key authority_key_identifier_subject = x509.SubjectKeyIdentifier.from_public_key(authority_key_identifier_public) authority_key_identifier_issuer = issuer_subject authority_key_identifier_serial = int(options['authority'].authority_certificate.serial) # TODO figure out a better way to increment serial # New authorities have a value at options['serial_number'] that is being ignored here. serial = int(uuid.uuid4()) else: # Issue certificate that is self-signed (new lemur_certificates root authority) issuer_subject = csr.subject chain_cert_pem = "" authority_key_identifier_public = csr.public_key() authority_key_identifier_subject = None authority_key_identifier_issuer = csr.subject authority_key_identifier_serial = options['serial_number'] # TODO figure out a better way to increment serial serial = int(uuid.uuid4()) extensions = normalize_extensions(csr) builder = x509.CertificateBuilder( issuer_name=issuer_subject, subject_name=csr.subject, public_key=csr.public_key(), not_valid_before=options['validity_start'], not_valid_after=options['validity_end'], serial_number=serial, extensions=extensions) for k, v in options.get('extensions', {}).items(): if k == 'authority_key_identifier': # One or both of these options may be present inside the aki extension (authority_key_identifier, authority_identifier) = (False, False) for k2, v2 in v.items(): if k2 == 'use_key_identifier' and v2: authority_key_identifier = True if k2 == 'use_authority_cert' and v2: authority_identifier = True if authority_key_identifier: if authority_key_identifier_subject: # FIXME in python-cryptography. # from_issuer_subject_key_identifier(cls, ski) is looking for ski.value.digest # but the digest of the ski is at just ski.digest. Until that library is fixed, # this function won't work. The second line has the same result. # aki = x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(authority_key_identifier_subject) aki = x509.AuthorityKeyIdentifier(authority_key_identifier_subject.digest, None, None) else: aki = x509.AuthorityKeyIdentifier.from_issuer_public_key(authority_key_identifier_public) elif authority_identifier: aki = x509.AuthorityKeyIdentifier(None, [x509.DirectoryName(authority_key_identifier_issuer)], authority_key_identifier_serial) builder = builder.add_extension(aki, critical=False) if k == 'certificate_info_access': # FIXME: Implement the AuthorityInformationAccess extension # descriptions = [ # x509.AccessDescription(x509.oid.AuthorityInformationAccessOID.OCSP, x509.UniformResourceIdentifier(u"http://FIXME")), # x509.AccessDescription(x509.oid.AuthorityInformationAccessOID.CA_ISSUERS, x509.UniformResourceIdentifier(u"http://FIXME")) # ] # for k2, v2 in v.items(): # if k2 == 'include_aia' and v2 == True: # builder = builder.add_extension( # x509.AuthorityInformationAccess(descriptions), # critical=False # ) pass if k == 'crl_distribution_points': # FIXME: Implement the CRLDistributionPoints extension # FIXME: Not implemented in lemur/schemas.py yet https://github.com/Netflix/lemur/issues/662 pass private_key = parse_private_key(private_key) cert = builder.sign(private_key, hashes.SHA256(), default_backend()) cert_pem = cert.public_bytes( encoding=serialization.Encoding.PEM ).decode('utf-8') return cert_pem, chain_cert_pem