From 6249bb8ea46a565dfdd35a702349ef91b7a930f2 Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Tue, 5 Mar 2019 00:09:48 +0100 Subject: [PATCH] openssl_certificate: make sure extensions are present when they are queried by assertonly (#53207) * Make sure extensions are present when they are queried by assertonly provider. * Add changelog. --- ...nssl_certificate-assertonly-extensions.yml | 2 + .../modules/crypto/openssl_certificate.py | 12 ++++ .../openssl_certificate/tasks/assertonly.yml | 56 +++++++++++++++++++ .../openssl_certificate/tasks/main.yml | 2 + 4 files changed, 72 insertions(+) create mode 100644 changelogs/fragments/53207-openssl_certificate-assertonly-extensions.yml create mode 100644 test/integration/targets/openssl_certificate/tasks/assertonly.yml diff --git a/changelogs/fragments/53207-openssl_certificate-assertonly-extensions.yml b/changelogs/fragments/53207-openssl_certificate-assertonly-extensions.yml new file mode 100644 index 00000000000..4f52bdf746d --- /dev/null +++ b/changelogs/fragments/53207-openssl_certificate-assertonly-extensions.yml @@ -0,0 +1,2 @@ +bugfixes: +- "openssl_certificate - make sure that extensions are actually present when their values should be checked." diff --git a/lib/ansible/modules/crypto/openssl_certificate.py b/lib/ansible/modules/crypto/openssl_certificate.py index d6f1a4ccbc5..9ac0306bb94 100644 --- a/lib/ansible/modules/crypto/openssl_certificate.py +++ b/lib/ansible/modules/crypto/openssl_certificate.py @@ -886,9 +886,11 @@ class AssertOnlyCertificate(Certificate): def _validate_keyUsage(): if self.keyUsage: + found = False for extension_idx in range(0, self.cert.get_extension_count()): extension = self.cert.get_extension(extension_idx) if extension.get_short_name() == b'keyUsage': + found = True keyUsage = [OpenSSL._util.lib.OBJ_txt2nid(keyUsage) for keyUsage in self.keyUsage] current_ku = [OpenSSL._util.lib.OBJ_txt2nid(usage.strip()) for usage in to_bytes(extension, errors='surrogate_or_strict').split(b',')] @@ -897,12 +899,16 @@ class AssertOnlyCertificate(Certificate): self.message.append( 'Invalid keyUsage component (got %s, expected all of %s to be present)' % (str(extension).split(', '), self.keyUsage) ) + if not found: + self.message.append('Found no keyUsage extension') def _validate_extendedKeyUsage(): if self.extendedKeyUsage: + found = False for extension_idx in range(0, self.cert.get_extension_count()): extension = self.cert.get_extension(extension_idx) if extension.get_short_name() == b'extendedKeyUsage': + found = True extKeyUsage = [OpenSSL._util.lib.OBJ_txt2nid(keyUsage) for keyUsage in self.extendedKeyUsage] current_xku = [OpenSSL._util.lib.OBJ_txt2nid(usage.strip()) for usage in to_bytes(extension, errors='surrogate_or_strict').split(b',')] @@ -912,12 +918,16 @@ class AssertOnlyCertificate(Certificate): 'Invalid extendedKeyUsage component (got %s, expected all of %s to be present)' % (str(extension).split(', '), self.extendedKeyUsage) ) + if not found: + self.message.append('Found no extendedKeyUsage extension') def _validate_subjectAltName(): if self.subjectAltName: + found = False for extension_idx in range(0, self.cert.get_extension_count()): extension = self.cert.get_extension(extension_idx) if extension.get_short_name() == b'subjectAltName': + found = True l_altnames = [altname.replace(b'IP Address', b'IP') for altname in to_bytes(extension, errors='surrogate_or_strict').split(b', ')] if (not self.subjectAltName_strict and not all(x in l_altnames for x in self.subjectAltName)) or \ @@ -925,6 +935,8 @@ class AssertOnlyCertificate(Certificate): self.message.append( 'Invalid subjectAltName component (got %s, expected all of %s to be present)' % (l_altnames, self.subjectAltName) ) + if not found: + self.message.append('Found no subjectAltName extension') def _validate_notBefore(): if self.notBefore: diff --git a/test/integration/targets/openssl_certificate/tasks/assertonly.yml b/test/integration/targets/openssl_certificate/tasks/assertonly.yml new file mode 100644 index 00000000000..88df62d18e8 --- /dev/null +++ b/test/integration/targets/openssl_certificate/tasks/assertonly.yml @@ -0,0 +1,56 @@ +--- +- name: Generate privatekey + openssl_privatekey: + path: '{{ output_dir }}/privatekey.pem' + +- name: Generate CSR (no extensions) + openssl_csr: + path: '{{ output_dir }}/csr_noext.csr' + privatekey_path: '{{ output_dir }}/privatekey.pem' + subject: + commonName: www.example.com + useCommonNameForSAN: no + +- name: Generate selfsigned certificate (no extensions) + openssl_certificate: + path: '{{ output_dir }}/cert_noext.pem' + csr_path: '{{ output_dir }}/csr_noext.csr' + privatekey_path: '{{ output_dir }}/privatekey.pem' + provider: selfsigned + selfsigned_digest: sha256 + +- name: Assert that subject_alt_name is there (should fail) + openssl_certificate: + path: '{{ output_dir }}/cert_noext.pem' + provider: assertonly + subject_alt_name: + - "DNS:example.com" + ignore_errors: yes + register: extension_missing_san + +- name: Assert that key_usage is there (should fail) + openssl_certificate: + path: '{{ output_dir }}/cert_noext.pem' + provider: assertonly + key_usage: + - digitalSignature + ignore_errors: yes + register: extension_missing_ku + +- name: Assert that extended_key_usage is there (should fail) + openssl_certificate: + path: '{{ output_dir }}/cert_noext.pem' + provider: assertonly + extended_key_usage: + - biometricInfo + ignore_errors: yes + register: extension_missing_eku + +- assert: + that: + - extension_missing_san is failed + - "'Found no subjectAltName extension' in extension_missing_san.msg" + - extension_missing_ku is failed + - "'Found no keyUsage extension' in extension_missing_ku.msg" + - extension_missing_eku is failed + - "'Found no extendedKeyUsage extension' in extension_missing_eku.msg" diff --git a/test/integration/targets/openssl_certificate/tasks/main.yml b/test/integration/targets/openssl_certificate/tasks/main.yml index 5cbb5ee4b99..f8d6424cc9e 100644 --- a/test/integration/targets/openssl_certificate/tasks/main.yml +++ b/test/integration/targets/openssl_certificate/tasks/main.yml @@ -1,6 +1,8 @@ --- - block: + - import_tasks: assertonly.yml + - import_tasks: expired.yml - import_tasks: selfsigned.yml