diff --git a/lemur/certificates/schemas.py b/lemur/certificates/schemas.py index 64cc487f..f4a6fa9a 100644 --- a/lemur/certificates/schemas.py +++ b/lemur/certificates/schemas.py @@ -112,10 +112,20 @@ class CertificateInputSchema(CertificateCreationSchema): if data.get('replacements'): data['replaces'] = data['replacements'] # TODO remove when field is deprecated if data.get('csr'): - dns_names = cert_utils.get_dns_names_from_csr(data['csr']) - if not data['extensions']['subAltNames']['names']: + csr_sans = cert_utils.get_sans_from_csr(data['csr']) + if not data.get('extensions'): + data['extensions'] = { + 'subAltNames': { + 'names': [] + } + } + elif not data['extensions'].get('subAltNames'): + data['extensions']['subAltNames'] = { + 'names': [] + } + elif not data['extensions']['subAltNames'].get('names'): data['extensions']['subAltNames']['names'] = [] - data['extensions']['subAltNames']['names'] += dns_names + data['extensions']['subAltNames']['names'] += csr_sans return missing.convert_validity_years(data) diff --git a/lemur/certificates/utils.py b/lemur/certificates/utils.py index 933fe45e..800e1201 100644 --- a/lemur/certificates/utils.py +++ b/lemur/certificates/utils.py @@ -14,14 +14,14 @@ from cryptography.hazmat.backends import default_backend from marshmallow.exceptions import ValidationError -def get_dns_names_from_csr(data): +def get_sans_from_csr(data): """ - Fetches DNSNames from CSR. - Potentially extendable to any kind of SubjectAlternativeName + Fetches SubjectAlternativeNames from CSR. + Works with any kind of SubjectAlternativeName :param data: PEM-encoded string with CSR - :return: + :return: List of LemurAPI-compatible subAltNames """ - dns_names = [] + sub_alt_names = [] try: request = x509.load_pem_x509_csr(data.encode('utf-8'), default_backend()) except Exception: @@ -29,14 +29,12 @@ def get_dns_names_from_csr(data): try: alt_names = request.extensions.get_extension_for_class(x509.SubjectAlternativeName) - - for name in alt_names.value.get_values_for_type(x509.DNSName): - dns_name = { - 'nameType': 'DNSName', - 'value': name - } - dns_names.append(dns_name) + for alt_name in alt_names.value: + sub_alt_names.append({ + 'nameType': type(alt_name).__name__, + 'value': alt_name.value + }) except x509.ExtensionNotFound: pass - return dns_names + return sub_alt_names diff --git a/lemur/tests/test_certificates.py b/lemur/tests/test_certificates.py index d6e6a7e8..cc8a5224 100644 --- a/lemur/tests/test_certificates.py +++ b/lemur/tests/test_certificates.py @@ -284,6 +284,31 @@ def test_certificate_input_with_extensions(client, authority): assert not errors +def test_certificate_input_schema_parse_csr(authority): + from lemur.certificates.schemas import CertificateInputSchema + + test_san_dns = 'foobar.com' + extensions = {'sub_alt_names': {'names': x509.SubjectAlternativeName([x509.DNSName(test_san_dns)])}} + csr, private_key = create_csr(owner='joe@example.com', common_name='ACommonName', organization='test', + organizational_unit='Meters', country='NL', state='Noord-Holland', location='Amsterdam', + key_type='RSA2048', extensions=extensions) + + input_data = { + 'commonName': 'test.example.com', + 'owner': 'jim@example.com', + 'authority': {'id': authority.id}, + 'description': 'testtestest', + 'csr': csr, + 'dnsProvider': None, + } + + data, errors = CertificateInputSchema().load(input_data) + + for san in data['extensions']['sub_alt_names']['names']: + assert san.value == test_san_dns + assert not errors + + def test_certificate_out_of_range_date(client, authority): from lemur.certificates.schemas import CertificateInputSchema input_data = {