Fix issue with certificates with no subject or CN
This patch fixes an issue where if the user attempts to use a certificate that does not have a subject or CN, we would fail to create a listener using the certificate. Per the x.509 specification, a blank subject is allowed as long as the subjectAltName extension is present in the certificate. Octavia will now check for the a valid subAltName if the subject CN can not be retrieved. If both are missing an appropriate error is raised for the user. Closes-Bug: #2043582 Change-Id: I06911f42b9bf29cf9a5f2e76d8333d8a2f1bc60b
This commit is contained in:
parent
7310986de9
commit
73cdee503f
@ -133,6 +133,12 @@ class UnreadablePKCS12(APIException):
|
||||
code = 400
|
||||
|
||||
|
||||
class MissingCertSubject(APIException):
|
||||
msg = _('No CN or DNSName(s) found in certificate. The certificate is '
|
||||
'invalid.')
|
||||
code = 400
|
||||
|
||||
|
||||
class MisMatchedKey(OctaviaException):
|
||||
message = _("Key and x509 certificate do not match")
|
||||
|
||||
|
@ -256,14 +256,16 @@ def get_host_names(certificate):
|
||||
"""
|
||||
if isinstance(certificate, str):
|
||||
certificate = certificate.encode('utf-8')
|
||||
host_names = {'cn': None, 'dns_names': []}
|
||||
try:
|
||||
cert = x509.load_pem_x509_certificate(certificate,
|
||||
backends.default_backend())
|
||||
cn = cert.subject.get_attributes_for_oid(x509.OID_COMMON_NAME)[0]
|
||||
host_names = {
|
||||
'cn': cn.value.lower(),
|
||||
'dns_names': []
|
||||
}
|
||||
try:
|
||||
cn = cert.subject.get_attributes_for_oid(x509.OID_COMMON_NAME)[0]
|
||||
host_names['cn'] = cn.value.lower()
|
||||
except Exception as e:
|
||||
LOG.debug(f'Unable to get CN from certificate due to: {e}. '
|
||||
f'Assuming subject alternative names are present.')
|
||||
try:
|
||||
ext = cert.extensions.get_extension_for_oid(
|
||||
x509.OID_SUBJECT_ALTERNATIVE_NAME
|
||||
@ -274,7 +276,17 @@ def get_host_names(certificate):
|
||||
LOG.debug("%s extension not found",
|
||||
x509.OID_SUBJECT_ALTERNATIVE_NAME)
|
||||
|
||||
# Certs with no subject are valid as long as a subject alternative
|
||||
# name is present. If both are missing, it is an invalid cert per
|
||||
# the x.509 standard.
|
||||
if not host_names['cn'] and not host_names['dns_names']:
|
||||
LOG.warning('No CN or DNSName(s) found in certificate. The '
|
||||
'certificate is invalid.')
|
||||
raise exceptions.MissingCertSubject()
|
||||
|
||||
return host_names
|
||||
except exceptions.MissingCertSubject:
|
||||
raise
|
||||
except Exception as e:
|
||||
LOG.exception('Unreadable Certificate.')
|
||||
raise exceptions.UnreadableCert from e
|
||||
@ -359,6 +371,10 @@ def load_certificates_data(cert_mngr, obj, context=None):
|
||||
cert_mngr.get_cert(context,
|
||||
obj.tls_certificate_id,
|
||||
check_only=True))
|
||||
except exceptions.MissingCertSubject:
|
||||
# This was logged below, so raise as is to provide a clear
|
||||
# user error
|
||||
raise
|
||||
except Exception as e:
|
||||
LOG.warning('Unable to retrieve certificate: %s due to %s.',
|
||||
obj.tls_certificate_id, str(e))
|
||||
|
@ -872,3 +872,118 @@ phYuPfZekoNbsOIPDTiPFniuP2saOF4TSRCW4KnpgblRkds6c8X+1ExdlSo5GjNa
|
||||
PftOKlYtE7T7Kw4CI9+O2H38IUOYjDt/c2twy954K4pKe4x9Ud8mImpS/oEzOsoz
|
||||
/Mn++bjO55LdaAUKQ3wa8LZ5WFB+Gs6b2kmBfzGarWEiX64=
|
||||
-----END X509 CRL-----"""
|
||||
|
||||
# An invalid certificate due to no subject and no subjectAltName
|
||||
NOCN_NOSUBALT_CRT = b"""-----BEGIN CERTIFICATE-----
|
||||
MIIE4zCCAsugAwIBAgIUTo7POpWDLecy0B7fY2OAbLztmswwDQYJKoZIhvcNAQEL
|
||||
BQAwADAgFw0yMzExMjIyMjE4MzBaGA8yMTIzMTAyOTIyMTgzMFowADCCAiIwDQYJ
|
||||
KoZIhvcNAQEBBQADggIPADCCAgoCggIBAPClqkTqRyjlp+LXE4oElYGvg7y710yZ
|
||||
pR96TNqgugXxNLmIgzx2A3wWJ77z6qn3XoTFEXNnT6f4WrVr1Eh5/Zd1ioyj1r0G
|
||||
hIuEWMkm42UsTv+bId6BkXrr4wTgXgU+ss82dmRsYArV1b+c+89oYlEjQorhQ6eT
|
||||
2aWnt1XJbtpgRYCy5DsBKg1Iq63QRXp5svEr4iX+jAiDCQnBBLhrkfMUf8zuMCev
|
||||
Ij5119OGY5ihLuopIZi6OurA0fyN9e2MFlnYmWcxSZu49+6yBnXGmhmev3qzWj1+
|
||||
9DA50Pqu+NS9rVpYBNhhKuBTBxaTeZPDAl67DC2Mc8TFI1OfpiOwb+w/ewRYznry
|
||||
ZceASFovPFsAlUddwu/94sxgUSCmSE81Op+VlXS0LRgg8o/OZHp/eFsG2NM0OGAH
|
||||
v2uJly4OTPTd/kT50zViX3wJlRYIH+4szSjpbNXE0aF+cqQ56PBrGEe6j+SaGZEV
|
||||
6k4N9WMHNipffkq10N2d6fkRQjAD9B7gHOB6AAQ1mxoZtgchCKL7E8FuA803Yx8B
|
||||
a7h9J65SJq9nbr0z4eTscFZPulW8wMZT/ZeooQJJWqvA+g2FZf0dExk46gqU3F2F
|
||||
IRMvfGzSbIQF7bp/Yj4fLMUwLVaYv6NNdzhI+/eC0wVDWwbQ2rZkkvcvysSteGT4
|
||||
IDuFKuIWt4UnAgMBAAGjUzBRMB0GA1UdDgQWBBSEDhho9+R5JhsAZlQ0wU4Rjbqn
|
||||
OjAfBgNVHSMEGDAWgBSEDhho9+R5JhsAZlQ0wU4RjbqnOjAPBgNVHRMBAf8EBTAD
|
||||
AQH/MA0GCSqGSIb3DQEBCwUAA4ICAQAZ8E7l2H56z08yJiAa5DFmT8jmBHUCoJlM
|
||||
HiZSn04mtzZEfho/21Zdnb2Pa2SDrRkVXmrO+DebO5sK1Kn/EFC9P3SAOeZ3LB+m
|
||||
bJUX4WGEJ+7fv9uVRwSRfF21Lxo9QFgSVfQlQAhmXcKCE/8VtKB34oOZRhR8tAxH
|
||||
I4VvHUPyCT8ZwNhofP2TYHEjRi/4fsXueBH4kBHDy0/pyHMy1b5crWQAjlOhFXhW
|
||||
+qauSXkbIXNXd+wX23UF2uQ8YH819V7cHAidx9ikwn6HC5hxXjzMjViDwI451V6Q
|
||||
eAgrVuKTgx6cdnd2mgra8k7Bd2S+uTxwcrzVVzNfF+D2Al43xgeFF02M8Wp6ZDsh
|
||||
3/mJ7NOJGTJbXLRP+u73PEh1mGGU8H2QoGvaRO7R599sbmU4LedWX/VJc2GXojzF
|
||||
ibPWaMkKtX31QiOeNiLTMSkUWiyDTvzFW2ErqyzARv/yYFcEixEFl1GV8Bqb+ujj
|
||||
cxO5/y9cK6aM+qPb/FrXivXQsNArrpE3T1C54RvhUWOi+kyCiV/mDIG+oOp7sfZ5
|
||||
tBPenwWB2/LGS4rS67jZdwyIC5UbVySaVxtqJrdQXTRNjGfj2m963CHbiaQLSoSF
|
||||
2Zh2e8W4ixo6k6mhih2YjZVtpHrXyzNEtHT9HpPHDeElVcWteIceZMI2Ah0C6Ggj
|
||||
uTbEBYW85Q==
|
||||
-----END CERTIFICATE-----"""
|
||||
|
||||
# A certificate with no subject but with Subject Alternative Name
|
||||
NOCN_SUBALT_CRT = b"""-----BEGIN CERTIFICATE-----
|
||||
MIIFAjCCAuqgAwIBAgIUNjJqSdaJ9FsivfRHbXpdmcZgJR4wDQYJKoZIhvcNAQEL
|
||||
BQAwADAgFw0yMzExMzAyMTQyNTVaGA8yMTIzMTEwNjIxNDI1NVowADCCAiIwDQYJ
|
||||
KoZIhvcNAQEBBQADggIPADCCAgoCggIBAKA8+0iJzx51kTufmIpxGCM/KUFWdJ0U
|
||||
MmOPN1NmySNaj6nGI/Ix6m13A5SaezhbRlJvEwN7Hqg+tl+fqu0RgtQOXfBDMiJm
|
||||
+kAl0CQiOH7XU41P6fyk/QL8WF3VVGBtawTWn3x9Jw7Itd/zFr+aepQOj5LIwcx1
|
||||
ncHXreWdMLqDa7PpW1Ru6BW0FKVxX6WYQr2PI08nEIxu6DzLcaLHktRyNYg7r9X9
|
||||
a0tLZcp5MCBG3h3EtVgUkL9qw8q6acJpDGBF7ssRTNDf3QUSg0jrfzkD9WJCi631
|
||||
tefdAkDNIZXGZggbWsDGPseX4JG9p7WGzPx5QY2DkMqDJqi6FoS35tT+WNcY0n9V
|
||||
oBQXtXFV/AqOC070NwrhxsNA3cBbpRqEQYJsIDaXq0cmFR4aoDWk4OXqs7I+dpyi
|
||||
MFeRHEU7h4DpwzaOmOyaSmzsZqEMG2lsdJZmC+fIFkyKtP0BQv/movWY25oJSpF5
|
||||
4Q/PdwKn6PFO2bRVSLStlrhpuqXw2+CzlQT6YCAz+ajqDnn/w8NIrT6y+DiFd+kt
|
||||
WCed/o4ZBzsxOexRph+t0bdkTmR8PNpnHwcxzVN33gCSc6Q5DW1/M2V8VGYqnPd/
|
||||
taEaMlHm/wQ3y2/aH/tkyq85PM5tqCbUscD4TUZ7R6kb0k83Ak2iZOM5RHb4zc4p
|
||||
mreNKLPfgrQ7AgMBAAGjcjBwMB0GA1UdDgQWBBT6/yXwr+5BhORB3cUkrrSgnreq
|
||||
NTAfBgNVHSMEGDAWgBT6/yXwr+5BhORB3cUkrrSgnreqNTAPBgNVHRMBAf8EBTAD
|
||||
AQH/MB0GA1UdEQEB/wQTMBGCD3d3dy5leGFtcGxlLmNvbTANBgkqhkiG9w0BAQsF
|
||||
AAOCAgEAjxrBZ3v6wK7oZWvrzFV+aCs+KkoUkK0Y61TM4SCbWIT8oinN68nweha5
|
||||
p48Jp+hSBHEsj9h0opHezihduKh5IVM7KtbcXn1GSeN2hmyAAPm/MbxyD+l+UEfB
|
||||
G/behQcsYdVXXog7nwD2NXINvra8KGPqA7n/BnQ7RsxBXHVa9+IHF2L4LpbcvG7G
|
||||
Ci/jmLSBk7Gi/75TsFphHAhfomovfnnNykfJ0u99ew14MxVmRWbZ+rbpMsUL/AhV
|
||||
h8VujkfUs1hFbdxePTVyHwplqH65yjzzQ18q8CX7kMGi9sz2k8xJS04Nz0x1l7xQ
|
||||
JDuhFMDDrcyb7vAqG7BHQ9zXWJ3IkTg9WrbfkOyTqQsJeInToWQybmr/7lY3PmC2
|
||||
e/X0zNABF+ypX29RrKzWL+KfpbslysZIEPLEW28qAh3KOyml1du+lbDSNtcHxQcT
|
||||
bnvz2rQlAYE70Ds3znLLuMXbq8GtS+h8EYH1jxcjZD9DAPhxi37v8QSY/ABIBGE2
|
||||
lfbhbzZ5OWQLMA0L1tbTg7bG5JGoi/GmPl4oA+Dbz3+8Yd/v8XJUzQgI221tx+T+
|
||||
isog5o96m62pW6hd1R+eZjVAOVMT/OxecJ9eIVva8EiZwu1Ja9arBkuhIBVK2htm
|
||||
PVi6J1iFUrPZG+QrK/ZePo4xE06Lm31dr8pxdZ7Y860owwIuHfA=
|
||||
-----END CERTIFICATE-----"""
|
||||
|
||||
NOCN_SUBALT_KEY = b"""-----BEGIN PRIVATE KEY-----
|
||||
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
|
||||
SYVTfCHpvJIgjRkRMP2yZCk3g6T4XA==
|
||||
-----END PRIVATE KEY-----"""
|
||||
|
@ -1044,6 +1044,51 @@ class TestListener(base.BaseAPITest):
|
||||
self.assertEqual(constants.CLIENT_AUTH_NONE,
|
||||
listener_api.get('client_authentication'))
|
||||
|
||||
def test_create_tls_with_no_subject_no_alt_names(self):
|
||||
tls_cert_mock = mock.MagicMock()
|
||||
tls_cert_mock.get_certificate.return_value = (
|
||||
sample_certs.NOCN_NOSUBALT_CRT)
|
||||
self.cert_manager_mock().get_cert.return_value = tls_cert_mock
|
||||
|
||||
lb_listener = {'name': 'listener1-no-subject-no-alt-names',
|
||||
'default_pool_id': None,
|
||||
'description': 'desc1',
|
||||
'admin_state_up': False,
|
||||
'protocol': constants.PROTOCOL_TERMINATED_HTTPS,
|
||||
'protocol_port': 80, 'connection_limit': 10,
|
||||
'default_tls_container_ref': uuidutils.generate_uuid(),
|
||||
'insert_headers': {},
|
||||
'project_id': self.project_id,
|
||||
'loadbalancer_id': self.lb_id,
|
||||
'tags': ['test_tag']}
|
||||
body = self._build_body(lb_listener)
|
||||
response = self.post(self.LISTENERS_PATH, body, status=400)
|
||||
self.assertIn("No CN or DNSName", response)
|
||||
|
||||
def test_create_tls_with_no_subject_with_alt_names(self):
|
||||
tls_cert_mock = mock.MagicMock()
|
||||
tls_cert_mock.get_certificate.return_value = (
|
||||
sample_certs.NOCN_SUBALT_CRT)
|
||||
tls_cert_mock.get_private_key.return_value = (
|
||||
sample_certs.NOCN_SUBALT_KEY)
|
||||
tls_cert_mock.get_private_key_passphrase.return_value = None
|
||||
self.cert_manager_mock().get_cert.return_value = tls_cert_mock
|
||||
|
||||
lb_listener = {'name': 'listener1-no-subject',
|
||||
'default_pool_id': None,
|
||||
'description': 'desc1',
|
||||
'admin_state_up': False,
|
||||
'protocol': constants.PROTOCOL_TERMINATED_HTTPS,
|
||||
'protocol_port': 80, 'connection_limit': 10,
|
||||
'default_tls_container_ref': uuidutils.generate_uuid(),
|
||||
'insert_headers': {},
|
||||
'project_id': self.project_id,
|
||||
'loadbalancer_id': self.lb_id,
|
||||
'tags': ['test_tag']}
|
||||
body = self._build_body(lb_listener)
|
||||
response = self.post(self.LISTENERS_PATH, body, status=201)
|
||||
self.assertIn("PENDING_CREATE", response)
|
||||
|
||||
def test_create_with_ca_cert_and_option(self):
|
||||
self.cert_manager_mock().get_secret.return_value = (
|
||||
sample_certs.X509_CA_CERT)
|
||||
|
@ -0,0 +1,4 @@
|
||||
---
|
||||
fixes:
|
||||
- |
|
||||
Fixed an issue when using certificates with a blank subject or missing CN.
|
Loading…
x
Reference in New Issue
Block a user