From 9c07a8354e951171b288c4e71b2f39698192a4fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20S=C5=82owikowski?= <59068696+msl0@users.noreply.github.com> Date: Thu, 15 Jun 2023 12:51:14 +0200 Subject: [PATCH] Added support for certificates in DER format for `x509_certificate_info` module (#622) * Added support for DER format * Updated description * Adjusted description The content of the certificate cannot be in DER format due to an input encoding problem in the Ansible module, but it works fine when reading the certificate from a file * Update support.py * Added der_support_enabled flag for DER-format support * Added changelog fragment for #603 * Fixed typo * Fixed missing import * Resolved issues found by static code analysis * Update plugins/module_utils/crypto/support.py Committed suggested change Co-authored-by: Felix Fontein * Apply suggestions from code review Co-authored-by: Felix Fontein --------- Co-authored-by: Felix Fontein --- .../fragments/622-der-format-support.yml | 2 ++ .../module_backends/certificate_info.py | 4 +-- plugins/module_utils/crypto/support.py | 25 ++++++++++++++----- plugins/modules/x509_certificate_info.py | 3 ++- 4 files changed, 25 insertions(+), 9 deletions(-) create mode 100644 changelogs/fragments/622-der-format-support.yml diff --git a/changelogs/fragments/622-der-format-support.yml b/changelogs/fragments/622-der-format-support.yml new file mode 100644 index 00000000..b4ba93e6 --- /dev/null +++ b/changelogs/fragments/622-der-format-support.yml @@ -0,0 +1,2 @@ +minor_changes: + - "x509_certificate_info - added support for certificates in DER format when using ``path`` parameter (https://github.com/ansible-collections/community.crypto/issues/603)." diff --git a/plugins/module_utils/crypto/module_backends/certificate_info.py b/plugins/module_utils/crypto/module_backends/certificate_info.py index a7beec6c..b10733ce 100644 --- a/plugins/module_utils/crypto/module_backends/certificate_info.py +++ b/plugins/module_utils/crypto/module_backends/certificate_info.py @@ -143,9 +143,9 @@ class CertificateInfoRetrieval(object): def _get_issuer_uri(self): pass - def get_info(self, prefer_one_fingerprint=False): + def get_info(self, prefer_one_fingerprint=False, der_support_enabled=False): result = dict() - self.cert = load_certificate(None, content=self.content, backend=self.backend) + self.cert = load_certificate(None, content=self.content, backend=self.backend, der_support_enabled=der_support_enabled) result['signature_algorithm'] = self._get_signature_algorithm() subject = self._get_subject_ordered() diff --git a/plugins/module_utils/crypto/support.py b/plugins/module_utils/crypto/support.py index ad8f1610..473246b1 100644 --- a/plugins/module_utils/crypto/support.py +++ b/plugins/module_utils/crypto/support.py @@ -18,6 +18,10 @@ import re from ansible.module_utils import six from ansible.module_utils.common.text.converters import to_native, to_bytes +from ansible_collections.community.crypto.plugins.module_utils.crypto.pem import ( + identify_pem_format, +) + try: from OpenSSL import crypto HAS_PYOPENSSL = True @@ -189,7 +193,7 @@ def load_publickey(path=None, content=None, backend=None): raise OpenSSLObjectError('Error while deserializing key: {0}'.format(e)) -def load_certificate(path, content=None, backend='cryptography'): +def load_certificate(path, content=None, backend='cryptography', der_support_enabled=False): """Load the specified certificate.""" try: @@ -201,12 +205,21 @@ def load_certificate(path, content=None, backend='cryptography'): except (IOError, OSError) as exc: raise OpenSSLObjectError(exc) if backend == 'pyopenssl': - return crypto.load_certificate(crypto.FILETYPE_PEM, cert_content) + if der_support_enabled is False or identify_pem_format(cert_content): + return crypto.load_certificate(crypto.FILETYPE_PEM, cert_content) + elif der_support_enabled: + raise OpenSSLObjectError('Certificate in DER format is not supported by the pyopenssl backend.') elif backend == 'cryptography': - try: - return x509.load_pem_x509_certificate(cert_content, cryptography_backend()) - except ValueError as exc: - raise OpenSSLObjectError(exc) + if der_support_enabled is False or identify_pem_format(cert_content): + try: + return x509.load_pem_x509_certificate(cert_content, cryptography_backend()) + except ValueError as exc: + raise OpenSSLObjectError(exc) + elif der_support_enabled: + try: + return x509.load_der_x509_certificate(cert_content, cryptography_backend()) + except ValueError as exc: + raise OpenSSLObjectError('Cannot parse DER certificate: {0}'.format(exc)) def load_certificate_request(path, content=None, backend='cryptography'): diff --git a/plugins/modules/x509_certificate_info.py b/plugins/modules/x509_certificate_info.py index d875c572..145cd219 100644 --- a/plugins/modules/x509_certificate_info.py +++ b/plugins/modules/x509_certificate_info.py @@ -40,6 +40,7 @@ options: description: - Remote absolute path where the certificate file is loaded from. - Either I(path) or I(content) must be specified, but not both. + - PEM and DER formats are supported. type: path content: description: @@ -447,7 +448,7 @@ def main(): valid_at[k] = get_relative_time_option(v, 'valid_at.{0}'.format(k)) try: - result = module_backend.get_info() + result = module_backend.get_info(der_support_enabled=module.params['content'] is None) not_before = module_backend.get_not_before() not_after = module_backend.get_not_after()