diff --git a/.azure-pipelines/azure-pipelines.yml b/.azure-pipelines/azure-pipelines.yml index 54f2ef75..14d3af65 100644 --- a/.azure-pipelines/azure-pipelines.yml +++ b/.azure-pipelines/azure-pipelines.yml @@ -177,8 +177,6 @@ stages: test: centos6 - name: Fedora 31 test: fedora31 - - name: Ubuntu 16.04 - test: ubuntu1604 - stage: Docker_2_9 displayName: Docker 2.9 dependsOn: [] @@ -193,8 +191,8 @@ stages: test: centos7 - name: Fedora 31 test: fedora31 - - name: Ubuntu 16.04 - test: ubuntu1604 + - name: openSUSE 15 py3 + test: opensuse15 - name: Ubuntu 18.04 test: ubuntu1804 diff --git a/changelogs/fragments/273-pyopenssl-removal.yml b/changelogs/fragments/273-pyopenssl-removal.yml new file mode 100644 index 00000000..513b48d9 --- /dev/null +++ b/changelogs/fragments/273-pyopenssl-removal.yml @@ -0,0 +1,17 @@ +removed_features: + - "get_certificate - removed the ``pyopenssl`` backend (https://github.com/ansible-collections/community.crypto/pull/273)." + - "openssl_csr - removed the ``pyopenssl`` backend (https://github.com/ansible-collections/community.crypto/pull/273)." + - "openssl_csr_info - removed the ``pyopenssl`` backend (https://github.com/ansible-collections/community.crypto/pull/273)." + - "openssl_csr_pipe - removed the ``pyopenssl`` backend (https://github.com/ansible-collections/community.crypto/pull/273)." + - "openssl_privatekey - removed the ``pyopenssl`` backend (https://github.com/ansible-collections/community.crypto/pull/273)." + - "openssl_privatekey_info - removed the ``pyopenssl`` backend (https://github.com/ansible-collections/community.crypto/pull/273)." + - "openssl_privatekey_pipe - removed the ``pyopenssl`` backend (https://github.com/ansible-collections/community.crypto/pull/273)." + - "openssl_publickey - removed the ``pyopenssl`` backend (https://github.com/ansible-collections/community.crypto/pull/273)." + - "openssl_publickey_info - removed the ``pyopenssl`` backend (https://github.com/ansible-collections/community.crypto/pull/273)." + - "openssl_signature - removed the ``pyopenssl`` backend (https://github.com/ansible-collections/community.crypto/pull/273)." + - "openssl_signature_info - removed the ``pyopenssl`` backend (https://github.com/ansible-collections/community.crypto/pull/273)." + - "x509_certificate - removed the ``pyopenssl`` backend (https://github.com/ansible-collections/community.crypto/pull/273)." + - "x509_certificate_info - removed the ``pyopenssl`` backend (https://github.com/ansible-collections/community.crypto/pull/273)." + - "x509_certificate_pipe - removed the ``pyopenssl`` backend (https://github.com/ansible-collections/community.crypto/pull/273)." +breaking_changes: + - "module_utils - removed various PyOpenSSL support functions and default backend values that are not needed for the openssl_pkcs12 module (https://github.com/ansible-collections/community.crypto/pull/273)." diff --git a/plugins/doc_fragments/acme.py b/plugins/doc_fragments/acme.py index 7fbeb74f..049c4e0e 100644 --- a/plugins/doc_fragments/acme.py +++ b/plugins/doc_fragments/acme.py @@ -33,7 +33,7 @@ options: key." - "Private keys can be created with the M(community.crypto.openssl_privatekey) or M(community.crypto.openssl_privatekey_pipe) - modules. If the requisites (pyOpenSSL or cryptography) are not available, + modules. If the requisite (cryptography) is not available, keys can also be created directly with the C(openssl) command line tool: RSA keys can be created with C(openssl genrsa ...). Elliptic curve keys can be created with C(openssl ecparam -genkey ...). Any other tool creating diff --git a/plugins/doc_fragments/module_certificate.py b/plugins/doc_fragments/module_certificate.py index 2c565e65..1cbe3437 100644 --- a/plugins/doc_fragments/module_certificate.py +++ b/plugins/doc_fragments/module_certificate.py @@ -14,12 +14,9 @@ class ModuleDocFragment(object): DOCUMENTATION = r''' description: - This module allows one to (re)generate OpenSSL certificates. - - It uses the pyOpenSSL or cryptography python library to interact with OpenSSL. - - If both the cryptography and PyOpenSSL libraries are available (and meet the minimum version requirements) - cryptography will be preferred as a backend over PyOpenSSL (unless the backend is forced with C(select_crypto_backend)). - Please note that the PyOpenSSL backend was deprecated in Ansible 2.9 and will be removed in community.crypto 2.0.0. + - It uses the cryptography python library to interact with OpenSSL. requirements: - - PyOpenSSL >= 0.15 or cryptography >= 1.6 (if using C(selfsigned), C(ownca) or C(assertonly) provider) + - cryptography >= 1.6 (if using C(selfsigned), C(ownca) or C(assertonly) provider) options: force: description: @@ -58,14 +55,11 @@ options: select_crypto_backend: description: - Determines which crypto backend to use. - - The default choice is C(auto), which tries to use C(cryptography) if available, and falls back to C(pyopenssl). - - If set to C(pyopenssl), will try to use the L(pyOpenSSL,https://pypi.org/project/pyOpenSSL/) library. + - The default choice is C(auto), which tries to use C(cryptography) if available. - If set to C(cryptography), will try to use the L(cryptography,https://cryptography.io/) library. - - Please note that the C(pyopenssl) backend has been deprecated in Ansible 2.9, and will be removed in community.crypto 2.0.0. - From that point on, only the C(cryptography) backend will be available. type: str default: auto - choices: [ auto, cryptography, pyopenssl ] + choices: [ auto, cryptography ] notes: - All ASN.1 TIME values should be specified following the YYYYMMDDHHMMSSZ pattern. diff --git a/plugins/doc_fragments/module_csr.py b/plugins/doc_fragments/module_csr.py index b1f5d927..88124031 100644 --- a/plugins/doc_fragments/module_csr.py +++ b/plugins/doc_fragments/module_csr.py @@ -15,13 +15,8 @@ description: - This module allows one to (re)generate OpenSSL certificate signing requests. - This module supports the subjectAltName, keyUsage, extendedKeyUsage, basicConstraints and OCSP Must Staple extensions. - - "The module can use the cryptography Python library, or the pyOpenSSL Python - library. By default, it tries to detect which one is available. This can be - overridden with the I(select_crypto_backend) option. Please note that the - PyOpenSSL backend was deprecated in Ansible 2.9 and will be removed in community.crypto 2.0.0." requirements: - - Either cryptography >= 1.3 - - Or pyOpenSSL >= 0.15 + - cryptography >= 1.3 options: digest: description: @@ -196,14 +191,11 @@ options: select_crypto_backend: description: - Determines which crypto backend to use. - - The default choice is C(auto), which tries to use C(cryptography) if available, and falls back to C(pyopenssl). - - If set to C(pyopenssl), will try to use the L(pyOpenSSL,https://pypi.org/project/pyOpenSSL/) library. + - The default choice is C(auto), which tries to use C(cryptography) if available. - If set to C(cryptography), will try to use the L(cryptography,https://cryptography.io/) library. - - Please note that the C(pyopenssl) backend has been deprecated in Ansible 2.9, and will be removed in community.crypto 2.0.0. - From that point on, only the C(cryptography) backend will be available. type: str default: auto - choices: [ auto, cryptography, pyopenssl ] + choices: [ auto, cryptography ] create_subject_key_identifier: description: - Create the Subject Key Identifier from the public key. diff --git a/plugins/doc_fragments/module_privatekey.py b/plugins/doc_fragments/module_privatekey.py index d93ab7f4..1795a735 100644 --- a/plugins/doc_fragments/module_privatekey.py +++ b/plugins/doc_fragments/module_privatekey.py @@ -22,13 +22,8 @@ description: (or specify none), change the keysize, etc., the private key will be regenerated. If you are concerned that this could B(overwrite your private key), consider using the I(backup) option." - - "The module can use the cryptography Python library, or the pyOpenSSL Python - library. By default, it tries to detect which one is available. This can be - overridden with the I(select_crypto_backend) option. Please note that the - PyOpenSSL backend was deprecated in Ansible 2.9 and will be removed in community.crypto 2.0.0." requirements: - - Either cryptography >= 1.2.3 (older versions might work as well) - - Or pyOpenSSL + - cryptography >= 1.2.3 (older versions might work as well) options: size: description: @@ -80,22 +75,16 @@ options: type: str cipher: description: - - The cipher to encrypt the private key. (Valid values can be found by - running `openssl list -cipher-algorithms` or `openssl list-cipher-algorithms`, - depending on your OpenSSL version.) - - When using the C(cryptography) backend, use C(auto). + - The cipher to encrypt the private key. Must be C(auto). type: str select_crypto_backend: description: - Determines which crypto backend to use. - - The default choice is C(auto), which tries to use C(cryptography) if available, and falls back to C(pyopenssl). - - If set to C(pyopenssl), will try to use the L(pyOpenSSL,https://pypi.org/project/pyOpenSSL/) library. + - The default choice is C(auto), which tries to use C(cryptography) if available. - If set to C(cryptography), will try to use the L(cryptography,https://cryptography.io/) library. - - Please note that the C(pyopenssl) backend has been deprecated in Ansible 2.9, and will be removed in community.crypto 2.0.0. - From that point on, only the C(cryptography) backend will be available. type: str default: auto - choices: [ auto, cryptography, pyopenssl ] + choices: [ auto, cryptography ] format: description: - Determines which format the private key is written in. By default, PKCS1 (traditional OpenSSL format) @@ -105,8 +94,6 @@ options: selected one for generation. - Note that if the format for an existing private key mismatches, the key is B(regenerated) by default. To change this behavior, use the I(format_mismatch) option. - - The I(format) option is only supported by the C(cryptography) backend. The C(pyopenssl) backend will - fail if a value different from C(auto_ignore) is used. type: str default: auto_ignore choices: [ pkcs1, pkcs8, raw, auto, auto_ignore ] diff --git a/plugins/module_utils/crypto/__init__.py b/plugins/module_utils/crypto/__init__.py index 16b87dc6..d25f955f 100644 --- a/plugins/module_utils/crypto/__init__.py +++ b/plugins/module_utils/crypto/__init__.py @@ -25,7 +25,6 @@ __metaclass__ = type # please stop doing so. from .basic import ( - HAS_PYOPENSSL, CRYPTOGRAPHY_HAS_X25519, CRYPTOGRAPHY_HAS_X25519_FULL, CRYPTOGRAPHY_HAS_X448, @@ -74,12 +73,6 @@ from ._objects import OID_LOOKUP as _OID_LOOKUP from ._objects import NORMALIZE_NAMES as _NORMALIZE_NAMES from ._objects import NORMALIZE_NAMES_SHORT as _NORMALIZE_NAMES_SHORT -from .pyopenssl_support import ( - pyopenssl_normalize_name, - pyopenssl_get_extensions_from_cert, - pyopenssl_get_extensions_from_csr, -) - from .support import ( get_fingerprint_of_bytes, get_fingerprint, diff --git a/plugins/module_utils/crypto/basic.py b/plugins/module_utils/crypto/basic.py index 7ba8dcba..a7ebb3d2 100644 --- a/plugins/module_utils/crypto/basic.py +++ b/plugins/module_utils/crypto/basic.py @@ -22,14 +22,6 @@ __metaclass__ = type from distutils.version import LooseVersion -try: - import OpenSSL # noqa - from OpenSSL import crypto # noqa - HAS_PYOPENSSL = True -except ImportError: - # Error handled in the calling module. - HAS_PYOPENSSL = False - try: import cryptography from cryptography import x509 diff --git a/plugins/module_utils/crypto/module_backends/certificate.py b/plugins/module_utils/crypto/module_backends/certificate.py index dbf2936c..8c5bb33c 100644 --- a/plugins/module_utils/crypto/module_backends/certificate.py +++ b/plugins/module_utils/crypto/module_backends/certificate.py @@ -38,18 +38,6 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.module_bac ) MINIMAL_CRYPTOGRAPHY_VERSION = '1.6' -MINIMAL_PYOPENSSL_VERSION = '0.15' - -PYOPENSSL_IMP_ERR = None -try: - import OpenSSL - from OpenSSL import crypto - PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__) -except ImportError: - PYOPENSSL_IMP_ERR = traceback.format_exc() - PYOPENSSL_FOUND = False -else: - PYOPENSSL_FOUND = True CRYPTOGRAPHY_IMP_ERR = None CRYPTOGRAPHY_VERSION = None @@ -173,43 +161,12 @@ class CertificateBackend(object): def _check_privatekey(self): """Check whether provided parameters match, assuming self.existing_certificate and self.privatekey have been populated.""" - if self.backend == 'pyopenssl': - ctx = OpenSSL.SSL.Context(OpenSSL.SSL.TLSv1_2_METHOD) - ctx.use_privatekey(self.privatekey) - ctx.use_certificate(self.existing_certificate) - try: - ctx.check_privatekey() - return True - except OpenSSL.SSL.Error: - return False - elif self.backend == 'cryptography': + if self.backend == 'cryptography': return cryptography_compare_public_keys(self.existing_certificate.public_key(), self.privatekey.public_key()) def _check_csr(self): """Check whether provided parameters match, assuming self.existing_certificate and self.csr have been populated.""" - if self.backend == 'pyopenssl': - # Verify that CSR is signed by certificate's private key - try: - self.csr.verify(self.existing_certificate.get_pubkey()) - except OpenSSL.crypto.Error: - return False - # Check subject - if self.check_csr_subject and self.csr.get_subject() != self.existing_certificate.get_subject(): - return False - # Check extensions - if not self.check_csr_extensions: - return True - csr_extensions = self.csr.get_extensions() - cert_extension_count = self.existing_certificate.get_extension_count() - if len(csr_extensions) != cert_extension_count: - return False - for extension_number in range(0, cert_extension_count): - cert_extension = self.existing_certificate.get_extension(extension_number) - csr_extension = filter(lambda extension: extension.get_short_name() == cert_extension.get_short_name(), csr_extensions) - if cert_extension.get_data() != list(csr_extension)[0].get_data(): - return False - return True - elif self.backend == 'cryptography': + if self.backend == 'cryptography': # Verify that CSR is signed by certificate's private key if not self.csr.is_signature_valid: return False @@ -244,10 +201,6 @@ class CertificateBackend(object): def _check_subject_key_identifier(self): """Check whether Subject Key Identifier matches, assuming self.existing_certificate has been populated.""" - if self.backend != 'cryptography': - # We do not support SKI with pyOpenSSL backend - return True - # Get hold of certificate's SKI try: ext = self.existing_certificate.extensions.get_extension_for_class(x509.SubjectKeyIdentifier) @@ -328,10 +281,6 @@ class CertificateProvider(object): def needs_version_two_certs(self, module): """Whether the provider needs to create a version 2 certificate.""" - def needs_pyopenssl_get_extensions(self, module): - """Whether the provider needs to use get_extensions() with pyOpenSSL.""" - return True - @abc.abstractmethod def create_backend(self, module, backend): """Create an implementation for a backend. @@ -352,45 +301,22 @@ def select_backend(module, backend, provider): if backend == 'auto': # Detect what backend we can use can_use_cryptography = CRYPTOGRAPHY_FOUND and CRYPTOGRAPHY_VERSION >= LooseVersion(MINIMAL_CRYPTOGRAPHY_VERSION) - can_use_pyopenssl = PYOPENSSL_FOUND and PYOPENSSL_VERSION >= LooseVersion(MINIMAL_PYOPENSSL_VERSION) # If cryptography is available we'll use it if can_use_cryptography: backend = 'cryptography' - elif can_use_pyopenssl: - backend = 'pyopenssl' - - if provider.needs_version_two_certs(module): - module.warn('crypto backend forced to pyopenssl. The cryptography library does not support v2 certificates') - backend = 'pyopenssl' # Fail if no backend has been found if backend == 'auto': - module.fail_json(msg=("Can't detect any of the required Python libraries " - "cryptography (>= {0}) or PyOpenSSL (>= {1})").format( - MINIMAL_CRYPTOGRAPHY_VERSION, - MINIMAL_PYOPENSSL_VERSION)) + module.fail_json(msg=("Can't detect the required Python library " + "cryptography (>= {0})").format(MINIMAL_CRYPTOGRAPHY_VERSION)) - if backend == 'pyopenssl': - module.deprecate('The module is using the PyOpenSSL backend. This backend has been deprecated', - version='2.0.0', collection_name='community.crypto') - - if not PYOPENSSL_FOUND: - module.fail_json(msg=missing_required_lib('pyOpenSSL >= {0}'.format(MINIMAL_PYOPENSSL_VERSION)), - exception=PYOPENSSL_IMP_ERR) - if provider.needs_pyopenssl_get_extensions(module): - try: - getattr(crypto.X509Req, 'get_extensions') - except AttributeError: - module.fail_json(msg='You need to have PyOpenSSL>=0.15') - - elif backend == 'cryptography': + if backend == 'cryptography': if not CRYPTOGRAPHY_FOUND: module.fail_json(msg=missing_required_lib('cryptography >= {0}'.format(MINIMAL_CRYPTOGRAPHY_VERSION)), exception=CRYPTOGRAPHY_IMP_ERR) if provider.needs_version_two_certs(module): - module.fail_json(msg='The cryptography backend does not support v2 certificates, ' - 'use select_crypto_backend=pyopenssl for v2 certificates') + module.fail_json(msg='The cryptography backend does not support v2 certificates') return provider.create_backend(module, backend) @@ -402,7 +328,7 @@ def get_certificate_argument_spec(): force=dict(type='bool', default=False,), csr_path=dict(type='path'), csr_content=dict(type='str'), - select_crypto_backend=dict(type='str', default='auto', choices=['auto', 'cryptography', 'pyopenssl']), + select_crypto_backend=dict(type='str', default='auto', choices=['auto', 'cryptography']), # General properties of a certificate privatekey_path=dict(type='path'), diff --git a/plugins/module_utils/crypto/module_backends/certificate_assertonly.py b/plugins/module_utils/crypto/module_backends/certificate_assertonly.py index 016dbbde..a73f3288 100644 --- a/plugins/module_utils/crypto/module_backends/certificate_assertonly.py +++ b/plugins/module_utils/crypto/module_backends/certificate_assertonly.py @@ -25,10 +25,6 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.cryptograp cryptography_parse_key_usage_params, ) -from ansible_collections.community.crypto.plugins.module_utils.crypto.pyopenssl_support import ( - pyopenssl_normalize_name_attribute, -) - from ansible_collections.community.crypto.plugins.module_utils.crypto.module_backends.certificate import ( CertificateBackend, CertificateProvider, @@ -460,164 +456,6 @@ class AssertOnlyCertificateBackendCryptography(AssertOnlyCertificateBackend): return self.existing_certificate.not_valid_before, valid_in_date, self.existing_certificate.not_valid_after -class AssertOnlyCertificateBackendPyOpenSSL(AssertOnlyCertificateBackend): - """validate the supplied certificate.""" - - def __init__(self, module): - super(AssertOnlyCertificateBackendPyOpenSSL, self).__init__(module, 'pyopenssl') - - # Ensure inputs are properly sanitized before comparison. - for param in ['signature_algorithms', 'key_usage', 'extended_key_usage', - 'subject_alt_name', 'subject', 'issuer', 'not_before', - 'not_after', 'valid_at', 'invalid_at']: - attr = getattr(self, param) - if isinstance(attr, list) and attr: - if isinstance(attr[0], str): - setattr(self, param, [to_bytes(item) for item in attr]) - elif isinstance(attr[0], tuple): - setattr(self, param, [(to_bytes(item[0]), to_bytes(item[1])) for item in attr]) - elif isinstance(attr, tuple): - setattr(self, param, dict((to_bytes(k), to_bytes(v)) for (k, v) in attr.items())) - elif isinstance(attr, dict): - setattr(self, param, dict((to_bytes(k), to_bytes(v)) for (k, v) in attr.items())) - elif isinstance(attr, str): - setattr(self, param, to_bytes(attr)) - - def _validate_privatekey(self): - ctx = OpenSSL.SSL.Context(OpenSSL.SSL.TLSv1_2_METHOD) - ctx.use_privatekey(self.privatekey) - ctx.use_certificate(self.existing_certificate) - try: - ctx.check_privatekey() - return True - except OpenSSL.SSL.Error: - return False - - def _validate_csr_signature(self): - try: - self.csr.verify(self.existing_certificate.get_pubkey()) - except OpenSSL.crypto.Error: - return False - - def _validate_csr_subject(self): - if self.csr.get_subject() != self.existing_certificate.get_subject(): - return False - - def _validate_csr_extensions(self): - csr_extensions = self.csr.get_extensions() - cert_extension_count = self.existing_certificate.get_extension_count() - if len(csr_extensions) != cert_extension_count: - return False - for extension_number in range(0, cert_extension_count): - cert_extension = self.existing_certificate.get_extension(extension_number) - csr_extension = filter(lambda extension: extension.get_short_name() == cert_extension.get_short_name(), csr_extensions) - if cert_extension.get_data() != list(csr_extension)[0].get_data(): - return False - return True - - def _validate_signature_algorithms(self): - if self.existing_certificate.get_signature_algorithm() not in self.signature_algorithms: - return self.existing_certificate.get_signature_algorithm() - - def _validate_subject(self): - expected_subject = [(OpenSSL._util.lib.OBJ_txt2nid(sub[0]), sub[1]) for sub in self.subject] - cert_subject = self.existing_certificate.get_subject().get_components() - current_subject = [(OpenSSL._util.lib.OBJ_txt2nid(sub[0]), sub[1]) for sub in cert_subject] - if not compare_sets(expected_subject, current_subject, self.subject_strict): - return expected_subject, current_subject - - def _validate_issuer(self): - expected_issuer = [(OpenSSL._util.lib.OBJ_txt2nid(iss[0]), iss[1]) for iss in self.issuer] - cert_issuer = self.existing_certificate.get_issuer().get_components() - current_issuer = [(OpenSSL._util.lib.OBJ_txt2nid(iss[0]), iss[1]) for iss in cert_issuer] - if not compare_sets(expected_issuer, current_issuer, self.issuer_strict): - return self.issuer, cert_issuer - - def _validate_has_expired(self): - # The following 3 lines are the same as the current PyOpenSSL code for cert.has_expired(). - # Older version of PyOpenSSL have a buggy implementation, - # to avoid issues with those we added the code from a more recent release here. - - time_string = to_native(self.existing_certificate.get_notAfter()) - not_after = datetime.datetime.strptime(time_string, "%Y%m%d%H%M%SZ") - cert_expired = not_after < datetime.datetime.utcnow() - return cert_expired - - def _validate_version(self): - # Version numbers in certs are off by one: - # v1: 0, v2: 1, v3: 2 ... - return self.existing_certificate.get_version() + 1 - - def _validate_key_usage(self): - found = False - for extension_idx in range(0, self.existing_certificate.get_extension_count()): - extension = self.existing_certificate.get_extension(extension_idx) - if extension.get_short_name() == b'keyUsage': - found = True - expected_extension = crypto.X509Extension(b"keyUsage", False, b', '.join(self.key_usage)) - key_usage = [usage.strip() for usage in to_text(expected_extension, errors='surrogate_or_strict').split(',')] - current_ku = [usage.strip() for usage in to_text(extension, errors='surrogate_or_strict').split(',')] - if not compare_sets(key_usage, current_ku, self.key_usage_strict): - return self.key_usage, str(extension).split(', ') - if not found: - # This is only bad if the user specified a non-empty list - if self.key_usage: - return NO_EXTENSION - - def _validate_extended_key_usage(self): - found = False - for extension_idx in range(0, self.existing_certificate.get_extension_count()): - extension = self.existing_certificate.get_extension(extension_idx) - if extension.get_short_name() == b'extendedKeyUsage': - found = True - extKeyUsage = [OpenSSL._util.lib.OBJ_txt2nid(keyUsage) for keyUsage in self.extended_key_usage] - current_xku = [OpenSSL._util.lib.OBJ_txt2nid(usage.strip()) for usage in - to_bytes(extension, errors='surrogate_or_strict').split(b',')] - if not compare_sets(extKeyUsage, current_xku, self.extended_key_usage_strict): - return self.extended_key_usage, str(extension).split(', ') - if not found: - # This is only bad if the user specified a non-empty list - if self.extended_key_usage: - return NO_EXTENSION - - def _validate_subject_alt_name(self): - found = False - for extension_idx in range(0, self.existing_certificate.get_extension_count()): - extension = self.existing_certificate.get_extension(extension_idx) - if extension.get_short_name() == b'subjectAltName': - found = True - l_altnames = [pyopenssl_normalize_name_attribute(altname.strip()) for altname in - to_text(extension, errors='surrogate_or_strict').split(', ')] - sans = [pyopenssl_normalize_name_attribute(to_text(san, errors='surrogate_or_strict')) for san in self.subject_alt_name] - if not compare_sets(sans, l_altnames, self.subject_alt_name_strict): - return self.subject_alt_name, l_altnames - if not found: - # This is only bad if the user specified a non-empty list - if self.subject_alt_name: - return NO_EXTENSION - - def _validate_not_before(self): - return self.existing_certificate.get_notBefore() - - def _validate_not_after(self): - return self.existing_certificate.get_notAfter() - - def _validate_valid_at(self): - rt = get_relative_time_option(self.valid_at, "valid_at", backend=self.backend) - rt = to_bytes(rt, errors='surrogate_or_strict') - return self.existing_certificate.get_notBefore(), rt, self.existing_certificate.get_notAfter() - - def _validate_invalid_at(self): - rt = get_relative_time_option(self.invalid_at, "invalid_at", backend=self.backend) - rt = to_bytes(rt, errors='surrogate_or_strict') - return self.existing_certificate.get_notBefore(), rt, self.existing_certificate.get_notAfter() - - def _validate_valid_in(self): - valid_in_asn1 = get_relative_time_option(self.valid_in, "valid_in", backend=self.backend) - valid_in_date = to_bytes(valid_in_asn1, errors='surrogate_or_strict') - return self.existing_certificate.get_notBefore(), valid_in_date, self.existing_certificate.get_notAfter() - - class AssertOnlyCertificateProvider(CertificateProvider): def validate_module_args(self, module): module.deprecate("The 'assertonly' provider is deprecated; please see the examples of " @@ -630,8 +468,6 @@ class AssertOnlyCertificateProvider(CertificateProvider): def create_backend(self, module, backend): if backend == 'cryptography': return AssertOnlyCertificateBackendCryptography(module) - if backend == 'pyopenssl': - return AssertOnlyCertificateBackendPyOpenSSL(module) def add_assertonly_provider_to_argument_spec(argument_spec): diff --git a/plugins/module_utils/crypto/module_backends/certificate_entrust.py b/plugins/module_utils/crypto/module_backends/certificate_entrust.py index 13026f9e..b911c532 100644 --- a/plugins/module_utils/crypto/module_backends/certificate_entrust.py +++ b/plugins/module_utils/crypto/module_backends/certificate_entrust.py @@ -58,18 +58,7 @@ class EntrustCertificateBackend(CertificateBackend): # We want to always force behavior of trying to use the organization provided in the CSR. # To that end we need to parse out the organization from the CSR. self.csr_org = None - if self.backend == 'pyopenssl': - csr_subject = self.csr.get_subject() - csr_subject_components = csr_subject.get_components() - for k, v in csr_subject_components: - if k.upper() == 'O': - # Entrust does not support multiple validated organizations in a single certificate - if self.csr_org is not None: - self.module.fail_json(msg=("Entrust provider does not currently support multiple validated organizations. Multiple organizations " - "found in Subject DN: '{0}'. ".format(csr_subject))) - else: - self.csr_org = v - elif self.backend == 'cryptography': + if self.backend == 'cryptography': csr_subject_orgs = self.csr.subject.get_attributes_for_oid(NameOID.ORGANIZATION_NAME) if len(csr_subject_orgs) == 1: self.csr_org = csr_subject_orgs[0].value @@ -162,11 +151,7 @@ class EntrustCertificateBackend(CertificateBackend): if self.existing_certificate: serial_number = None expiry = None - if self.backend == 'pyopenssl': - serial_number = "{0:X}".format(self.existing_certificate.get_serial_number()) - time_string = to_native(self.existing_certificate.get_notAfter()) - expiry = datetime.datetime.strptime(time_string, "%Y%m%d%H%M%SZ") - elif self.backend == 'cryptography': + if self.backend == 'cryptography': serial_number = "{0:X}".format(cryptography_serial_number_of_cert(self.existing_certificate)) expiry = self.existing_certificate.not_valid_after diff --git a/plugins/module_utils/crypto/module_backends/certificate_info.py b/plugins/module_utils/crypto/module_backends/certificate_info.py index bd24f67f..9aedf5d9 100644 --- a/plugins/module_utils/crypto/module_backends/certificate_info.py +++ b/plugins/module_utils/crypto/module_backends/certificate_info.py @@ -33,37 +33,11 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.cryptograp cryptography_serial_number_of_cert, ) -from ansible_collections.community.crypto.plugins.module_utils.crypto.pyopenssl_support import ( - pyopenssl_get_extensions_from_cert, - pyopenssl_normalize_name, - pyopenssl_normalize_name_attribute, -) - from ansible_collections.community.crypto.plugins.module_utils.crypto.module_backends.publickey_info import ( get_publickey_info, ) MINIMAL_CRYPTOGRAPHY_VERSION = '1.6' -MINIMAL_PYOPENSSL_VERSION = '0.15' - -PYOPENSSL_IMP_ERR = None -try: - import OpenSSL - from OpenSSL import crypto - PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__) - if OpenSSL.SSL.OPENSSL_VERSION_NUMBER >= 0x10100000: - # OpenSSL 1.1.0 or newer - OPENSSL_MUST_STAPLE_NAME = b"tlsfeature" - OPENSSL_MUST_STAPLE_VALUE = b"status_request" - else: - # OpenSSL 1.0.x or older - OPENSSL_MUST_STAPLE_NAME = b"1.3.6.1.5.5.7.1.24" - OPENSSL_MUST_STAPLE_VALUE = b"DER:30:03:02:01:05" -except ImportError: - PYOPENSSL_IMP_ERR = traceback.format_exc() - PYOPENSSL_FOUND = False -else: - PYOPENSSL_FOUND = True CRYPTOGRAPHY_IMP_ERR = None try: @@ -209,20 +183,19 @@ class CertificateInfoRetrieval(object): result['fingerprints'] = get_fingerprint_of_bytes( self._get_der_bytes(), prefer_one=prefer_one_fingerprint) - if self.backend != 'pyopenssl': - ski = self._get_subject_key_identifier() - if ski is not None: - ski = to_native(binascii.hexlify(ski)) - ski = ':'.join([ski[i:i + 2] for i in range(0, len(ski), 2)]) - result['subject_key_identifier'] = ski + ski = self._get_subject_key_identifier() + if ski is not None: + ski = to_native(binascii.hexlify(ski)) + ski = ':'.join([ski[i:i + 2] for i in range(0, len(ski), 2)]) + result['subject_key_identifier'] = ski - aki, aci, acsn = self._get_authority_key_identifier() - if aki is not None: - aki = to_native(binascii.hexlify(aki)) - aki = ':'.join([aki[i:i + 2] for i in range(0, len(aki), 2)]) - result['authority_key_identifier'] = aki - result['authority_cert_issuer'] = aci - result['authority_cert_serial_number'] = acsn + aki, aci, acsn = self._get_authority_key_identifier() + if aki is not None: + aki = to_native(binascii.hexlify(aki)) + aki = ':'.join([aki[i:i + 2] for i in range(0, len(aki), 2)]) + result['authority_key_identifier'] = aki + result['authority_cert_issuer'] = aci + result['authority_cert_serial_number'] = acsn result['serial_number'] = self._get_serial_number() result['extensions_by_oid'] = self._get_all_extensions() @@ -392,136 +365,9 @@ class CertificateInfoRetrievalCryptography(CertificateInfoRetrieval): return None -class CertificateInfoRetrievalPyOpenSSL(CertificateInfoRetrieval): - """validate the supplied certificate.""" - - def __init__(self, module, content): - super(CertificateInfoRetrievalPyOpenSSL, self).__init__(module, 'pyopenssl', content) - - def _get_der_bytes(self): - return crypto.dump_certificate(crypto.FILETYPE_ASN1, self.cert) - - def _get_signature_algorithm(self): - return to_text(self.cert.get_signature_algorithm()) - - def __get_name(self, name): - result = [] - for sub in name.get_components(): - result.append([pyopenssl_normalize_name(sub[0]), to_text(sub[1])]) - return result - - def _get_subject_ordered(self): - return self.__get_name(self.cert.get_subject()) - - def _get_issuer_ordered(self): - return self.__get_name(self.cert.get_issuer()) - - def _get_version(self): - # Version numbers in certs are off by one: - # v1: 0, v2: 1, v3: 2 ... - return self.cert.get_version() + 1 - - def _get_extension(self, short_name): - for extension_idx in range(0, self.cert.get_extension_count()): - extension = self.cert.get_extension(extension_idx) - if extension.get_short_name() == short_name: - result = [ - pyopenssl_normalize_name(usage.strip()) for usage in to_text(extension, errors='surrogate_or_strict').split(',') - ] - return sorted(result), bool(extension.get_critical()) - return None, False - - def _get_key_usage(self): - return self._get_extension(b'keyUsage') - - def _get_extended_key_usage(self): - return self._get_extension(b'extendedKeyUsage') - - def _get_basic_constraints(self): - return self._get_extension(b'basicConstraints') - - def _get_ocsp_must_staple(self): - extensions = [self.cert.get_extension(i) for i in range(0, self.cert.get_extension_count())] - oms_ext = [ - ext for ext in extensions - if to_bytes(ext.get_short_name()) == OPENSSL_MUST_STAPLE_NAME and to_bytes(ext) == OPENSSL_MUST_STAPLE_VALUE - ] - if OpenSSL.SSL.OPENSSL_VERSION_NUMBER < 0x10100000: - # Older versions of libssl don't know about OCSP Must Staple - oms_ext.extend([ext for ext in extensions if ext.get_short_name() == b'UNDEF' and ext.get_data() == b'\x30\x03\x02\x01\x05']) - if oms_ext: - return True, bool(oms_ext[0].get_critical()) - else: - return None, False - - def _get_subject_alt_name(self): - 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': - result = [pyopenssl_normalize_name_attribute(altname.strip()) for altname in - to_text(extension, errors='surrogate_or_strict').split(', ')] - return result, bool(extension.get_critical()) - return None, False - - def get_not_before(self): - time_string = to_native(self.cert.get_notBefore()) - return datetime.datetime.strptime(time_string, "%Y%m%d%H%M%SZ") - - def get_not_after(self): - time_string = to_native(self.cert.get_notAfter()) - return datetime.datetime.strptime(time_string, "%Y%m%d%H%M%SZ") - - def _get_public_key_pem(self): - try: - return crypto.dump_publickey( - crypto.FILETYPE_PEM, - self.cert.get_pubkey(), - ) - except AttributeError: - try: - # pyOpenSSL < 16.0: - bio = crypto._new_mem_buf() - rc = crypto._lib.PEM_write_bio_PUBKEY(bio, self.cert.get_pubkey()._pkey) - if rc != 1: - crypto._raise_current_error() - return crypto._bio_to_string(bio) - except AttributeError: - self.module.warn('Your pyOpenSSL version does not support dumping public keys. ' - 'Please upgrade to version 16.0 or newer, or use the cryptography backend.') - - def _get_public_key_object(self): - return self.cert.get_pubkey() - - def _get_subject_key_identifier(self): - # Won't be implemented - return None - - def _get_authority_key_identifier(self): - # Won't be implemented - return None, None, None - - def _get_serial_number(self): - return self.cert.get_serial_number() - - def _get_all_extensions(self): - return pyopenssl_get_extensions_from_cert(self.cert) - - def _get_ocsp_uri(self): - for i in range(self.cert.get_extension_count()): - ext = self.cert.get_extension(i) - if ext.get_short_name() == b'authorityInfoAccess': - v = str(ext) - m = re.search('^OCSP - URI:(.*)$', v, flags=re.MULTILINE) - if m: - return m.group(1) - return None - - def get_certificate_info(module, backend, content, prefer_one_fingerprint=False): if backend == 'cryptography': info = CertificateInfoRetrievalCryptography(module, content) - elif backend == 'pyopenssl': - info = CertificateInfoRetrievalPyOpenSSL(module, content) return info.get_info(prefer_one_fingerprint=prefer_one_fingerprint) @@ -529,34 +375,17 @@ def select_backend(module, backend, content): if backend == 'auto': # Detection what is possible can_use_cryptography = CRYPTOGRAPHY_FOUND and CRYPTOGRAPHY_VERSION >= LooseVersion(MINIMAL_CRYPTOGRAPHY_VERSION) - can_use_pyopenssl = PYOPENSSL_FOUND and PYOPENSSL_VERSION >= LooseVersion(MINIMAL_PYOPENSSL_VERSION) - # First try cryptography, then pyOpenSSL + # Try cryptography if can_use_cryptography: backend = 'cryptography' - elif can_use_pyopenssl: - backend = 'pyopenssl' # Success? if backend == 'auto': module.fail_json(msg=("Can't detect any of the required Python libraries " - "cryptography (>= {0}) or PyOpenSSL (>= {1})").format( - MINIMAL_CRYPTOGRAPHY_VERSION, - MINIMAL_PYOPENSSL_VERSION)) + "cryptography (>= {0})").format(MINIMAL_CRYPTOGRAPHY_VERSION)) - if backend == 'pyopenssl': - if not PYOPENSSL_FOUND: - module.fail_json(msg=missing_required_lib('pyOpenSSL >= {0}'.format(MINIMAL_PYOPENSSL_VERSION)), - exception=PYOPENSSL_IMP_ERR) - try: - getattr(crypto.X509Req, 'get_extensions') - except AttributeError: - module.fail_json(msg='You need to have PyOpenSSL>=0.15 to generate CSRs') - - module.deprecate('The module is using the PyOpenSSL backend. This backend has been deprecated', - version='2.0.0', collection_name='community.crypto') - return backend, CertificateInfoRetrievalPyOpenSSL(module, content) - elif backend == 'cryptography': + if backend == 'cryptography': if not CRYPTOGRAPHY_FOUND: module.fail_json(msg=missing_required_lib('cryptography >= {0}'.format(MINIMAL_CRYPTOGRAPHY_VERSION)), exception=CRYPTOGRAPHY_IMP_ERR) diff --git a/plugins/module_utils/crypto/module_backends/certificate_ownca.py b/plugins/module_utils/crypto/module_backends/certificate_ownca.py index af28bec0..55cd0374 100644 --- a/plugins/module_utils/crypto/module_backends/certificate_ownca.py +++ b/plugins/module_utils/crypto/module_backends/certificate_ownca.py @@ -227,100 +227,6 @@ def generate_serial_number(): return result -class OwnCACertificateBackendPyOpenSSL(CertificateBackend): - def __init__(self, module): - super(OwnCACertificateBackendPyOpenSSL, self).__init__(module, 'pyopenssl') - - self.notBefore = get_relative_time_option(self.module.params['ownca_not_before'], 'ownca_not_before', backend=self.backend) - self.notAfter = get_relative_time_option(self.module.params['ownca_not_after'], 'ownca_not_after', backend=self.backend) - self.digest = self.module.params['ownca_digest'] - self.version = self.module.params['ownca_version'] - self.serial_number = generate_serial_number() - if self.module.params['ownca_create_subject_key_identifier'] != 'create_if_not_provided': - self.module.fail_json(msg='ownca_create_subject_key_identifier cannot be used with the pyOpenSSL backend!') - if self.module.params['ownca_create_authority_key_identifier']: - self.module.warn('ownca_create_authority_key_identifier is ignored by the pyOpenSSL backend!') - self.ca_cert_path = self.module.params['ownca_path'] - self.ca_cert_content = self.module.params['ownca_content'] - if self.ca_cert_content is not None: - self.ca_cert_content = self.ca_cert_content.encode('utf-8') - self.ca_privatekey_path = self.module.params['ownca_privatekey_path'] - self.ca_privatekey_content = self.module.params['ownca_privatekey_content'] - if self.ca_privatekey_content is not None: - self.ca_privatekey_content = self.ca_privatekey_content.encode('utf-8') - self.ca_privatekey_passphrase = self.module.params['ownca_privatekey_passphrase'] - - if self.csr_content is None and not os.path.exists(self.csr_path): - raise CertificateError( - 'The certificate signing request file {0} does not exist'.format(self.csr_path) - ) - if self.ca_cert_content is None and not os.path.exists(self.ca_cert_path): - raise CertificateError( - 'The CA certificate file {0} does not exist'.format(self.ca_cert_path) - ) - if self.ca_privatekey_content is None and not os.path.exists(self.ca_privatekey_path): - raise CertificateError( - 'The CA private key file {0} does not exist'.format(self.ca_privatekey_path) - ) - - self._ensure_csr_loaded() - self.ca_cert = load_certificate( - path=self.ca_cert_path, - content=self.ca_cert_content, - ) - try: - self.ca_privatekey = load_privatekey( - path=self.ca_privatekey_path, - content=self.ca_privatekey_content, - passphrase=self.ca_privatekey_passphrase - ) - except OpenSSLBadPassphraseError as exc: - self.module.fail_json(msg=str(exc)) - - def generate_certificate(self): - """(Re-)Generate certificate.""" - cert = crypto.X509() - cert.set_serial_number(self.serial_number) - cert.set_notBefore(to_bytes(self.notBefore)) - cert.set_notAfter(to_bytes(self.notAfter)) - cert.set_subject(self.csr.get_subject()) - cert.set_issuer(self.ca_cert.get_subject()) - cert.set_version(self.version - 1) - cert.set_pubkey(self.csr.get_pubkey()) - cert.add_extensions(self.csr.get_extensions()) - - cert.sign(self.ca_privatekey, self.digest) - self.cert = cert - - def get_certificate_data(self): - """Return bytes for self.cert.""" - return crypto.dump_certificate(crypto.FILETYPE_PEM, self.cert) - - def dump(self, include_certificate): - result = super(OwnCACertificateBackendPyOpenSSL, self).dump(include_certificate) - result.update({ - 'ca_cert': self.ca_cert_path, - 'ca_privatekey': self.ca_privatekey_path, - }) - - if self.module.check_mode: - result.update({ - 'notBefore': self.notBefore, - 'notAfter': self.notAfter, - 'serial_number': self.serial_number, - }) - else: - if self.cert is None: - self.cert = self.existing_certificate - result.update({ - 'notBefore': self.cert.get_notBefore(), - 'notAfter': self.cert.get_notAfter(), - 'serial_number': self.cert.get_serial_number(), - }) - - return result - - class OwnCACertificateProvider(CertificateProvider): def validate_module_args(self, module): if module.params['ownca_path'] is None and module.params['ownca_content'] is None: @@ -334,8 +240,6 @@ class OwnCACertificateProvider(CertificateProvider): def create_backend(self, module, backend): if backend == 'cryptography': return OwnCACertificateBackendCryptography(module) - if backend == 'pyopenssl': - return OwnCACertificateBackendPyOpenSSL(module) def add_ownca_provider_to_argument_spec(argument_spec): diff --git a/plugins/module_utils/crypto/module_backends/certificate_selfsigned.py b/plugins/module_utils/crypto/module_backends/certificate_selfsigned.py index fb348fe3..74aeaa33 100644 --- a/plugins/module_utils/crypto/module_backends/certificate_selfsigned.py +++ b/plugins/module_utils/crypto/module_backends/certificate_selfsigned.py @@ -163,76 +163,6 @@ def generate_serial_number(): return result -class SelfSignedCertificateBackendPyOpenSSL(CertificateBackend): - def __init__(self, module): - super(SelfSignedCertificateBackendPyOpenSSL, self).__init__(module, 'pyopenssl') - - if module.params['selfsigned_create_subject_key_identifier'] != 'create_if_not_provided': - module.fail_json(msg='selfsigned_create_subject_key_identifier cannot be used with the pyOpenSSL backend!') - self.notBefore = get_relative_time_option(module.params['selfsigned_not_before'], 'selfsigned_not_before', backend=self.backend) - self.notAfter = get_relative_time_option(module.params['selfsigned_not_after'], 'selfsigned_not_after', backend=self.backend) - self.digest = module.params['selfsigned_digest'] - self.version = module.params['selfsigned_version'] - self.serial_number = generate_serial_number() - - if self.csr_path is not None and not os.path.exists(self.csr_path): - raise CertificateError( - 'The certificate signing request file {0} does not exist'.format(self.csr_path) - ) - if self.privatekey_content is None and not os.path.exists(self.privatekey_path): - raise CertificateError( - 'The private key file {0} does not exist'.format(self.privatekey_path) - ) - - self._ensure_private_key_loaded() - - self._ensure_csr_loaded() - if self.csr is None: - # Create empty CSR on the fly - self.csr = crypto.X509Req() - self.csr.set_pubkey(self.privatekey) - self.csr.sign(self.privatekey, self.digest) - - def generate_certificate(self): - """(Re-)Generate certificate.""" - cert = crypto.X509() - cert.set_serial_number(self.serial_number) - cert.set_notBefore(to_bytes(self.notBefore)) - cert.set_notAfter(to_bytes(self.notAfter)) - cert.set_subject(self.csr.get_subject()) - cert.set_issuer(self.csr.get_subject()) - cert.set_version(self.version - 1) - cert.set_pubkey(self.csr.get_pubkey()) - cert.add_extensions(self.csr.get_extensions()) - - cert.sign(self.privatekey, self.digest) - self.cert = cert - - def get_certificate_data(self): - """Return bytes for self.cert.""" - return crypto.dump_certificate(crypto.FILETYPE_PEM, self.cert) - - def dump(self, include_certificate): - result = super(SelfSignedCertificateBackendPyOpenSSL, self).dump(include_certificate) - - if self.module.check_mode: - result.update({ - 'notBefore': self.notBefore, - 'notAfter': self.notAfter, - 'serial_number': self.serial_number, - }) - else: - if self.cert is None: - self.cert = self.existing_certificate - result.update({ - 'notBefore': self.cert.get_notBefore(), - 'notAfter': self.cert.get_notAfter(), - 'serial_number': self.cert.get_serial_number(), - }) - - return result - - class SelfSignedCertificateProvider(CertificateProvider): def validate_module_args(self, module): if module.params['privatekey_path'] is None and module.params['privatekey_content'] is None: @@ -244,8 +174,6 @@ class SelfSignedCertificateProvider(CertificateProvider): def create_backend(self, module, backend): if backend == 'cryptography': return SelfSignedCertificateBackendCryptography(module) - if backend == 'pyopenssl': - return SelfSignedCertificateBackendPyOpenSSL(module) def add_selfsigned_provider_to_argument_spec(argument_spec): diff --git a/plugins/module_utils/crypto/module_backends/csr.py b/plugins/module_utils/crypto/module_backends/csr.py index 1c11131d..17a7244e 100644 --- a/plugins/module_utils/crypto/module_backends/csr.py +++ b/plugins/module_utils/crypto/module_backends/csr.py @@ -43,11 +43,6 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.cryptograp REVOCATION_REASON_MAP, ) -from ansible_collections.community.crypto.plugins.module_utils.crypto.pyopenssl_support import ( - pyopenssl_normalize_name_attribute, - pyopenssl_parse_name_constraints, -) - from ansible_collections.community.crypto.plugins.module_utils.crypto.module_backends.csr_info import ( get_csr_info, ) @@ -55,28 +50,8 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.module_bac from ansible_collections.community.crypto.plugins.module_utils.crypto.module_backends.common import ArgumentSpec -MINIMAL_PYOPENSSL_VERSION = '0.15' MINIMAL_CRYPTOGRAPHY_VERSION = '1.3' -PYOPENSSL_IMP_ERR = None -try: - import OpenSSL - from OpenSSL import crypto - PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__) -except ImportError: - PYOPENSSL_IMP_ERR = traceback.format_exc() - PYOPENSSL_FOUND = False -else: - PYOPENSSL_FOUND = True - if OpenSSL.SSL.OPENSSL_VERSION_NUMBER >= 0x10100000: - # OpenSSL 1.1.0 or newer - OPENSSL_MUST_STAPLE_NAME = b"tlsfeature" - OPENSSL_MUST_STAPLE_VALUE = b"status_request" - else: - # OpenSSL 1.0.x or older - OPENSSL_MUST_STAPLE_NAME = b"1.3.6.1.5.5.7.1.24" - OPENSSL_MUST_STAPLE_VALUE = b"DER:30:03:02:01:05" - CRYPTOGRAPHY_IMP_ERR = None try: import cryptography @@ -273,174 +248,6 @@ class CertificateSigningRequestBackend(object): return result -# Implementation with using pyOpenSSL -class CertificateSigningRequestPyOpenSSLBackend(CertificateSigningRequestBackend): - def __init__(self, module): - for o in ('create_subject_key_identifier', ): - if module.params[o]: - module.fail_json(msg='You cannot use {0} with the pyOpenSSL backend!'.format(o)) - for o in ('subject_key_identifier', 'authority_key_identifier', 'authority_cert_issuer', 'authority_cert_serial_number', 'crl_distribution_points'): - if module.params[o] is not None: - module.fail_json(msg='You cannot use {0} with the pyOpenSSL backend!'.format(o)) - super(CertificateSigningRequestPyOpenSSLBackend, self).__init__(module, 'pyopenssl') - - def generate_csr(self): - """(Re-)Generate CSR.""" - self._ensure_private_key_loaded() - - req = crypto.X509Req() - req.set_version(self.version - 1) - subject = req.get_subject() - for entry in self.subject: - if entry[1] is not None: - # Workaround for https://github.com/pyca/pyopenssl/issues/165 - nid = OpenSSL._util.lib.OBJ_txt2nid(to_bytes(entry[0])) - if nid == 0: - raise CertificateSigningRequestError('Unknown subject field identifier "{0}"'.format(entry[0])) - res = OpenSSL._util.lib.X509_NAME_add_entry_by_NID(subject._name, nid, OpenSSL._util.lib.MBSTRING_UTF8, to_bytes(entry[1]), -1, -1, 0) - if res == 0: - raise CertificateSigningRequestError('Invalid value for subject field identifier "{0}": {1}'.format(entry[0], entry[1])) - - extensions = [] - if self.subjectAltName: - altnames = ', '.join(self.subjectAltName) - try: - extensions.append(crypto.X509Extension(b"subjectAltName", self.subjectAltName_critical, altnames.encode('ascii'))) - except OpenSSL.crypto.Error as e: - raise CertificateSigningRequestError( - 'Error while parsing Subject Alternative Names {0} (check for missing type prefix, such as "DNS:"!): {1}'.format( - ', '.join(["{0}".format(san) for san in self.subjectAltName]), str(e) - ) - ) - - if self.keyUsage: - usages = ', '.join(self.keyUsage) - extensions.append(crypto.X509Extension(b"keyUsage", self.keyUsage_critical, usages.encode('ascii'))) - - if self.extendedKeyUsage: - usages = ', '.join(self.extendedKeyUsage) - extensions.append(crypto.X509Extension(b"extendedKeyUsage", self.extendedKeyUsage_critical, usages.encode('ascii'))) - - if self.basicConstraints: - usages = ', '.join(self.basicConstraints) - extensions.append(crypto.X509Extension(b"basicConstraints", self.basicConstraints_critical, usages.encode('ascii'))) - - if self.name_constraints_permitted or self.name_constraints_excluded: - usages = ', '.join( - ['permitted;{0}'.format(name) for name in self.name_constraints_permitted] + - ['excluded;{0}'.format(name) for name in self.name_constraints_excluded] - ) - extensions.append(crypto.X509Extension(b"nameConstraints", self.name_constraints_critical, usages.encode('ascii'))) - - if self.ocspMustStaple: - extensions.append(crypto.X509Extension(OPENSSL_MUST_STAPLE_NAME, self.ocspMustStaple_critical, OPENSSL_MUST_STAPLE_VALUE)) - - if extensions: - req.add_extensions(extensions) - - req.set_pubkey(self.privatekey) - req.sign(self.privatekey, self.digest) - self.csr = req - - def get_csr_data(self): - """Return bytes for self.csr.""" - return crypto.dump_certificate_request(crypto.FILETYPE_PEM, self.csr) - - def _check_csr(self): - def _check_subject(csr): - subject = [(OpenSSL._util.lib.OBJ_txt2nid(to_bytes(sub[0])), to_bytes(sub[1])) for sub in self.subject] - current_subject = [(OpenSSL._util.lib.OBJ_txt2nid(to_bytes(sub[0])), to_bytes(sub[1])) for sub in csr.get_subject().get_components()] - if not set(subject) == set(current_subject): - return False - - return True - - def _check_subjectAltName(extensions): - altnames_ext = next((ext for ext in extensions if ext.get_short_name() == b'subjectAltName'), '') - altnames = [pyopenssl_normalize_name_attribute(altname.strip()) for altname in - to_text(altnames_ext, errors='surrogate_or_strict').split(',') if altname.strip()] - if self.subjectAltName: - if (set(altnames) != set([pyopenssl_normalize_name_attribute(to_text(name)) for name in self.subjectAltName]) or - altnames_ext.get_critical() != self.subjectAltName_critical): - return False - else: - if altnames: - return False - - return True - - def _check_keyUsage_(extensions, extName, expected, critical): - usages_ext = [ext for ext in extensions if ext.get_short_name() == extName] - if (not usages_ext and expected) or (usages_ext and not expected): - return False - elif not usages_ext and not expected: - return True - else: - current = [OpenSSL._util.lib.OBJ_txt2nid(to_bytes(usage.strip())) for usage in str(usages_ext[0]).split(',')] - expected = [OpenSSL._util.lib.OBJ_txt2nid(to_bytes(usage)) for usage in expected] - return set(current) == set(expected) and usages_ext[0].get_critical() == critical - - def _check_keyUsage(extensions): - usages_ext = [ext for ext in extensions if ext.get_short_name() == b'keyUsage'] - if (not usages_ext and self.keyUsage) or (usages_ext and not self.keyUsage): - return False - elif not usages_ext and not self.keyUsage: - return True - else: - # OpenSSL._util.lib.OBJ_txt2nid() always returns 0 for all keyUsage values - # (since keyUsage has a fixed bitfield for these values and is not extensible). - # Therefore, we create an extension for the wanted values, and compare the - # data of the extensions (which is the serialized bitfield). - expected_ext = crypto.X509Extension(b"keyUsage", False, ', '.join(self.keyUsage).encode('ascii')) - return usages_ext[0].get_data() == expected_ext.get_data() and usages_ext[0].get_critical() == self.keyUsage_critical - - def _check_extenededKeyUsage(extensions): - return _check_keyUsage_(extensions, b'extendedKeyUsage', self.extendedKeyUsage, self.extendedKeyUsage_critical) - - def _check_basicConstraints(extensions): - return _check_keyUsage_(extensions, b'basicConstraints', self.basicConstraints, self.basicConstraints_critical) - - def _check_nameConstraints(extensions): - nc_ext = next((ext for ext in extensions if ext.get_short_name() == b'nameConstraints'), '') - permitted, excluded = pyopenssl_parse_name_constraints(nc_ext) - if self.name_constraints_permitted or self.name_constraints_excluded: - if set(permitted) != set([pyopenssl_normalize_name_attribute(to_text(name)) for name in self.name_constraints_permitted]): - return False - if set(excluded) != set([pyopenssl_normalize_name_attribute(to_text(name)) for name in self.name_constraints_excluded]): - return False - if nc_ext.get_critical() != self.name_constraints_critical: - return False - else: - if permitted or excluded: - return False - - return True - - def _check_ocspMustStaple(extensions): - oms_ext = [ext for ext in extensions if to_bytes(ext.get_short_name()) == OPENSSL_MUST_STAPLE_NAME and to_bytes(ext) == OPENSSL_MUST_STAPLE_VALUE] - if OpenSSL.SSL.OPENSSL_VERSION_NUMBER < 0x10100000: - # Older versions of libssl don't know about OCSP Must Staple - oms_ext.extend([ext for ext in extensions if ext.get_short_name() == b'UNDEF' and ext.get_data() == b'\x30\x03\x02\x01\x05']) - if self.ocspMustStaple: - return len(oms_ext) > 0 and oms_ext[0].get_critical() == self.ocspMustStaple_critical - else: - return len(oms_ext) == 0 - - def _check_extensions(csr): - extensions = csr.get_extensions() - return (_check_subjectAltName(extensions) and _check_keyUsage(extensions) and - _check_extenededKeyUsage(extensions) and _check_basicConstraints(extensions) and - _check_ocspMustStaple(extensions) and _check_nameConstraints(extensions)) - - def _check_signature(csr): - try: - return csr.verify(self.privatekey) - except crypto.Error: - return False - - return _check_subject(self.existing_csr) and _check_extensions(self.existing_csr) and _check_signature(self.existing_csr) - - def parse_crl_distribution_points(module, crl_distribution_points): result = [] for index, parse_crl_distribution_point in enumerate(crl_distribution_points): @@ -762,34 +569,17 @@ def select_backend(module, backend): if backend == 'auto': # Detection what is possible can_use_cryptography = CRYPTOGRAPHY_FOUND and CRYPTOGRAPHY_VERSION >= LooseVersion(MINIMAL_CRYPTOGRAPHY_VERSION) - can_use_pyopenssl = PYOPENSSL_FOUND and PYOPENSSL_VERSION >= LooseVersion(MINIMAL_PYOPENSSL_VERSION) - # First try cryptography, then pyOpenSSL + # Try cryptography if can_use_cryptography: backend = 'cryptography' - elif can_use_pyopenssl: - backend = 'pyopenssl' # Success? if backend == 'auto': module.fail_json(msg=("Can't detect any of the required Python libraries " - "cryptography (>= {0}) or PyOpenSSL (>= {1})").format( - MINIMAL_CRYPTOGRAPHY_VERSION, - MINIMAL_PYOPENSSL_VERSION)) + "cryptography (>= {0})").format(MINIMAL_CRYPTOGRAPHY_VERSION)) - if backend == 'pyopenssl': - if not PYOPENSSL_FOUND: - module.fail_json(msg=missing_required_lib('pyOpenSSL >= {0}'.format(MINIMAL_PYOPENSSL_VERSION)), - exception=PYOPENSSL_IMP_ERR) - try: - getattr(crypto.X509Req, 'get_extensions') - except AttributeError: - module.fail_json(msg='You need to have PyOpenSSL>=0.15 to generate CSRs') - - module.deprecate('The module is using the PyOpenSSL backend. This backend has been deprecated', - version='2.0.0', collection_name='community.crypto') - return backend, CertificateSigningRequestPyOpenSSLBackend(module) - elif backend == 'cryptography': + if backend == 'cryptography': if not CRYPTOGRAPHY_FOUND: module.fail_json(msg=missing_required_lib('cryptography >= {0}'.format(MINIMAL_CRYPTOGRAPHY_VERSION)), exception=CRYPTOGRAPHY_IMP_ERR) @@ -853,7 +643,7 @@ def get_csr_argument_spec(): ), mutually_exclusive=[('full_name', 'relative_name')] ), - select_crypto_backend=dict(type='str', default='auto', choices=['auto', 'cryptography', 'pyopenssl']), + select_crypto_backend=dict(type='str', default='auto', choices=['auto', 'cryptography']), ), required_together=[ ['authority_cert_issuer', 'authority_cert_serial_number'], diff --git a/plugins/module_utils/crypto/module_backends/csr_info.py b/plugins/module_utils/crypto/module_backends/csr_info.py index bad68d9b..e7a26f36 100644 --- a/plugins/module_utils/crypto/module_backends/csr_info.py +++ b/plugins/module_utils/crypto/module_backends/csr_info.py @@ -30,38 +30,11 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.cryptograp cryptography_oid_to_name, ) -from ansible_collections.community.crypto.plugins.module_utils.crypto.pyopenssl_support import ( - pyopenssl_get_extensions_from_csr, - pyopenssl_normalize_name, - pyopenssl_normalize_name_attribute, - pyopenssl_parse_name_constraints, -) - from ansible_collections.community.crypto.plugins.module_utils.crypto.module_backends.publickey_info import ( get_publickey_info, ) MINIMAL_CRYPTOGRAPHY_VERSION = '1.3' -MINIMAL_PYOPENSSL_VERSION = '0.15' - -PYOPENSSL_IMP_ERR = None -try: - import OpenSSL - from OpenSSL import crypto - PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__) - if OpenSSL.SSL.OPENSSL_VERSION_NUMBER >= 0x10100000: - # OpenSSL 1.1.0 or newer - OPENSSL_MUST_STAPLE_NAME = b"tlsfeature" - OPENSSL_MUST_STAPLE_VALUE = b"status_request" - else: - # OpenSSL 1.0.x or older - OPENSSL_MUST_STAPLE_NAME = b"1.3.6.1.5.5.7.1.24" - OPENSSL_MUST_STAPLE_VALUE = b"DER:30:03:02:01:05" -except ImportError: - PYOPENSSL_IMP_ERR = traceback.format_exc() - PYOPENSSL_FOUND = False -else: - PYOPENSSL_FOUND = True CRYPTOGRAPHY_IMP_ERR = None try: @@ -173,20 +146,19 @@ class CSRInfoRetrieval(object): 'public_key_fingerprints': public_key_info['fingerprints'], }) - if self.backend != 'pyopenssl': - ski = self._get_subject_key_identifier() - if ski is not None: - ski = to_native(binascii.hexlify(ski)) - ski = ':'.join([ski[i:i + 2] for i in range(0, len(ski), 2)]) - result['subject_key_identifier'] = ski + ski = self._get_subject_key_identifier() + if ski is not None: + ski = to_native(binascii.hexlify(ski)) + ski = ':'.join([ski[i:i + 2] for i in range(0, len(ski), 2)]) + result['subject_key_identifier'] = ski - aki, aci, acsn = self._get_authority_key_identifier() - if aki is not None: - aki = to_native(binascii.hexlify(aki)) - aki = ':'.join([aki[i:i + 2] for i in range(0, len(aki), 2)]) - result['authority_key_identifier'] = aki - result['authority_cert_issuer'] = aci - result['authority_cert_serial_number'] = acsn + aki, aci, acsn = self._get_authority_key_identifier() + if aki is not None: + aki = to_native(binascii.hexlify(aki)) + aki = ':'.join([aki[i:i + 2] for i in range(0, len(aki), 2)]) + result['authority_key_identifier'] = aki + result['authority_cert_issuer'] = aci + result['authority_cert_serial_number'] = acsn result['extensions_by_oid'] = self._get_all_extensions() @@ -332,112 +304,9 @@ class CSRInfoRetrievalCryptography(CSRInfoRetrieval): return self.csr.is_signature_valid -class CSRInfoRetrievalPyOpenSSL(CSRInfoRetrieval): - """validate the supplied CSR.""" - - def __init__(self, module, content, validate_signature): - super(CSRInfoRetrievalPyOpenSSL, self).__init__(module, 'pyopenssl', content, validate_signature) - - def __get_name(self, name): - result = [] - for sub in name.get_components(): - result.append([pyopenssl_normalize_name(sub[0]), to_text(sub[1])]) - return result - - def _get_subject_ordered(self): - return self.__get_name(self.csr.get_subject()) - - def _get_extension(self, short_name): - for extension in self.csr.get_extensions(): - if extension.get_short_name() == short_name: - result = [ - pyopenssl_normalize_name(usage.strip()) for usage in to_text(extension, errors='surrogate_or_strict').split(',') - ] - return sorted(result), bool(extension.get_critical()) - return None, False - - def _get_key_usage(self): - return self._get_extension(b'keyUsage') - - def _get_extended_key_usage(self): - return self._get_extension(b'extendedKeyUsage') - - def _get_basic_constraints(self): - return self._get_extension(b'basicConstraints') - - def _get_ocsp_must_staple(self): - extensions = self.csr.get_extensions() - oms_ext = [ - ext for ext in extensions - if to_bytes(ext.get_short_name()) == OPENSSL_MUST_STAPLE_NAME and to_bytes(ext) == OPENSSL_MUST_STAPLE_VALUE - ] - if OpenSSL.SSL.OPENSSL_VERSION_NUMBER < 0x10100000: - # Older versions of libssl don't know about OCSP Must Staple - oms_ext.extend([ext for ext in extensions if ext.get_short_name() == b'UNDEF' and ext.get_data() == b'\x30\x03\x02\x01\x05']) - if oms_ext: - return True, bool(oms_ext[0].get_critical()) - else: - return None, False - - def _get_subject_alt_name(self): - for extension in self.csr.get_extensions(): - if extension.get_short_name() == b'subjectAltName': - result = [pyopenssl_normalize_name_attribute(altname.strip()) for altname in - to_text(extension, errors='surrogate_or_strict').split(', ')] - return result, bool(extension.get_critical()) - return None, False - - def _get_name_constraints(self): - for extension in self.csr.get_extensions(): - if extension.get_short_name() == b'nameConstraints': - permitted, excluded = pyopenssl_parse_name_constraints(extension) - return permitted, excluded, bool(extension.get_critical()) - return None, None, False - - def _get_public_key_pem(self): - try: - return crypto.dump_publickey( - crypto.FILETYPE_PEM, - self.csr.get_pubkey(), - ) - except AttributeError: - try: - bio = crypto._new_mem_buf() - rc = crypto._lib.PEM_write_bio_PUBKEY(bio, self.csr.get_pubkey()._pkey) - if rc != 1: - crypto._raise_current_error() - return crypto._bio_to_string(bio) - except AttributeError: - self.module.warn('Your pyOpenSSL version does not support dumping public keys. ' - 'Please upgrade to version 16.0 or newer, or use the cryptography backend.') - - def _get_public_key_object(self): - return self.csr.get_pubkey() - - def _get_subject_key_identifier(self): - # Won't be implemented - return None - - def _get_authority_key_identifier(self): - # Won't be implemented - return None, None, None - - def _get_all_extensions(self): - return pyopenssl_get_extensions_from_csr(self.csr) - - def _is_signature_valid(self): - try: - return bool(self.csr.verify(self.csr.get_pubkey())) - except crypto.Error: - # OpenSSL error means that key is not consistent - return False - - def get_csr_info(module, backend, content, validate_signature=True, prefer_one_fingerprint=False): if backend == 'cryptography': info = CSRInfoRetrievalCryptography(module, content, validate_signature=validate_signature) - elif backend == 'pyopenssl': - info = CSRInfoRetrievalPyOpenSSL(module, content, validate_signature=validate_signature) return info.get_info(prefer_one_fingerprint=prefer_one_fingerprint) @@ -445,34 +314,17 @@ def select_backend(module, backend, content, validate_signature=True): if backend == 'auto': # Detection what is possible can_use_cryptography = CRYPTOGRAPHY_FOUND and CRYPTOGRAPHY_VERSION >= LooseVersion(MINIMAL_CRYPTOGRAPHY_VERSION) - can_use_pyopenssl = PYOPENSSL_FOUND and PYOPENSSL_VERSION >= LooseVersion(MINIMAL_PYOPENSSL_VERSION) - # First try cryptography, then pyOpenSSL + # Try cryptography if can_use_cryptography: backend = 'cryptography' - elif can_use_pyopenssl: - backend = 'pyopenssl' # Success? if backend == 'auto': - module.fail_json(msg=("Can't detect any of the required Python libraries " - "cryptography (>= {0}) or PyOpenSSL (>= {1})").format( - MINIMAL_CRYPTOGRAPHY_VERSION, - MINIMAL_PYOPENSSL_VERSION)) + module.fail_json(msg=("Can't detect the required Python library " + "cryptography (>= {0})").format(MINIMAL_CRYPTOGRAPHY_VERSION)) - if backend == 'pyopenssl': - if not PYOPENSSL_FOUND: - module.fail_json(msg=missing_required_lib('pyOpenSSL >= {0}'.format(MINIMAL_PYOPENSSL_VERSION)), - exception=PYOPENSSL_IMP_ERR) - try: - getattr(crypto.X509Req, 'get_extensions') - except AttributeError: - module.fail_json(msg='You need to have PyOpenSSL>=0.15 to generate CSRs') - - module.deprecate('The module is using the PyOpenSSL backend. This backend has been deprecated', - version='2.0.0', collection_name='community.crypto') - return backend, CSRInfoRetrievalPyOpenSSL(module, content, validate_signature=validate_signature) - elif backend == 'cryptography': + if backend == 'cryptography': if not CRYPTOGRAPHY_FOUND: module.fail_json(msg=missing_required_lib('cryptography >= {0}'.format(MINIMAL_CRYPTOGRAPHY_VERSION)), exception=CRYPTOGRAPHY_IMP_ERR) diff --git a/plugins/module_utils/crypto/module_backends/privatekey.py b/plugins/module_utils/crypto/module_backends/privatekey.py index ffeea026..4beed041 100644 --- a/plugins/module_utils/crypto/module_backends/privatekey.py +++ b/plugins/module_utils/crypto/module_backends/privatekey.py @@ -46,20 +46,8 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.module_bac from ansible_collections.community.crypto.plugins.module_utils.crypto.module_backends.common import ArgumentSpec -MINIMAL_PYOPENSSL_VERSION = '0.6' MINIMAL_CRYPTOGRAPHY_VERSION = '1.2.3' -PYOPENSSL_IMP_ERR = None -try: - import OpenSSL - from OpenSSL import crypto - PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__) -except ImportError: - PYOPENSSL_IMP_ERR = traceback.format_exc() - PYOPENSSL_FOUND = False -else: - PYOPENSSL_FOUND = True - CRYPTOGRAPHY_IMP_ERR = None try: import cryptography @@ -263,61 +251,6 @@ class PrivateKeyBackend: return result -# Implementation with using pyOpenSSL -class PrivateKeyPyOpenSSLBackend(PrivateKeyBackend): - - def __init__(self, module): - super(PrivateKeyPyOpenSSLBackend, self).__init__(module=module, backend='pyopenssl') - - if self.type == 'RSA': - self.openssl_type = crypto.TYPE_RSA - elif self.type == 'DSA': - self.openssl_type = crypto.TYPE_DSA - else: - self.module.fail_json(msg="PyOpenSSL backend only supports RSA and DSA keys.") - - if self.format != 'auto_ignore': - self.module.fail_json(msg="PyOpenSSL backend only supports auto_ignore format.") - - def generate_private_key(self): - """(Re-)Generate private key.""" - self.private_key = crypto.PKey() - try: - self.private_key.generate_key(self.openssl_type, self.size) - except (TypeError, ValueError) as exc: - raise PrivateKeyError(exc) - - def _ensure_existing_private_key_loaded(self): - if self.existing_private_key is None and self.has_existing(): - try: - self.existing_private_key = load_privatekey( - None, self.passphrase, content=self.existing_private_key_bytes, backend=self.backend) - except OpenSSLBadPassphraseError as exc: - raise PrivateKeyError(exc) - - def get_private_key_data(self): - """Return bytes for self.private_key""" - if self.cipher and self.passphrase: - return crypto.dump_privatekey(crypto.FILETYPE_PEM, self.private_key, - self.cipher, to_bytes(self.passphrase)) - else: - return crypto.dump_privatekey(crypto.FILETYPE_PEM, self.private_key) - - def _check_passphrase(self): - try: - load_privatekey(None, self.passphrase, content=self.existing_private_key_bytes, backend=self.backend) - return True - except Exception as dummy: - return False - - def _check_size_and_type(self): - return self.size == self.existing_private_key.bits() and self.openssl_type == self.existing_private_key.type() - - def _check_format(self): - # Not supported by this backend - return True - - # Implementation with using cryptography class PrivateKeyCryptographyBackend(PrivateKeyBackend): @@ -550,36 +483,16 @@ def select_backend(module, backend): if backend == 'auto': # Detection what is possible can_use_cryptography = CRYPTOGRAPHY_FOUND and CRYPTOGRAPHY_VERSION >= LooseVersion(MINIMAL_CRYPTOGRAPHY_VERSION) - can_use_pyopenssl = PYOPENSSL_FOUND and PYOPENSSL_VERSION >= LooseVersion(MINIMAL_PYOPENSSL_VERSION) # Decision - if module.params['cipher'] and module.params['passphrase'] and module.params['cipher'] != 'auto': - # First try pyOpenSSL, then cryptography - if can_use_pyopenssl: - backend = 'pyopenssl' - elif can_use_cryptography: - backend = 'cryptography' - else: - # First try cryptography, then pyOpenSSL - if can_use_cryptography: - backend = 'cryptography' - elif can_use_pyopenssl: - backend = 'pyopenssl' + if can_use_cryptography: + backend = 'cryptography' # Success? if backend == 'auto': - module.fail_json(msg=("Can't detect any of the required Python libraries " - "cryptography (>= {0}) or PyOpenSSL (>= {1})").format( - MINIMAL_CRYPTOGRAPHY_VERSION, - MINIMAL_PYOPENSSL_VERSION)) - if backend == 'pyopenssl': - if not PYOPENSSL_FOUND: - module.fail_json(msg=missing_required_lib('pyOpenSSL >= {0}'.format(MINIMAL_PYOPENSSL_VERSION)), - exception=PYOPENSSL_IMP_ERR) - module.deprecate('The module is using the PyOpenSSL backend. This backend has been deprecated', - version='2.0.0', collection_name='community.crypto') - return backend, PrivateKeyPyOpenSSLBackend(module) - elif backend == 'cryptography': + module.fail_json(msg=("Can't detect the required Python library " + "cryptography (>= {0})").format(MINIMAL_CRYPTOGRAPHY_VERSION)) + if backend == 'cryptography': if not CRYPTOGRAPHY_FOUND: module.fail_json(msg=missing_required_lib('cryptography >= {0}'.format(MINIMAL_CRYPTOGRAPHY_VERSION)), exception=CRYPTOGRAPHY_IMP_ERR) @@ -605,7 +518,7 @@ def get_privatekey_argument_spec(): cipher=dict(type='str'), format=dict(type='str', default='auto_ignore', choices=['pkcs1', 'pkcs8', 'raw', 'auto', 'auto_ignore']), format_mismatch=dict(type='str', default='regenerate', choices=['regenerate', 'convert']), - select_crypto_backend=dict(type='str', choices=['auto', 'pyopenssl', 'cryptography'], default='auto'), + select_crypto_backend=dict(type='str', choices=['auto', 'cryptography'], default='auto'), regenerate=dict( type='str', default='full_idempotence', diff --git a/plugins/module_utils/crypto/module_backends/privatekey_info.py b/plugins/module_utils/crypto/module_backends/privatekey_info.py index c5431473..00bb484f 100644 --- a/plugins/module_utils/crypto/module_backends/privatekey_info.py +++ b/plugins/module_utils/crypto/module_backends/privatekey_info.py @@ -36,24 +36,10 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.math impor from ansible_collections.community.crypto.plugins.module_utils.crypto.module_backends.publickey_info import ( _get_cryptography_public_key_info, - _bigint_to_int, - _get_pyopenssl_public_key_info, ) MINIMAL_CRYPTOGRAPHY_VERSION = '1.2.3' -MINIMAL_PYOPENSSL_VERSION = '0.15' - -PYOPENSSL_IMP_ERR = None -try: - import OpenSSL - from OpenSSL import crypto - PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__) -except ImportError: - PYOPENSSL_IMP_ERR = traceback.format_exc() - PYOPENSSL_FOUND = False -else: - PYOPENSSL_FOUND = True CRYPTOGRAPHY_IMP_ERR = None try: @@ -265,135 +251,10 @@ class PrivateKeyInfoRetrievalCryptography(PrivateKeyInfoRetrieval): return _is_cryptography_key_consistent(self.key, key_public_data, key_private_data) -class PrivateKeyInfoRetrievalPyOpenSSL(PrivateKeyInfoRetrieval): - """validate the supplied private key.""" - - def __init__(self, module, content, **kwargs): - super(PrivateKeyInfoRetrievalPyOpenSSL, self).__init__(module, 'pyopenssl', content, **kwargs) - - def _get_public_key(self, binary): - try: - return crypto.dump_publickey( - crypto.FILETYPE_ASN1 if binary else crypto.FILETYPE_PEM, - self.key - ) - except AttributeError: - try: - # pyOpenSSL < 16.0: - bio = crypto._new_mem_buf() - if binary: - rc = crypto._lib.i2d_PUBKEY_bio(bio, self.key._pkey) - else: - rc = crypto._lib.PEM_write_bio_PUBKEY(bio, self.key._pkey) - if rc != 1: - crypto._raise_current_error() - return crypto._bio_to_string(bio) - except AttributeError: - self.module.warn('Your pyOpenSSL version does not support dumping public keys. ' - 'Please upgrade to version 16.0 or newer, or use the cryptography backend.') - - def _get_key_info(self): - key_type, key_public_data, try_fallback = _get_pyopenssl_public_key_info(self.key) - key_private_data = dict() - openssl_key_type = self.key.type() - if crypto.TYPE_RSA == openssl_key_type: - try: - # Use OpenSSL directly to extract key data - key = OpenSSL._util.lib.EVP_PKEY_get1_RSA(self.key._pkey) - key = OpenSSL._util.ffi.gc(key, OpenSSL._util.lib.RSA_free) - # OpenSSL 1.1 and newer have functions to extract the parameters - # from the EVP PKEY data structures. Older versions didn't have - # these getters, and it was common use to simply access the values - # directly. Since there's no guarantee that these data structures - # will still be accessible in the future, we use the getters for - # 1.1 and later, and directly access the values for 1.0.x and - # earlier. - if OpenSSL.SSL.OPENSSL_VERSION_NUMBER >= 0x10100000: - # Get modulus and exponents - n = OpenSSL._util.ffi.new("BIGNUM **") - e = OpenSSL._util.ffi.new("BIGNUM **") - d = OpenSSL._util.ffi.new("BIGNUM **") - OpenSSL._util.lib.RSA_get0_key(key, n, e, d) - key_private_data['exponent'] = _bigint_to_int(d[0]) - # Get factors - p = OpenSSL._util.ffi.new("BIGNUM **") - q = OpenSSL._util.ffi.new("BIGNUM **") - OpenSSL._util.lib.RSA_get0_factors(key, p, q) - key_private_data['p'] = _bigint_to_int(p[0]) - key_private_data['q'] = _bigint_to_int(q[0]) - else: - # Get private exponent - key_private_data['exponent'] = _bigint_to_int(key.d) - # Get factors - key_private_data['p'] = _bigint_to_int(key.p) - key_private_data['q'] = _bigint_to_int(key.q) - except AttributeError: - try_fallback = True - elif crypto.TYPE_DSA == openssl_key_type: - try: - # Use OpenSSL directly to extract key data - key = OpenSSL._util.lib.EVP_PKEY_get1_DSA(self.key._pkey) - key = OpenSSL._util.ffi.gc(key, OpenSSL._util.lib.DSA_free) - # OpenSSL 1.1 and newer have functions to extract the parameters - # from the EVP PKEY data structures. Older versions didn't have - # these getters, and it was common use to simply access the values - # directly. Since there's no guarantee that these data structures - # will still be accessible in the future, we use the getters for - # 1.1 and later, and directly access the values for 1.0.x and - # earlier. - if OpenSSL.SSL.OPENSSL_VERSION_NUMBER >= 0x10100000: - # Get private key exponents - y = OpenSSL._util.ffi.new("BIGNUM **") - x = OpenSSL._util.ffi.new("BIGNUM **") - OpenSSL._util.lib.DSA_get0_key(key, y, x) - key_private_data['x'] = _bigint_to_int(x[0]) - else: - # Get private key exponents - key_private_data['x'] = _bigint_to_int(key.priv_key) - except AttributeError: - try_fallback = True - else: - # Return 'unknown' - key_type = 'unknown ({0})'.format(self.key.type()) - # If needed and if possible, fall back to cryptography - if try_fallback and PYOPENSSL_VERSION >= LooseVersion('16.1.0') and CRYPTOGRAPHY_FOUND: - return _get_cryptography_private_key_info(self.key.to_cryptography_key()) - return key_type, key_public_data, key_private_data - - def _is_key_consistent(self, key_public_data, key_private_data): - openssl_key_type = self.key.type() - if crypto.TYPE_RSA == openssl_key_type: - try: - return self.key.check() - except crypto.Error: - # OpenSSL error means that key is not consistent - return False - if crypto.TYPE_DSA == openssl_key_type: - result = _check_dsa_consistency(key_public_data, key_private_data) - if result is not None: - return result - signature = crypto.sign(self.key, SIGNATURE_TEST_DATA, 'sha256') - # Verify wants a cert (where it can get the public key from) - cert = crypto.X509() - cert.set_pubkey(self.key) - try: - crypto.verify(cert, signature, SIGNATURE_TEST_DATA, 'sha256') - return True - except crypto.Error: - return False - # If needed and if possible, fall back to cryptography - if PYOPENSSL_VERSION >= LooseVersion('16.1.0') and CRYPTOGRAPHY_FOUND: - return _is_cryptography_key_consistent(self.key.to_cryptography_key(), key_public_data, key_private_data) - return None - - def get_privatekey_info(module, backend, content, passphrase=None, return_private_key_data=False, prefer_one_fingerprint=False): if backend == 'cryptography': info = PrivateKeyInfoRetrievalCryptography( module, content, passphrase=passphrase, return_private_key_data=return_private_key_data) - elif backend == 'pyopenssl': - info = PrivateKeyInfoRetrievalPyOpenSSL( - module, content, passphrase=passphrase, return_private_key_data=return_private_key_data) return info.get_info(prefer_one_fingerprint=prefer_one_fingerprint) @@ -401,30 +262,17 @@ def select_backend(module, backend, content, passphrase=None, return_private_key if backend == 'auto': # Detection what is possible can_use_cryptography = CRYPTOGRAPHY_FOUND and CRYPTOGRAPHY_VERSION >= LooseVersion(MINIMAL_CRYPTOGRAPHY_VERSION) - can_use_pyopenssl = PYOPENSSL_FOUND and PYOPENSSL_VERSION >= LooseVersion(MINIMAL_PYOPENSSL_VERSION) - # First try cryptography, then pyOpenSSL + # Try cryptography if can_use_cryptography: backend = 'cryptography' - elif can_use_pyopenssl: - backend = 'pyopenssl' # Success? if backend == 'auto': - module.fail_json(msg=("Can't detect any of the required Python libraries " - "cryptography (>= {0}) or PyOpenSSL (>= {1})").format( - MINIMAL_CRYPTOGRAPHY_VERSION, - MINIMAL_PYOPENSSL_VERSION)) + module.fail_json(msg=("Can't detect the required Python library " + "cryptography (>= {0})").format(MINIMAL_CRYPTOGRAPHY_VERSION)) - if backend == 'pyopenssl': - if not PYOPENSSL_FOUND: - module.fail_json(msg=missing_required_lib('pyOpenSSL >= {0}'.format(MINIMAL_PYOPENSSL_VERSION)), - exception=PYOPENSSL_IMP_ERR) - module.deprecate('The module is using the PyOpenSSL backend. This backend has been deprecated', - version='2.0.0', collection_name='community.crypto') - return backend, PrivateKeyInfoRetrievalPyOpenSSL( - module, content, passphrase=passphrase, return_private_key_data=return_private_key_data) - elif backend == 'cryptography': + if backend == 'cryptography': if not CRYPTOGRAPHY_FOUND: module.fail_json(msg=missing_required_lib('cryptography >= {0}'.format(MINIMAL_CRYPTOGRAPHY_VERSION)), exception=CRYPTOGRAPHY_IMP_ERR) diff --git a/plugins/module_utils/crypto/module_backends/publickey_info.py b/plugins/module_utils/crypto/module_backends/publickey_info.py index 345a1bb7..00d19d38 100644 --- a/plugins/module_utils/crypto/module_backends/publickey_info.py +++ b/plugins/module_utils/crypto/module_backends/publickey_info.py @@ -31,18 +31,6 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.support im MINIMAL_CRYPTOGRAPHY_VERSION = '1.2.3' -MINIMAL_PYOPENSSL_VERSION = '16.0.0' # when working with public key objects, the minimal required version is 0.15 - -PYOPENSSL_IMP_ERR = None -try: - import OpenSSL - from OpenSSL import crypto - PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__) -except ImportError: - PYOPENSSL_IMP_ERR = traceback.format_exc() - PYOPENSSL_FOUND = False -else: - PYOPENSSL_FOUND = True CRYPTOGRAPHY_IMP_ERR = None try: @@ -93,98 +81,6 @@ def _get_cryptography_public_key_info(key): return key_type, key_public_data -def _bigint_to_int(bn): - '''Convert OpenSSL BIGINT to Python integer''' - if bn == OpenSSL._util.ffi.NULL: - return None - hexstr = OpenSSL._util.lib.BN_bn2hex(bn) - try: - return int(OpenSSL._util.ffi.string(hexstr), 16) - finally: - OpenSSL._util.lib.OPENSSL_free(hexstr) - - -def _get_pyopenssl_public_key_info(key): - key_public_data = dict() - try_fallback = True - openssl_key_type = key.type() - if crypto.TYPE_RSA == openssl_key_type: - key_type = 'RSA' - key_public_data['size'] = key.bits() - - try: - # Use OpenSSL directly to extract key data - key = OpenSSL._util.lib.EVP_PKEY_get1_RSA(key._pkey) - key = OpenSSL._util.ffi.gc(key, OpenSSL._util.lib.RSA_free) - # OpenSSL 1.1 and newer have functions to extract the parameters - # from the EVP PKEY data structures. Older versions didn't have - # these getters, and it was common use to simply access the values - # directly. Since there's no guarantee that these data structures - # will still be accessible in the future, we use the getters for - # 1.1 and later, and directly access the values for 1.0.x and - # earlier. - if OpenSSL.SSL.OPENSSL_VERSION_NUMBER >= 0x10100000: - # Get modulus and exponents - n = OpenSSL._util.ffi.new("BIGNUM **") - e = OpenSSL._util.ffi.new("BIGNUM **") - d = OpenSSL._util.ffi.new("BIGNUM **") - OpenSSL._util.lib.RSA_get0_key(key, n, e, d) - key_public_data['modulus'] = _bigint_to_int(n[0]) - key_public_data['exponent'] = _bigint_to_int(e[0]) - else: - # Get modulus and exponents - key_public_data['modulus'] = _bigint_to_int(key.n) - key_public_data['exponent'] = _bigint_to_int(key.e) - try_fallback = False - except AttributeError: - # Use fallback if available - pass - elif crypto.TYPE_DSA == openssl_key_type: - key_type = 'DSA' - key_public_data['size'] = key.bits() - - try: - # Use OpenSSL directly to extract key data - key = OpenSSL._util.lib.EVP_PKEY_get1_DSA(key._pkey) - key = OpenSSL._util.ffi.gc(key, OpenSSL._util.lib.DSA_free) - # OpenSSL 1.1 and newer have functions to extract the parameters - # from the EVP PKEY data structures. Older versions didn't have - # these getters, and it was common use to simply access the values - # directly. Since there's no guarantee that these data structures - # will still be accessible in the future, we use the getters for - # 1.1 and later, and directly access the values for 1.0.x and - # earlier. - if OpenSSL.SSL.OPENSSL_VERSION_NUMBER >= 0x10100000: - # Get public parameters (primes and group element) - p = OpenSSL._util.ffi.new("BIGNUM **") - q = OpenSSL._util.ffi.new("BIGNUM **") - g = OpenSSL._util.ffi.new("BIGNUM **") - OpenSSL._util.lib.DSA_get0_pqg(key, p, q, g) - key_public_data['p'] = _bigint_to_int(p[0]) - key_public_data['q'] = _bigint_to_int(q[0]) - key_public_data['g'] = _bigint_to_int(g[0]) - # Get public key exponents - y = OpenSSL._util.ffi.new("BIGNUM **") - x = OpenSSL._util.ffi.new("BIGNUM **") - OpenSSL._util.lib.DSA_get0_key(key, y, x) - key_public_data['y'] = _bigint_to_int(y[0]) - else: - # Get public parameters (primes and group element) - key_public_data['p'] = _bigint_to_int(key.p) - key_public_data['q'] = _bigint_to_int(key.q) - key_public_data['g'] = _bigint_to_int(key.g) - # Get public key exponents - key_public_data['y'] = _bigint_to_int(key.pub_key) - try_fallback = False - except AttributeError: - # Use fallback if available - pass - else: - # Return 'unknown' - key_type = 'unknown ({0})'.format(key.type()) - return key_type, key_public_data, try_fallback - - class PublicKeyParseError(OpenSSLObjectError): def __init__(self, msg, result): super(PublicKeyParseError, self).__init__(msg) @@ -242,46 +138,9 @@ class PublicKeyInfoRetrievalCryptography(PublicKeyInfoRetrieval): return _get_cryptography_public_key_info(self.key) -class PublicKeyInfoRetrievalPyOpenSSL(PublicKeyInfoRetrieval): - """validate the supplied public key.""" - - def __init__(self, module, content=None, key=None): - super(PublicKeyInfoRetrievalPyOpenSSL, self).__init__(module, 'pyopenssl', content=content, key=key) - - def _get_public_key(self, binary): - try: - return crypto.dump_publickey( - crypto.FILETYPE_ASN1 if binary else crypto.FILETYPE_PEM, - self.key - ) - except AttributeError: - try: - # pyOpenSSL < 16.0: - bio = crypto._new_mem_buf() - if binary: - rc = crypto._lib.i2d_PUBKEY_bio(bio, self.key._pkey) - else: - rc = crypto._lib.PEM_write_bio_PUBKEY(bio, self.key._pkey) - if rc != 1: - crypto._raise_current_error() - return crypto._bio_to_string(bio) - except AttributeError: - self.module.warn('Your pyOpenSSL version does not support dumping public keys. ' - 'Please upgrade to version 16.0 or newer, or use the cryptography backend.') - - def _get_key_info(self): - key_type, key_public_data, try_fallback = _get_pyopenssl_public_key_info(self.key) - # If needed and if possible, fall back to cryptography - if try_fallback and PYOPENSSL_VERSION >= LooseVersion('16.1.0') and CRYPTOGRAPHY_FOUND: - return _get_cryptography_public_key_info(self.key.to_cryptography_key()) - return key_type, key_public_data - - def get_publickey_info(module, backend, content=None, key=None, prefer_one_fingerprint=False): if backend == 'cryptography': info = PublicKeyInfoRetrievalCryptography(module, content=content, key=key) - elif backend == 'pyopenssl': - info = PublicKeyInfoRetrievalPyOpenSSL(module, content=content, key=key) return info.get_info(prefer_one_fingerprint=prefer_one_fingerprint) @@ -289,29 +148,17 @@ def select_backend(module, backend, content=None, key=None): if backend == 'auto': # Detection what is possible can_use_cryptography = CRYPTOGRAPHY_FOUND and CRYPTOGRAPHY_VERSION >= LooseVersion(MINIMAL_CRYPTOGRAPHY_VERSION) - can_use_pyopenssl = PYOPENSSL_FOUND and PYOPENSSL_VERSION >= LooseVersion(MINIMAL_PYOPENSSL_VERSION) - # First try cryptography, then pyOpenSSL + # Try cryptography if can_use_cryptography: backend = 'cryptography' - elif can_use_pyopenssl: - backend = 'pyopenssl' # Success? if backend == 'auto': module.fail_json(msg=("Can't detect any of the required Python libraries " - "cryptography (>= {0}) or PyOpenSSL (>= {1})").format( - MINIMAL_CRYPTOGRAPHY_VERSION, - MINIMAL_PYOPENSSL_VERSION)) + "cryptography (>= {0})").format(MINIMAL_CRYPTOGRAPHY_VERSION)) - if backend == 'pyopenssl': - if not PYOPENSSL_FOUND: - module.fail_json(msg=missing_required_lib('pyOpenSSL >= {0}'.format(MINIMAL_PYOPENSSL_VERSION)), - exception=PYOPENSSL_IMP_ERR) - module.deprecate('The module is using the PyOpenSSL backend. This backend has been deprecated', - version='2.0.0', collection_name='community.crypto') - return backend, PublicKeyInfoRetrievalPyOpenSSL(module, content=content, key=key) - elif backend == 'cryptography': + if backend == 'cryptography': if not CRYPTOGRAPHY_FOUND: module.fail_json(msg=missing_required_lib('cryptography >= {0}'.format(MINIMAL_CRYPTOGRAPHY_VERSION)), exception=CRYPTOGRAPHY_IMP_ERR) diff --git a/plugins/module_utils/crypto/pyopenssl_support.py b/plugins/module_utils/crypto/pyopenssl_support.py deleted file mode 100644 index 4e0ae617..00000000 --- a/plugins/module_utils/crypto/pyopenssl_support.py +++ /dev/null @@ -1,154 +0,0 @@ -# -*- coding: utf-8 -*- -# -# (c) 2019, Felix Fontein -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -import base64 - -from ansible.module_utils.common.text.converters import to_bytes, to_text - -from ansible_collections.community.crypto.plugins.module_utils.compat import ipaddress as compat_ipaddress - -try: - import OpenSSL -except ImportError: - # Error handled in the calling module. - pass - -from ._objects import ( - NORMALIZE_NAMES_SHORT, - NORMALIZE_NAMES, -) - -from ._obj2txt import obj2txt - -from .basic import ( - OpenSSLObjectError, -) - - -def pyopenssl_normalize_name(name, short=False): - nid = OpenSSL._util.lib.OBJ_txt2nid(to_bytes(name)) - if nid != 0: - b_name = OpenSSL._util.lib.OBJ_nid2ln(nid) - name = to_text(OpenSSL._util.ffi.string(b_name)) - if short: - return NORMALIZE_NAMES_SHORT.get(name, name) - else: - return NORMALIZE_NAMES.get(name, name) - - -def pyopenssl_normalize_name_attribute(san): - # apparently openssl returns 'IP address' not 'IP' as specifier when converting the subjectAltName to string - # although it won't accept this specifier when generating the CSR. (https://github.com/openssl/openssl/issues/4004) - if san.startswith('IP Address:'): - san = 'IP:' + san[len('IP Address:'):] - if san.startswith('IP:'): - address = san[3:] - if '/' in address: - ip = compat_ipaddress.ip_network(address) - san = 'IP:{0}/{1}'.format(ip.network_address.compressed, ip.prefixlen) - else: - ip = compat_ipaddress.ip_address(address) - san = 'IP:{0}'.format(ip.compressed) - if san.startswith('Registered ID:'): - san = 'RID:' + san[len('Registered ID:'):] - # Some versions of OpenSSL apparently forgot the colon. Happens in CI with Ubuntu 16.04 and FreeBSD 11.1 - if san.startswith('Registered ID'): - san = 'RID:' + san[len('Registered ID'):] - return san - - -def pyopenssl_get_extensions_from_cert(cert): - # While pyOpenSSL allows us to get an extension's DER value, it won't - # give us the dotted string for an OID. So we have to do some magic to - # get hold of it. - result = dict() - ext_count = cert.get_extension_count() - for i in range(0, ext_count): - ext = cert.get_extension(i) - entry = dict( - critical=bool(ext.get_critical()), - value=base64.b64encode(ext.get_data()), - ) - oid = obj2txt( - OpenSSL._util.lib, - OpenSSL._util.ffi, - OpenSSL._util.lib.X509_EXTENSION_get_object(ext._extension) - ) - # This could also be done a bit simpler: - # - # oid = obj2txt(OpenSSL._util.lib, OpenSSL._util.ffi, OpenSSL._util.lib.OBJ_nid2obj(ext._nid)) - # - # Unfortunately this gives the wrong result in case the linked OpenSSL - # doesn't know the OID. That's why we have to get the OID dotted string - # similarly to how cryptography does it. - result[oid] = entry - return result - - -def pyopenssl_get_extensions_from_csr(csr): - # While pyOpenSSL allows us to get an extension's DER value, it won't - # give us the dotted string for an OID. So we have to do some magic to - # get hold of it. - result = dict() - for ext in csr.get_extensions(): - entry = dict( - critical=bool(ext.get_critical()), - value=base64.b64encode(ext.get_data()), - ) - oid = obj2txt( - OpenSSL._util.lib, - OpenSSL._util.ffi, - OpenSSL._util.lib.X509_EXTENSION_get_object(ext._extension) - ) - # This could also be done a bit simpler: - # - # oid = obj2txt(OpenSSL._util.lib, OpenSSL._util.ffi, OpenSSL._util.lib.OBJ_nid2obj(ext._nid)) - # - # Unfortunately this gives the wrong result in case the linked OpenSSL - # doesn't know the OID. That's why we have to get the OID dotted string - # similarly to how cryptography does it. - result[oid] = entry - return result - - -def pyopenssl_parse_name_constraints(name_constraints_extension): - lines = to_text(name_constraints_extension, errors='surrogate_or_strict').splitlines() - exclude = None - excluded = [] - permitted = [] - for line in lines: - if line.startswith(' ') or line.startswith('\t'): - name = pyopenssl_normalize_name_attribute(line.strip()) - if exclude is True: - excluded.append(name) - elif exclude is False: - permitted.append(name) - else: - raise OpenSSLObjectError('Unexpected nameConstraint line: "{0}"'.format(line)) - else: - line_lc = line.lower() - if line_lc.startswith('exclud'): - exclude = True - elif line_lc.startswith('includ') or line_lc.startswith('permitt'): - exclude = False - else: - raise OpenSSLObjectError('Cannot parse nameConstraint line: "{0}"'.format(line)) - return permitted, excluded diff --git a/plugins/module_utils/crypto/support.py b/plugins/module_utils/crypto/support.py index 67b7226c..b6bc2fa8 100644 --- a/plugins/module_utils/crypto/support.py +++ b/plugins/module_utils/crypto/support.py @@ -98,25 +98,10 @@ def get_fingerprint_of_bytes(source, prefer_one=False): return fingerprint -def get_fingerprint_of_privatekey(privatekey, backend='pyopenssl', prefer_one=False): +def get_fingerprint_of_privatekey(privatekey, backend='cryptography', prefer_one=False): """Generate the fingerprint of the public key. """ - if backend == 'pyopenssl': - try: - publickey = crypto.dump_publickey(crypto.FILETYPE_ASN1, privatekey) - except AttributeError: - # If PyOpenSSL < 16.0 crypto.dump_publickey() will fail. - try: - bio = crypto._new_mem_buf() - rc = crypto._lib.i2d_PUBKEY_bio(bio, privatekey._pkey) - if rc != 1: - crypto._raise_current_error() - publickey = crypto._bio_to_string(bio) - except AttributeError: - # By doing this we prevent the code from raising an error - # yet we return no value in the fingerprint hash. - return None - elif backend == 'cryptography': + if backend == 'cryptography': publickey = privatekey.public_key().public_bytes( serialization.Encoding.DER, serialization.PublicFormat.SubjectPublicKeyInfo @@ -125,7 +110,7 @@ def get_fingerprint_of_privatekey(privatekey, backend='pyopenssl', prefer_one=Fa return get_fingerprint_of_bytes(publickey, prefer_one=prefer_one) -def get_fingerprint(path, passphrase=None, content=None, backend='pyopenssl', prefer_one=False): +def get_fingerprint(path, passphrase=None, content=None, backend='cryptography', prefer_one=False): """Generate the fingerprint of the public key. """ privatekey = load_privatekey(path, passphrase=passphrase, content=content, check_passphrase=False, backend=backend) @@ -133,7 +118,7 @@ def get_fingerprint(path, passphrase=None, content=None, backend='pyopenssl', pr return get_fingerprint_of_privatekey(privatekey, backend=backend, prefer_one=prefer_one) -def load_privatekey(path, passphrase=None, check_passphrase=True, content=None, backend='pyopenssl'): +def load_privatekey(path, passphrase=None, check_passphrase=True, content=None, backend='cryptography'): """Load the specified OpenSSL private key. The content can also be specified via content; in that case, @@ -213,14 +198,9 @@ def load_publickey(path=None, content=None, backend=None): return serialization.load_pem_public_key(content, backend=cryptography_backend()) except Exception as e: raise OpenSSLObjectError('Error while deserializing key: {0}'.format(e)) - else: - try: - return crypto.load_publickey(crypto.FILETYPE_PEM, content) - except crypto.Error as e: - raise OpenSSLObjectError('Error while deserializing key: {0}'.format(e)) -def load_certificate(path, content=None, backend='pyopenssl'): +def load_certificate(path, content=None, backend='cryptography'): """Load the specified certificate.""" try: @@ -240,7 +220,7 @@ def load_certificate(path, content=None, backend='pyopenssl'): raise OpenSSLObjectError(exc) -def load_certificate_request(path, content=None, backend='pyopenssl'): +def load_certificate_request(path, content=None, backend='cryptography'): """Load the specified certificate signing request.""" try: if content is None: @@ -250,9 +230,7 @@ def load_certificate_request(path, content=None, backend='pyopenssl'): csr_content = content except (IOError, OSError) as exc: raise OpenSSLObjectError(exc) - if backend == 'pyopenssl': - return crypto.load_certificate_request(crypto.FILETYPE_PEM, csr_content) - elif backend == 'cryptography': + if backend == 'cryptography': try: return x509.load_pem_x509_csr(csr_content, cryptography_backend()) except ValueError as exc: @@ -322,9 +300,7 @@ def get_relative_time_option(input_string, input_name, backend='cryptography'): elif backend == 'cryptography': return result_datetime # Absolute time - if backend == 'pyopenssl': - return input_string - elif backend == 'cryptography': + if backend == 'cryptography': for date_fmt in ['%Y%m%d%H%M%SZ', '%Y%m%d%H%MZ', '%Y%m%d%H%M%S%z', '%Y%m%d%H%M%z']: try: return datetime.datetime.strptime(result, date_fmt) diff --git a/plugins/modules/get_certificate.py b/plugins/modules/get_certificate.py index 3fd5fb90..2436917b 100644 --- a/plugins/modules/get_certificate.py +++ b/plugins/modules/get_certificate.py @@ -14,10 +14,7 @@ author: "John Westcott IV (@john-westcott-iv)" short_description: Get a certificate from a host:port description: - Makes a secure connection and returns information about the presented certificate - - "The module can use the cryptography Python library, or the pyOpenSSL Python - library. By default, it tries to detect which one is available. This can be - overridden with the I(select_crypto_backend) option. Please note that the PyOpenSSL - backend was deprecated in Ansible 2.9 and will be removed in community.crypto 2.0.0." + - The module uses the cryptography Python library. - Support SNI (L(Server Name Indication,https://en.wikipedia.org/wiki/Server_Name_Indication)) only with python >= 2.7. options: host: @@ -66,19 +63,18 @@ options: select_crypto_backend: description: - Determines which crypto backend to use. - - The default choice is C(auto), which tries to use C(cryptography) if available, and falls back to C(pyopenssl). - - If set to C(pyopenssl), will try to use the L(pyOpenSSL,https://pypi.org/project/pyOpenSSL/) library. + - The default choice is C(auto), which tries to use C(cryptography) if available. - If set to C(cryptography), will try to use the L(cryptography,https://cryptography.io/) library. type: str default: auto - choices: [ auto, cryptography, pyopenssl ] + choices: [ auto, cryptography ] notes: - When using ca_cert on OS X it has been reported that in some conditions the validate will always succeed. requirements: - "python >= 2.7 when using C(proxy_host)" - - "cryptography >= 1.6 or pyOpenSSL >= 0.15" + - "cryptography >= 1.6" ''' RETURN = ''' @@ -180,7 +176,6 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.cryptograp cryptography_get_extensions_from_cert, ) -MINIMAL_PYOPENSSL_VERSION = '0.15' MINIMAL_CRYPTOGRAPHY_VERSION = '1.6' CREATE_DEFAULT_CONTEXT_IMP_ERR = None @@ -192,17 +187,6 @@ except ImportError: else: HAS_CREATE_DEFAULT_CONTEXT = True -PYOPENSSL_IMP_ERR = None -try: - import OpenSSL - from OpenSSL import crypto - PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__) -except ImportError: - PYOPENSSL_IMP_ERR = traceback.format_exc() - PYOPENSSL_FOUND = False -else: - PYOPENSSL_FOUND = True - CRYPTOGRAPHY_IMP_ERR = None try: import cryptography @@ -241,7 +225,7 @@ def main(): proxy_port=dict(type='int', default=8080), server_name=dict(type='str'), timeout=dict(type='int', default=10), - select_crypto_backend=dict(type='str', choices=['auto', 'pyopenssl', 'cryptography'], default='auto'), + select_crypto_backend=dict(type='str', choices=['auto', 'cryptography'], default='auto'), starttls=dict(type='str', choices=['mysql']), ), ) @@ -259,28 +243,17 @@ def main(): if backend == 'auto': # Detection what is possible can_use_cryptography = CRYPTOGRAPHY_FOUND and CRYPTOGRAPHY_VERSION >= LooseVersion(MINIMAL_CRYPTOGRAPHY_VERSION) - can_use_pyopenssl = PYOPENSSL_FOUND and PYOPENSSL_VERSION >= LooseVersion(MINIMAL_PYOPENSSL_VERSION) - # First try cryptography, then pyOpenSSL + # Try cryptography if can_use_cryptography: backend = 'cryptography' - elif can_use_pyopenssl: - backend = 'pyopenssl' # Success? if backend == 'auto': - module.fail_json(msg=("Can't detect any of the required Python libraries " - "cryptography (>= {0}) or PyOpenSSL (>= {1})").format( - MINIMAL_CRYPTOGRAPHY_VERSION, - MINIMAL_PYOPENSSL_VERSION)) + module.fail_json(msg=("Can't detect the required Python library " + "cryptography (>= {0})").format(MINIMAL_CRYPTOGRAPHY_VERSION)) - if backend == 'pyopenssl': - if not PYOPENSSL_FOUND: - module.fail_json(msg=missing_required_lib('pyOpenSSL >= {0}'.format(MINIMAL_PYOPENSSL_VERSION)), - exception=PYOPENSSL_IMP_ERR) - module.deprecate('The module is using the PyOpenSSL backend. This backend has been deprecated', - version='2.0.0', collection_name='community.crypto') - elif backend == 'cryptography': + if backend == 'cryptography': if not CRYPTOGRAPHY_FOUND: module.fail_json(msg=missing_required_lib('cryptography >= {0}'.format(MINIMAL_CRYPTOGRAPHY_VERSION)), exception=CRYPTOGRAPHY_IMP_ERR) @@ -343,37 +316,7 @@ def main(): result['cert'] = cert - if backend == 'pyopenssl': - x509 = crypto.load_certificate(crypto.FILETYPE_PEM, cert) - result['subject'] = {} - for component in x509.get_subject().get_components(): - result['subject'][component[0]] = component[1] - - result['expired'] = x509.has_expired() - - result['extensions'] = [] - extension_count = x509.get_extension_count() - for index in range(0, extension_count): - extension = x509.get_extension(index) - result['extensions'].append({ - 'critical': extension.get_critical(), - 'asn1_data': extension.get_data(), - 'name': extension.get_short_name(), - }) - - result['issuer'] = {} - for component in x509.get_issuer().get_components(): - result['issuer'][component[0]] = component[1] - - result['not_after'] = x509.get_notAfter() - result['not_before'] = x509.get_notBefore() - - result['serial_number'] = x509.get_serial_number() - result['signature_algorithm'] = x509.get_signature_algorithm() - - result['version'] = x509.get_version() - - elif backend == 'cryptography': + if backend == 'cryptography': x509 = cryptography.x509.load_pem_x509_certificate(to_bytes(cert), cryptography_backend()) result['subject'] = {} for attribute in x509.subject: diff --git a/plugins/modules/openssl_csr_info.py b/plugins/modules/openssl_csr_info.py index b7518b35..4f78b476 100644 --- a/plugins/modules/openssl_csr_info.py +++ b/plugins/modules/openssl_csr_info.py @@ -17,13 +17,9 @@ description: - This module allows one to query information on OpenSSL Certificate Signing Requests (CSR). - In case the CSR signature cannot be validated, the module will fail. In this case, all return variables are still returned. - - It uses the pyOpenSSL or cryptography python library to interact with OpenSSL. If both the - cryptography and PyOpenSSL libraries are available (and meet the minimum version requirements) - cryptography will be preferred as a backend over PyOpenSSL (unless the backend is forced with - C(select_crypto_backend)). Please note that the PyOpenSSL backend was deprecated in Ansible 2.9 - and will be removed in community.crypto 2.0.0. + - It uses the cryptography python library to interact with OpenSSL. requirements: - - PyOpenSSL >= 0.15 or cryptography >= 1.3 + - cryptography >= 1.3 author: - Felix Fontein (@felixfontein) - Yanis Guenane (@Spredzy) @@ -42,14 +38,11 @@ options: select_crypto_backend: description: - Determines which crypto backend to use. - - The default choice is C(auto), which tries to use C(cryptography) if available, and falls back to C(pyopenssl). - - If set to C(pyopenssl), will try to use the L(pyOpenSSL,https://pypi.org/project/pyOpenSSL/) library. + - The default choice is C(auto), which tries to use C(cryptography) if available. - If set to C(cryptography), will try to use the L(cryptography,https://cryptography.io/) library. - - Please note that the C(pyopenssl) backend has been deprecated in Ansible 2.9, and will be removed in community.crypto 2.0.0. - From that point on, only the C(cryptography) backend will be available. type: str default: auto - choices: [ auto, cryptography, pyopenssl ] + choices: [ auto, cryptography ] seealso: - module: community.crypto.openssl_csr @@ -267,7 +260,7 @@ subject_key_identifier: - The CSR's subject key identifier. - The identifier is returned in hexadecimal, with C(:) used to separate bytes. - Is C(none) if the C(SubjectKeyIdentifier) extension is not present. - returned: success and if the pyOpenSSL backend is I(not) used + returned: success type: str sample: '00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22:33' authority_key_identifier: @@ -275,14 +268,14 @@ authority_key_identifier: - The CSR's authority key identifier. - The identifier is returned in hexadecimal, with C(:) used to separate bytes. - Is C(none) if the C(AuthorityKeyIdentifier) extension is not present. - returned: success and if the pyOpenSSL backend is I(not) used + returned: success type: str sample: '00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22:33' authority_cert_issuer: description: - The CSR's authority cert issuer as a list of general names. - Is C(none) if the C(AuthorityKeyIdentifier) extension is not present. - returned: success and if the pyOpenSSL backend is I(not) used + returned: success type: list elements: str sample: "[DNS:www.ansible.com, IP:1.2.3.4]" @@ -290,7 +283,7 @@ authority_cert_serial_number: description: - The CSR's authority cert serial number. - Is C(none) if the C(AuthorityKeyIdentifier) extension is not present. - returned: success and if the pyOpenSSL backend is I(not) used + returned: success type: int sample: '12345' ''' @@ -313,7 +306,7 @@ def main(): argument_spec=dict( path=dict(type='path'), content=dict(type='str'), - select_crypto_backend=dict(type='str', default='auto', choices=['auto', 'cryptography', 'pyopenssl']), + select_crypto_backend=dict(type='str', default='auto', choices=['auto', 'cryptography']), ), required_one_of=( ['path', 'content'], diff --git a/plugins/modules/openssl_privatekey.py b/plugins/modules/openssl_privatekey.py index 595c1986..32e3e716 100644 --- a/plugins/modules/openssl_privatekey.py +++ b/plugins/modules/openssl_privatekey.py @@ -117,7 +117,6 @@ filename: fingerprint: description: - The fingerprint of the public key. Fingerprint will be generated for each C(hashlib.algorithms) available. - - The PyOpenSSL backend requires PyOpenSSL >= 16.0 for meaningful output. returned: changed or success type: dict sample: diff --git a/plugins/modules/openssl_privatekey_info.py b/plugins/modules/openssl_privatekey_info.py index 2aed7c75..5e272732 100644 --- a/plugins/modules/openssl_privatekey_info.py +++ b/plugins/modules/openssl_privatekey_info.py @@ -19,13 +19,9 @@ description: private key. In this case, all return variables are still returned. Note that key consistency checks are not available all key types; if none is available, C(none) is returned for C(key_is_consistent). - - It uses the pyOpenSSL or cryptography python library to interact with OpenSSL. If both the - cryptography and PyOpenSSL libraries are available (and meet the minimum version requirements) - cryptography will be preferred as a backend over PyOpenSSL (unless the backend is forced with - C(select_crypto_backend)). Please note that the PyOpenSSL backend was deprecated in Ansible 2.9 - and will be removed in community.crypto 2.0.0. + - It uses the cryptography python library to interact with OpenSSL. requirements: - - PyOpenSSL >= 0.15 or cryptography >= 1.2.3 + - cryptography >= 1.2.3 author: - Felix Fontein (@felixfontein) - Yanis Guenane (@Spredzy) @@ -56,14 +52,11 @@ options: select_crypto_backend: description: - Determines which crypto backend to use. - - The default choice is C(auto), which tries to use C(cryptography) if available, and falls back to C(pyopenssl). - - If set to C(pyopenssl), will try to use the L(pyOpenSSL,https://pypi.org/project/pyOpenSSL/) library. + - The default choice is C(auto), which tries to use C(cryptography) if available. - If set to C(cryptography), will try to use the L(cryptography,https://cryptography.io/) library. - - Please note that the C(pyopenssl) backend has been deprecated in Ansible 2.9, and will be removed in community.crypto 2.0.0. - From that point on, only the C(cryptography) backend will be available. type: str default: auto - choices: [ auto, cryptography, pyopenssl ] + choices: [ auto, cryptography ] notes: - Supports C(check_mode). @@ -215,7 +208,7 @@ def main(): content=dict(type='str', no_log=True), passphrase=dict(type='str', no_log=True), return_private_key_data=dict(type='bool', default=False), - select_crypto_backend=dict(type='str', default='auto', choices=['auto', 'cryptography', 'pyopenssl']), + select_crypto_backend=dict(type='str', default='auto', choices=['auto', 'cryptography']), ), required_one_of=( ['path', 'content'], diff --git a/plugins/modules/openssl_privatekey_pipe.py b/plugins/modules/openssl_privatekey_pipe.py index 16e8ce23..aecc0581 100644 --- a/plugins/modules/openssl_privatekey_pipe.py +++ b/plugins/modules/openssl_privatekey_pipe.py @@ -97,7 +97,6 @@ curve: fingerprint: description: - The fingerprint of the public key. Fingerprint will be generated for each C(hashlib.algorithms) available. - - The PyOpenSSL backend requires PyOpenSSL >= 16.0 for meaningful output. returned: changed or success type: dict sample: diff --git a/plugins/modules/openssl_publickey.py b/plugins/modules/openssl_publickey.py index 0f2e2850..00196778 100644 --- a/plugins/modules/openssl_publickey.py +++ b/plugins/modules/openssl_publickey.py @@ -15,14 +15,9 @@ short_description: Generate an OpenSSL public key from its private key. description: - This module allows one to (re)generate OpenSSL public keys from their private keys. - Keys are generated in PEM or OpenSSH format. - - "The module can use the cryptography Python library, or the pyOpenSSL Python - library. By default, it tries to detect which one is available. This can be - overridden with the I(select_crypto_backend) option. When I(format) is C(OpenSSH), - the C(cryptography) backend has to be used. Please note that the PyOpenSSL backend - was deprecated in Ansible 2.9 and will be removed in community.crypto 2.0.0." + - The module uses the cryptography Python library. requirements: - - Either cryptography >= 1.2.3 (older versions might work as well) - - Or pyOpenSSL >= 16.0.0 + - cryptography >= 1.2.3 (older versions might work as well) - Needs cryptography >= 1.4 if I(format) is C(OpenSSH) author: - Yanis Guenane (@Spredzy) @@ -76,12 +71,11 @@ options: select_crypto_backend: description: - Determines which crypto backend to use. - - The default choice is C(auto), which tries to use C(cryptography) if available, and falls back to C(pyopenssl). - - If set to C(pyopenssl), will try to use the L(pyOpenSSL,https://pypi.org/project/pyOpenSSL/) library. + - The default choice is C(auto), which tries to use C(cryptography) if available. - If set to C(cryptography), will try to use the L(cryptography,https://cryptography.io/) library. type: str default: auto - choices: [ auto, cryptography, pyopenssl ] + choices: [ auto, cryptography ] return_content: description: - If set to C(yes), will return the (current or generated) public key's content as I(publickey). @@ -157,7 +151,6 @@ filename: fingerprint: description: - The fingerprint of the public key. Fingerprint will be generated for each hashlib.algorithms available. - - Requires PyOpenSSL >= 16.0 for meaningful output. returned: changed or success type: dict sample: @@ -208,21 +201,9 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.module_bac get_publickey_info, ) -MINIMAL_PYOPENSSL_VERSION = '16.0.0' MINIMAL_CRYPTOGRAPHY_VERSION = '1.2.3' MINIMAL_CRYPTOGRAPHY_VERSION_OPENSSH = '1.4' -PYOPENSSL_IMP_ERR = None -try: - import OpenSSL - from OpenSSL import crypto - PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__) -except ImportError: - PYOPENSSL_IMP_ERR = traceback.format_exc() - PYOPENSSL_FOUND = False -else: - PYOPENSSL_FOUND = True - CRYPTOGRAPHY_IMP_ERR = None try: import cryptography @@ -300,11 +281,6 @@ class PublicKey(OpenSSLObject): crypto_serialization.Encoding.PEM, crypto_serialization.PublicFormat.SubjectPublicKeyInfo ) - else: - try: - return crypto.dump_publickey(crypto.FILETYPE_PEM, self.privatekey) - except AttributeError as dummy: - raise PublicKeyError('You need to have PyOpenSSL>=16.0.0 to generate public keys') def generate(self, module): """Generate the public key.""" @@ -372,11 +348,6 @@ class PublicKey(OpenSSLObject): crypto_serialization.Encoding.PEM, crypto_serialization.PublicFormat.SubjectPublicKeyInfo ) - else: - publickey_content = crypto.dump_publickey( - crypto.FILETYPE_PEM, - crypto.load_publickey(crypto.FILETYPE_PEM, publickey_content) - ) except Exception as dummy: return False @@ -434,7 +405,7 @@ def main(): format=dict(type='str', default='PEM', choices=['OpenSSH', 'PEM']), privatekey_passphrase=dict(type='str', no_log=True), backup=dict(type='bool', default=False), - select_crypto_backend=dict(type='str', choices=['auto', 'pyopenssl', 'cryptography'], default='auto'), + select_crypto_backend=dict(type='str', choices=['auto', 'cryptography'], default='auto'), return_content=dict(type='bool', default=False), ), supports_check_mode=True, @@ -453,36 +424,20 @@ def main(): if backend == 'auto': # Detection what is possible can_use_cryptography = CRYPTOGRAPHY_FOUND and CRYPTOGRAPHY_VERSION >= LooseVersion(minimal_cryptography_version) - can_use_pyopenssl = PYOPENSSL_FOUND and PYOPENSSL_VERSION >= LooseVersion(MINIMAL_PYOPENSSL_VERSION) # Decision if can_use_cryptography: backend = 'cryptography' - elif can_use_pyopenssl: - if module.params['format'] == 'OpenSSH': - module.fail_json( - msg=missing_required_lib('cryptography >= {0}'.format(MINIMAL_CRYPTOGRAPHY_VERSION_OPENSSH)), - exception=CRYPTOGRAPHY_IMP_ERR - ) - backend = 'pyopenssl' # Success? if backend == 'auto': - module.fail_json(msg=("Can't detect any of the required Python libraries " - "cryptography (>= {0}) or PyOpenSSL (>= {1})").format( - minimal_cryptography_version, - MINIMAL_PYOPENSSL_VERSION)) + module.fail_json(msg=("Can't detect the required Python library " + "cryptography (>= {0})").format(minimal_cryptography_version)) if module.params['format'] == 'OpenSSH' and backend != 'cryptography': module.fail_json(msg="Format OpenSSH requires the cryptography backend.") - if backend == 'pyopenssl': - if not PYOPENSSL_FOUND: - module.fail_json(msg=missing_required_lib('pyOpenSSL >= {0}'.format(MINIMAL_PYOPENSSL_VERSION)), - exception=PYOPENSSL_IMP_ERR) - module.deprecate('The module is using the PyOpenSSL backend. This backend has been deprecated', - version='2.0.0', collection_name='community.crypto') - elif backend == 'cryptography': + if backend == 'cryptography': if not CRYPTOGRAPHY_FOUND: module.fail_json(msg=missing_required_lib('cryptography >= {0}'.format(minimal_cryptography_version)), exception=CRYPTOGRAPHY_IMP_ERR) diff --git a/plugins/modules/openssl_publickey_info.py b/plugins/modules/openssl_publickey_info.py index 014596db..d3886be6 100644 --- a/plugins/modules/openssl_publickey_info.py +++ b/plugins/modules/openssl_publickey_info.py @@ -14,14 +14,10 @@ module: openssl_publickey_info short_description: Provide information for OpenSSL public keys description: - This module allows one to query information on OpenSSL public keys. - - It uses the pyOpenSSL or cryptography python library to interact with OpenSSL. If both the - cryptography and PyOpenSSL libraries are available (and meet the minimum version requirements) - cryptography will be preferred as a backend over PyOpenSSL (unless the backend is forced with - C(select_crypto_backend)). Please note that the PyOpenSSL backend was deprecated in Ansible 2.9 - and will be removed in community.crypto 2.0.0. + - It uses the cryptography python library to interact with OpenSSL. version_added: 1.7.0 requirements: - - PyOpenSSL >= 0.15 or cryptography >= 1.2.3 + - cryptography >= 1.2.3 author: - Felix Fontein (@felixfontein) options: @@ -38,14 +34,11 @@ options: select_crypto_backend: description: - Determines which crypto backend to use. - - The default choice is C(auto), which tries to use C(cryptography) if available, and falls back to C(pyopenssl). - - If set to C(pyopenssl), will try to use the L(pyOpenSSL,https://pypi.org/project/pyOpenSSL/) library. + - The default choice is C(auto), which tries to use C(cryptography) if available. - If set to C(cryptography), will try to use the L(cryptography,https://cryptography.io/) library. - - Please note that the C(pyopenssl) backend has been deprecated in Ansible 2.9, and will be removed in community.crypto 2.0.0. - From that point on, only the C(cryptography) backend will be available. type: str default: auto - choices: [ auto, cryptography, pyopenssl ] + choices: [ auto, cryptography ] notes: - Supports C(check_mode). @@ -174,7 +167,7 @@ def main(): argument_spec=dict( path=dict(type='path'), content=dict(type='str', no_log=True), - select_crypto_backend=dict(type='str', default='auto', choices=['auto', 'cryptography', 'pyopenssl']), + select_crypto_backend=dict(type='str', default='auto', choices=['auto', 'cryptography']), ), required_one_of=( ['path', 'content'], diff --git a/plugins/modules/openssl_signature.py b/plugins/modules/openssl_signature.py index 24a5fa7b..971ee505 100644 --- a/plugins/modules/openssl_signature.py +++ b/plugins/modules/openssl_signature.py @@ -15,13 +15,9 @@ version_added: 1.1.0 short_description: Sign data with openssl description: - This module allows one to sign data using a private key. - - The module can use the cryptography Python library, or the pyOpenSSL Python - library. By default, it tries to detect which one is available. This can be - overridden with the I(select_crypto_backend) option. Please note that the PyOpenSSL backend - was deprecated in Ansible 2.9 and will be removed in community.crypto 2.0.0. + - The module uses the cryptography Python library. requirements: - - Either cryptography >= 1.4 (some key types require newer versions) - - Or pyOpenSSL >= 0.11 (Ed25519 and Ed448 keys are not supported with this backend) + - cryptography >= 1.4 (some key types require newer versions) author: - Patrick Pichler (@aveexy) - Markus Teufelberger (@MarkusTeufelberger) @@ -50,12 +46,11 @@ options: select_crypto_backend: description: - Determines which crypto backend to use. - - The default choice is C(auto), which tries to use C(cryptography) if available, and falls back to C(pyopenssl). - - If set to C(pyopenssl), will try to use the L(pyOpenSSL,https://pypi.org/project/pyOpenSSL/) library. + - The default choice is C(auto), which tries to use C(cryptography) if available. - If set to C(cryptography), will try to use the L(cryptography,https://cryptography.io/) library. type: str default: auto - choices: [ auto, cryptography, pyopenssl ] + choices: [ auto, cryptography ] notes: - | When using the C(cryptography) backend, the following key types require at least the following C(cryptography) version: @@ -99,20 +94,8 @@ import traceback from distutils.version import LooseVersion import base64 -MINIMAL_PYOPENSSL_VERSION = '0.11' MINIMAL_CRYPTOGRAPHY_VERSION = '1.4' -PYOPENSSL_IMP_ERR = None -try: - import OpenSSL - from OpenSSL import crypto - PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__) -except ImportError: - PYOPENSSL_IMP_ERR = traceback.format_exc() - PYOPENSSL_FOUND = False -else: - PYOPENSSL_FOUND = True - CRYPTOGRAPHY_IMP_ERR = None try: import cryptography @@ -170,34 +153,6 @@ class SignatureBase(OpenSSLObject): pass -# Implementation with using pyOpenSSL -class SignaturePyOpenSSL(SignatureBase): - - def __init__(self, module, backend): - super(SignaturePyOpenSSL, self).__init__(module, backend) - - def run(self): - - result = dict() - - try: - with open(self.path, "rb") as f: - _in = f.read() - - private_key = load_privatekey( - path=self.privatekey_path, - content=self.privatekey_content, - passphrase=self.privatekey_passphrase, - backend=self.backend, - ) - - signature = OpenSSL.crypto.sign(private_key, _in, "sha256") - result['signature'] = base64.b64encode(signature) - return result - except Exception as e: - raise OpenSSLObjectError(e) - - # Implementation with using cryptography class SignatureCryptography(SignatureBase): @@ -262,7 +217,7 @@ def main(): privatekey_content=dict(type='str', no_log=True), privatekey_passphrase=dict(type='str', no_log=True), path=dict(type='path', required=True), - select_crypto_backend=dict(type='str', choices=['auto', 'pyopenssl', 'cryptography'], default='auto'), + select_crypto_backend=dict(type='str', choices=['auto', 'cryptography'], default='auto'), ), mutually_exclusive=( ['privatekey_path', 'privatekey_content'], @@ -283,29 +238,17 @@ def main(): if backend == 'auto': # Detection what is possible can_use_cryptography = CRYPTOGRAPHY_FOUND and CRYPTOGRAPHY_VERSION >= LooseVersion(MINIMAL_CRYPTOGRAPHY_VERSION) - can_use_pyopenssl = PYOPENSSL_FOUND and PYOPENSSL_VERSION >= LooseVersion(MINIMAL_PYOPENSSL_VERSION) # Decision if can_use_cryptography: backend = 'cryptography' - elif can_use_pyopenssl: - backend = 'pyopenssl' # Success? if backend == 'auto': - module.fail_json(msg=("Can't detect any of the required Python libraries " - "cryptography (>= {0}) or PyOpenSSL (>= {1})").format( - MINIMAL_CRYPTOGRAPHY_VERSION, - MINIMAL_PYOPENSSL_VERSION)) + module.fail_json(msg=("Can't detect the required Python library " + "cryptography (>= {0})").format(MINIMAL_CRYPTOGRAPHY_VERSION)) try: - if backend == 'pyopenssl': - if not PYOPENSSL_FOUND: - module.fail_json(msg=missing_required_lib('pyOpenSSL >= {0}'.format(MINIMAL_PYOPENSSL_VERSION)), - exception=PYOPENSSL_IMP_ERR) - module.deprecate('The module is using the PyOpenSSL backend. This backend has been deprecated', - version='2.0.0', collection_name='community.crypto') - _sign = SignaturePyOpenSSL(module, backend) - elif backend == 'cryptography': + if backend == 'cryptography': if not CRYPTOGRAPHY_FOUND: module.fail_json(msg=missing_required_lib('cryptography >= {0}'.format(MINIMAL_CRYPTOGRAPHY_VERSION)), exception=CRYPTOGRAPHY_IMP_ERR) diff --git a/plugins/modules/openssl_signature_info.py b/plugins/modules/openssl_signature_info.py index 9b248f88..b3d0c795 100644 --- a/plugins/modules/openssl_signature_info.py +++ b/plugins/modules/openssl_signature_info.py @@ -15,13 +15,9 @@ version_added: 1.1.0 short_description: Verify signatures with openssl description: - This module allows one to verify a signature for a file by a certificate. - - The module can use the cryptography Python library, or the pyOpenSSL Python - library. By default, it tries to detect which one is available. This can be - overridden with the I(select_crypto_backend) option. Please note that the PyOpenSSL backend - was deprecated in Ansible 2.9 and will be removed in community.crypto 2.0.0. + - The module uses the cryptography Python library. requirements: - - Either cryptography >= 1.4 (some key types require newer versions) - - Or pyOpenSSL >= 0.11 (Ed25519 and Ed448 keys are not supported with this backend) + - cryptography >= 1.4 (some key types require newer versions) author: - Patrick Pichler (@aveexy) - Markus Teufelberger (@MarkusTeufelberger) @@ -49,12 +45,11 @@ options: select_crypto_backend: description: - Determines which crypto backend to use. - - The default choice is C(auto), which tries to use C(cryptography) if available, and falls back to C(pyopenssl). - - If set to C(pyopenssl), will try to use the L(pyOpenSSL,https://pypi.org/project/pyOpenSSL/) library. + - The default choice is C(auto), which tries to use C(cryptography) if available. - If set to C(cryptography), will try to use the L(cryptography,https://cryptography.io/) library. type: str default: auto - choices: [ auto, cryptography, pyopenssl ] + choices: [ auto, cryptography ] notes: - | When using the C(cryptography) backend, the following key types require at least the following C(cryptography) version: @@ -99,20 +94,8 @@ import traceback from distutils.version import LooseVersion import base64 -MINIMAL_PYOPENSSL_VERSION = '0.11' MINIMAL_CRYPTOGRAPHY_VERSION = '1.4' -PYOPENSSL_IMP_ERR = None -try: - import OpenSSL - from OpenSSL import crypto - PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__) -except ImportError: - PYOPENSSL_IMP_ERR = traceback.format_exc() - PYOPENSSL_FOUND = False -else: - PYOPENSSL_FOUND = True - CRYPTOGRAPHY_IMP_ERR = None try: import cryptography @@ -170,37 +153,6 @@ class SignatureInfoBase(OpenSSLObject): pass -# Implementation with using pyOpenSSL -class SignatureInfoPyOpenSSL(SignatureInfoBase): - - def __init__(self, module, backend): - super(SignatureInfoPyOpenSSL, self).__init__(module, backend) - - def run(self): - - result = dict() - - try: - with open(self.path, "rb") as f: - _in = f.read() - - _signature = base64.b64decode(self.signature) - certificate = load_certificate( - path=self.certificate_path, - content=self.certificate_content, - backend=self.backend, - ) - - try: - OpenSSL.crypto.verify(certificate, _signature, _in, 'sha256') - result['valid'] = True - except Exception: - result['valid'] = False - return result - except Exception as e: - raise OpenSSLObjectError(e) - - # Implementation with using cryptography class SignatureInfoCryptography(SignatureInfoBase): @@ -295,7 +247,7 @@ def main(): certificate_content=dict(type='str'), path=dict(type='path', required=True), signature=dict(type='str', required=True), - select_crypto_backend=dict(type='str', choices=['auto', 'pyopenssl', 'cryptography'], default='auto'), + select_crypto_backend=dict(type='str', choices=['auto', 'cryptography'], default='auto'), ), mutually_exclusive=( ['certificate_path', 'certificate_content'], @@ -316,29 +268,17 @@ def main(): if backend == 'auto': # Detection what is possible can_use_cryptography = CRYPTOGRAPHY_FOUND and CRYPTOGRAPHY_VERSION >= LooseVersion(MINIMAL_CRYPTOGRAPHY_VERSION) - can_use_pyopenssl = PYOPENSSL_FOUND and PYOPENSSL_VERSION >= LooseVersion(MINIMAL_PYOPENSSL_VERSION) # Decision if can_use_cryptography: backend = 'cryptography' - elif can_use_pyopenssl: - backend = 'pyopenssl' # Success? if backend == 'auto': module.fail_json(msg=("Can't detect any of the required Python libraries " - "cryptography (>= {0}) or PyOpenSSL (>= {1})").format( - MINIMAL_CRYPTOGRAPHY_VERSION, - MINIMAL_PYOPENSSL_VERSION)) + "cryptography (>= {0})").format(MINIMAL_CRYPTOGRAPHY_VERSION)) try: - if backend == 'pyopenssl': - if not PYOPENSSL_FOUND: - module.fail_json(msg=missing_required_lib('pyOpenSSL >= {0}'.format(MINIMAL_PYOPENSSL_VERSION)), - exception=PYOPENSSL_IMP_ERR) - module.deprecate('The module is using the PyOpenSSL backend. This backend has been deprecated', - version='2.0.0', collection_name='community.crypto') - _sign = SignatureInfoPyOpenSSL(module, backend) - elif backend == 'cryptography': + if backend == 'cryptography': if not CRYPTOGRAPHY_FOUND: module.fail_json(msg=missing_required_lib('cryptography >= {0}'.format(MINIMAL_CRYPTOGRAPHY_VERSION)), exception=CRYPTOGRAPHY_IMP_ERR) diff --git a/plugins/modules/x509_certificate_info.py b/plugins/modules/x509_certificate_info.py index e530e428..aca76960 100644 --- a/plugins/modules/x509_certificate_info.py +++ b/plugins/modules/x509_certificate_info.py @@ -15,11 +15,7 @@ module: x509_certificate_info short_description: Provide information of OpenSSL X.509 certificates description: - This module allows one to query information on OpenSSL certificates. - - It uses the pyOpenSSL or cryptography python library to interact with OpenSSL. If both the - cryptography and PyOpenSSL libraries are available (and meet the minimum version requirements) - cryptography will be preferred as a backend over PyOpenSSL (unless the backend is forced with - C(select_crypto_backend)). Please note that the PyOpenSSL backend was deprecated in Ansible 2.9 - and will be removed in community.crypto 2.0.0. + - It uses the cryptography python library to interact with OpenSSL. - Note that this module was called C(openssl_certificate_info) when included directly in Ansible up to version 2.9. When moved to the collection C(community.crypto), it was renamed to M(community.crypto.x509_certificate_info). From Ansible 2.10 on, it can still be used by the @@ -29,7 +25,7 @@ description: keyword, the new name M(community.crypto.x509_certificate_info) should be used to avoid a deprecation warning. requirements: - - PyOpenSSL >= 0.15 or cryptography >= 1.6 + - cryptography >= 1.6 author: - Felix Fontein (@felixfontein) - Yanis Guenane (@Spredzy) @@ -60,14 +56,11 @@ options: select_crypto_backend: description: - Determines which crypto backend to use. - - The default choice is C(auto), which tries to use C(cryptography) if available, and falls back to C(pyopenssl). - - If set to C(pyopenssl), will try to use the L(pyOpenSSL,https://pypi.org/project/pyOpenSSL/) library. + - The default choice is C(auto), which tries to use C(cryptography) if available. - If set to C(cryptography), will try to use the L(cryptography,https://cryptography.io/) library. - - Please note that the C(pyopenssl) backend has been deprecated in Ansible 2.9, and will be removed in community.crypto 2.0.0. - From that point on, only the C(cryptography) backend will be available. type: str default: auto - choices: [ auto, cryptography, pyopenssl ] + choices: [ auto, cryptography ] notes: - All timestamp values are provided in ASN.1 TIME format, in other words, following the C(YYYYMMDDHHMMSSZ) pattern. @@ -341,7 +334,7 @@ subject_key_identifier: - The certificate's subject key identifier. - The identifier is returned in hexadecimal, with C(:) used to separate bytes. - Is C(none) if the C(SubjectKeyIdentifier) extension is not present. - returned: success and if the pyOpenSSL backend is I(not) used + returned: success type: str sample: '00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22:33' authority_key_identifier: @@ -349,14 +342,14 @@ authority_key_identifier: - The certificate's authority key identifier. - The identifier is returned in hexadecimal, with C(:) used to separate bytes. - Is C(none) if the C(AuthorityKeyIdentifier) extension is not present. - returned: success and if the pyOpenSSL backend is I(not) used + returned: success type: str sample: '00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22:33' authority_cert_issuer: description: - The certificate's authority cert issuer as a list of general names. - Is C(none) if the C(AuthorityKeyIdentifier) extension is not present. - returned: success and if the pyOpenSSL backend is I(not) used + returned: success type: list elements: str sample: "[DNS:www.ansible.com, IP:1.2.3.4]" @@ -364,7 +357,7 @@ authority_cert_serial_number: description: - The certificate's authority cert serial number. - Is C(none) if the C(AuthorityKeyIdentifier) extension is not present. - returned: success and if the pyOpenSSL backend is I(not) used + returned: success type: int sample: '12345' ocsp_uri: @@ -398,7 +391,7 @@ def main(): path=dict(type='path'), content=dict(type='str'), valid_at=dict(type='dict'), - select_crypto_backend=dict(type='str', default='auto', choices=['auto', 'cryptography', 'pyopenssl']), + select_crypto_backend=dict(type='str', default='auto', choices=['auto', 'cryptography']), ), required_one_of=( ['path', 'content'], diff --git a/tests/integration/targets/get_certificate/meta/main.yml b/tests/integration/targets/get_certificate/meta/main.yml index fe62e922..54be4e6d 100644 --- a/tests/integration/targets/get_certificate/meta/main.yml +++ b/tests/integration/targets/get_certificate/meta/main.yml @@ -1,4 +1,3 @@ dependencies: - setup_openssl - - setup_pyopenssl - prepare_http_tests diff --git a/tests/integration/targets/get_certificate/tasks/main.yml b/tests/integration/targets/get_certificate/tasks/main.yml index 560e6faa..186caf9d 100644 --- a/tests/integration/targets/get_certificate/tasks/main.yml +++ b/tests/integration/targets/get_certificate/tasks/main.yml @@ -30,17 +30,7 @@ that: - result is success or skip_tests - when: | - pyopenssl_version.stdout is version('0.15', '>=') or - cryptography_version.stdout is version('1.6', '>=') - -- block: - - - include_tasks: ../tests/validate.yml - vars: - select_crypto_backend: pyopenssl - - when: pyopenssl_version.stdout is version('0.15', '>=') and not skip_tests + when: cryptography_version.stdout is version('1.6', '>=') - block: diff --git a/tests/integration/targets/openssl_csr/meta/main.yml b/tests/integration/targets/openssl_csr/meta/main.yml index ff8af08d..7f98a190 100644 --- a/tests/integration/targets/openssl_csr/meta/main.yml +++ b/tests/integration/targets/openssl_csr/meta/main.yml @@ -1,4 +1,3 @@ dependencies: - setup_openssl - - setup_pyopenssl - setup_remote_tmp_dir diff --git a/tests/integration/targets/openssl_csr/tasks/impl.yml b/tests/integration/targets/openssl_csr/tasks/impl.yml index fc01a5b1..e3e141bf 100644 --- a/tests/integration/targets/openssl_csr/tasks/impl.yml +++ b/tests/integration/targets/openssl_csr/tasks/impl.yml @@ -363,7 +363,6 @@ commonName: www.ansible.com subject_key_identifier: "00:11:22:33" select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend != 'pyopenssl' register: subject_key_identifier_1 - name: "({{ select_crypto_backend }}) Generate CSR with subject key identifier (idempotency)" @@ -374,7 +373,6 @@ commonName: www.ansible.com subject_key_identifier: "00:11:22:33" select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend != 'pyopenssl' register: subject_key_identifier_2 - name: "({{ select_crypto_backend }}) Generate CSR with subject key identifier (change)" @@ -385,7 +383,6 @@ commonName: www.ansible.com subject_key_identifier: "44:55:66:77:88" select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend != 'pyopenssl' register: subject_key_identifier_3 - name: "({{ select_crypto_backend }}) Generate CSR with subject key identifier (auto-create)" @@ -396,7 +393,6 @@ commonName: www.ansible.com create_subject_key_identifier: yes select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend != 'pyopenssl' register: subject_key_identifier_4 - name: "({{ select_crypto_backend }}) Generate CSR with subject key identifier (auto-create idempotency)" @@ -407,7 +403,6 @@ commonName: www.ansible.com create_subject_key_identifier: yes select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend != 'pyopenssl' register: subject_key_identifier_5 - name: "({{ select_crypto_backend }}) Generate CSR with subject key identifier (remove)" @@ -417,7 +412,6 @@ subject: commonName: www.ansible.com select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend != 'pyopenssl' register: subject_key_identifier_6 - name: "({{ select_crypto_backend }}) Generate CSR with authority key identifier" @@ -428,7 +422,6 @@ commonName: www.ansible.com authority_key_identifier: "00:11:22:33" select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend != 'pyopenssl' register: authority_key_identifier_1 - name: "({{ select_crypto_backend }}) Generate CSR with authority key identifier (idempotency)" @@ -439,7 +432,6 @@ commonName: www.ansible.com authority_key_identifier: "00:11:22:33" select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend != 'pyopenssl' register: authority_key_identifier_2 - name: "({{ select_crypto_backend }}) Generate CSR with authority key identifier (change)" @@ -450,7 +442,6 @@ commonName: www.ansible.com authority_key_identifier: "44:55:66:77:88" select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend != 'pyopenssl' register: authority_key_identifier_3 - name: "({{ select_crypto_backend }}) Generate CSR with authority key identifier (remove)" @@ -460,7 +451,6 @@ subject: commonName: www.ansible.com select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend != 'pyopenssl' register: authority_key_identifier_4 - name: "({{ select_crypto_backend }}) Generate CSR with authority cert issuer / serial number" @@ -474,7 +464,6 @@ - "IP:1.2.3.4" authority_cert_serial_number: 12345 select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend != 'pyopenssl' register: authority_cert_issuer_sn_1 - name: "({{ select_crypto_backend }}) Generate CSR with authority cert issuer / serial number (idempotency)" @@ -488,7 +477,6 @@ - "IP:1.2.3.4" authority_cert_serial_number: 12345 select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend != 'pyopenssl' register: authority_cert_issuer_sn_2 - name: "({{ select_crypto_backend }}) Generate CSR with authority cert issuer / serial number (change issuer)" @@ -502,7 +490,6 @@ - "DNS:ca.example.org" authority_cert_serial_number: 12345 select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend != 'pyopenssl' register: authority_cert_issuer_sn_3 - name: "({{ select_crypto_backend }}) Generate CSR with authority cert issuer / serial number (change serial number)" @@ -516,7 +503,6 @@ - "DNS:ca.example.org" authority_cert_serial_number: 54321 select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend != 'pyopenssl' register: authority_cert_issuer_sn_4 - name: "({{ select_crypto_backend }}) Generate CSR with authority cert issuer / serial number (remove)" @@ -525,7 +511,6 @@ privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem' subject: commonName: www.ansible.com - when: select_crypto_backend != 'pyopenssl' register: authority_cert_issuer_sn_5 - name: "({{ select_crypto_backend }}) Generate CSR with everything" @@ -561,37 +546,24 @@ - Encipher Only - decipherOnly key_usage_critical: yes - extended_key_usage: '{{ value_for_extended_key_usage if select_crypto_backend != "pyopenssl" else value_for_extended_key_usage_pyopenssl }}' - subject_alt_name: '{{ value_for_san if select_crypto_backend != "pyopenssl" else value_for_san_pyopenssl }}' + extended_key_usage: '{{ value_for_extended_key_usage }}' + subject_alt_name: '{{ value_for_san }}' basic_constraints: - "CA:TRUE" - "pathlen:23" basic_constraints_critical: yes - name_constraints_permitted: '{{ value_for_name_constraints_permitted if select_crypto_backend != "pyopenssl" else value_for_name_constraints_permitted_pyopenssl }}' + name_constraints_permitted: '{{ value_for_name_constraints_permitted }}' name_constraints_excluded: - "DNS:.example.com" - "DNS:.org" name_constraints_critical: yes ocsp_must_staple: yes - subject_key_identifier: '{{ "00:11:22:33" if select_crypto_backend != "pyopenssl" else omit }}' - authority_key_identifier: '{{ "44:55:66:77" if select_crypto_backend != "pyopenssl" else omit }}' - authority_cert_issuer: '{{ value_for_authority_cert_issuer if select_crypto_backend != "pyopenssl" else omit }}' - authority_cert_serial_number: '{{ 12345 if select_crypto_backend != "pyopenssl" else omit }}' + subject_key_identifier: 00:11:22:33 + authority_key_identifier: 44:55:66:77 + authority_cert_issuer: '{{ value_for_authority_cert_issuer }}' + authority_cert_serial_number: 12345 select_crypto_backend: '{{ select_crypto_backend }}' vars: - value_for_extended_key_usage_pyopenssl: - - serverAuth # the same as "TLS Web Server Authentication" - - TLS Web Server Authentication - - TLS Web Client Authentication - - Code Signing - - E-mail Protection - - timeStamping - - OCSPSigning - - Any Extended Key Usage - - qcStatements - - DVCS - - IPSec User - - biometricInfo value_for_extended_key_usage: - serverAuth # the same as "TLS Web Server Authentication" - TLS Web Server Authentication @@ -609,13 +581,6 @@ value_for_authority_cert_issuer: - "DNS:ca.example.org" - "IP:1.2.3.4" - value_for_san_pyopenssl: - - "DNS:www.ansible.com" - - "IP:1.2.3.4" - - "IP:::1" - - "email:test@example.org" - - "URI:https://example.org/test/index.html" - - "RID:1.2.3.4" value_for_san: - "DNS:www.ansible.com" - "IP:1.2.3.4" @@ -631,9 +596,6 @@ - "DNS:www.example.com" - "IP:1.2.3.0/24" - "IP:::1:0:0/112" - value_for_name_constraints_permitted_pyopenssl: - - "DNS:www.example.com" - - "IP:1.2.3.0/255.255.255.0" register: everything_1 - name: "({{ select_crypto_backend }}) Generate CSR with everything (idempotent, check mode)" @@ -669,37 +631,24 @@ - Encipher Only - decipherOnly key_usage_critical: yes - extended_key_usage: '{{ value_for_extended_key_usage if select_crypto_backend != "pyopenssl" else value_for_extended_key_usage_pyopenssl }}' - subject_alt_name: '{{ value_for_san if select_crypto_backend != "pyopenssl" else value_for_san_pyopenssl }}' + extended_key_usage: '{{ value_for_extended_key_usage }}' + subject_alt_name: '{{ value_for_san }}' basic_constraints: - "CA:TRUE" - "pathlen:23" basic_constraints_critical: yes - name_constraints_permitted: '{{ value_for_name_constraints_permitted if select_crypto_backend != "pyopenssl" else value_for_name_constraints_permitted_pyopenssl }}' + name_constraints_permitted: '{{ value_for_name_constraints_permitted }}' name_constraints_excluded: - "DNS:.org" - "DNS:.example.com" name_constraints_critical: yes ocsp_must_staple: yes - subject_key_identifier: '{{ "00:11:22:33" if select_crypto_backend != "pyopenssl" else omit }}' - authority_key_identifier: '{{ "44:55:66:77" if select_crypto_backend != "pyopenssl" else omit }}' - authority_cert_issuer: '{{ value_for_authority_cert_issuer if select_crypto_backend != "pyopenssl" else omit }}' - authority_cert_serial_number: '{{ 12345 if select_crypto_backend != "pyopenssl" else omit }}' + subject_key_identifier: 00:11:22:33 + authority_key_identifier: 44:55:66:77 + authority_cert_issuer: '{{ value_for_authority_cert_issuer }}' + authority_cert_serial_number: 12345 select_crypto_backend: '{{ select_crypto_backend }}' vars: - value_for_extended_key_usage_pyopenssl: - - serverAuth # the same as "TLS Web Server Authentication" - - TLS Web Server Authentication - - TLS Web Client Authentication - - Code Signing - - E-mail Protection - - timeStamping - - OCSPSigning - - Any Extended Key Usage - - qcStatements - - DVCS - - IPSec User - - biometricInfo value_for_extended_key_usage: - serverAuth # the same as "TLS Web Server Authentication" - TLS Web Server Authentication @@ -717,13 +666,6 @@ value_for_authority_cert_issuer: - "DNS:ca.example.org" - "IP:1.2.3.4" - value_for_san_pyopenssl: - - "DNS:www.ansible.com" - - "IP:1.2.3.4" - - "IP:::1" - - "email:test@example.org" - - "URI:https://example.org/test/index.html" - - "RID:1.2.3.4" value_for_san: - "DNS:www.ansible.com" - "IP:1.2.3.4" @@ -739,9 +681,6 @@ - "DNS:www.example.com" - "IP:1.2.3.0/255.255.255.0" - "IP:0::0:1:0:0/112" - value_for_name_constraints_permitted_pyopenssl: - - "DNS:www.example.com" - - "IP:1.2.3.0/255.255.255.0" check_mode: yes register: everything_2 @@ -778,37 +717,24 @@ - Encipher Only - decipherOnly key_usage_critical: yes - extended_key_usage: '{{ value_for_extended_key_usage if select_crypto_backend != "pyopenssl" else value_for_extended_key_usage_pyopenssl }}' - subject_alt_name: '{{ value_for_san if select_crypto_backend != "pyopenssl" else value_for_san_pyopenssl }}' + extended_key_usage: '{{ value_for_extended_key_usage }}' + subject_alt_name: '{{ value_for_san }}' basic_constraints: - "CA:TRUE" - "pathlen:23" basic_constraints_critical: yes - name_constraints_permitted: '{{ value_for_name_constraints_permitted if select_crypto_backend != "pyopenssl" else value_for_name_constraints_permitted_pyopenssl }}' + name_constraints_permitted: '{{ value_for_name_constraints_permitted }}' name_constraints_excluded: - "DNS:.org" - "DNS:.example.com" name_constraints_critical: yes ocsp_must_staple: yes - subject_key_identifier: '{{ "00:11:22:33" if select_crypto_backend != "pyopenssl" else omit }}' - authority_key_identifier: '{{ "44:55:66:77" if select_crypto_backend != "pyopenssl" else omit }}' - authority_cert_issuer: '{{ value_for_authority_cert_issuer if select_crypto_backend != "pyopenssl" else omit }}' - authority_cert_serial_number: '{{ 12345 if select_crypto_backend != "pyopenssl" else omit }}' + subject_key_identifier: 00:11:22:33 + authority_key_identifier: 44:55:66:77 + authority_cert_issuer: '{{ value_for_authority_cert_issuer }}' + authority_cert_serial_number: 12345 select_crypto_backend: '{{ select_crypto_backend }}' vars: - value_for_extended_key_usage_pyopenssl: - - serverAuth # the same as "TLS Web Server Authentication" - - TLS Web Server Authentication - - TLS Web Client Authentication - - Code Signing - - E-mail Protection - - timeStamping - - OCSPSigning - - Any Extended Key Usage - - qcStatements - - DVCS - - IPSec User - - biometricInfo value_for_extended_key_usage: - serverAuth # the same as "TLS Web Server Authentication" - TLS Web Server Authentication @@ -826,13 +752,6 @@ value_for_authority_cert_issuer: - "DNS:ca.example.org" - "IP:1.2.3.4" - value_for_san_pyopenssl: - - "DNS:www.ansible.com" - - "IP:1.2.3.4" - - "IP:::1" - - "email:test@example.org" - - "URI:https://example.org/test/index.html" - - "RID:1.2.3.4" value_for_san: - "DNS:www.ansible.com" - "IP:1.2.3.4" @@ -848,9 +767,6 @@ - "DNS:www.example.com" - "IP:1.2.3.0/255.255.255.0" - "IP:0::0:1:0:0/112" - value_for_name_constraints_permitted_pyopenssl: - - "DNS:www.example.com" - - "IP:1.2.3.0/255.255.255.0" register: everything_3 - name: "({{ select_crypto_backend }}) Get info from CSR with everything" diff --git a/tests/integration/targets/openssl_csr/tasks/main.yml b/tests/integration/targets/openssl_csr/tasks/main.yml index 21006c7e..66fe3f97 100644 --- a/tests/integration/targets/openssl_csr/tasks/main.yml +++ b/tests/integration/targets/openssl_csr/tasks/main.yml @@ -4,40 +4,18 @@ # and should not be used as examples of how to write Ansible roles # #################################################################### -- name: Prepare private key for backend autodetection test - openssl_privatekey: - path: '{{ remote_tmp_dir }}/privatekey_backend_selection.pem' - size: '{{ default_rsa_key_size }}' -- name: Run module with backend autodetection - openssl_csr: - path: '{{ remote_tmp_dir }}/csr_backend_selection.csr' - privatekey_path: '{{ remote_tmp_dir }}/privatekey_backend_selection.pem' - subject: - commonName: www.ansible.com - - block: - - name: Running tests with pyOpenSSL backend - include_tasks: impl.yml - vars: - select_crypto_backend: pyopenssl + - name: Prepare private key for backend autodetection test + openssl_privatekey: + path: '{{ remote_tmp_dir }}/privatekey_backend_selection.pem' + size: '{{ default_rsa_key_size }}' + - name: Run module with backend autodetection + openssl_csr: + path: '{{ remote_tmp_dir }}/csr_backend_selection.csr' + privatekey_path: '{{ remote_tmp_dir }}/privatekey_backend_selection.pem' + subject: + commonName: www.ansible.com - - import_tasks: ../tests/validate.yml - vars: - select_crypto_backend: pyopenssl - - when: pyopenssl_version.stdout is version('0.15', '>=') - -- name: Remove output directory - file: - path: "{{ remote_tmp_dir }}" - state: absent - -- name: Re-create output directory - file: - path: "{{ remote_tmp_dir }}" - state: directory - -- block: - name: Running tests with cryptography backend include_tasks: impl.yml vars: diff --git a/tests/integration/targets/openssl_csr/tests/validate.yml b/tests/integration/targets/openssl_csr/tests/validate.yml index 56afbe1a..24638197 100644 --- a/tests/integration/targets/openssl_csr/tests/validate.yml +++ b/tests/integration/targets/openssl_csr/tests/validate.yml @@ -74,13 +74,13 @@ - "'Subject Alternative Name' in generate_csr_invalid_san.msg" - name: "({{ select_crypto_backend }}) Validate invalid SAN (2/2)" - # Note that pyOpenSSL simply accepts this name, and modern cryptography versions do so as well. + # Note that modern cryptography versions simply accept this name. # The error has been observed with cryptography 1.7.2 and 1.9, but not with 2.3 and newer. assert: that: - generate_csr_invalid_san_2 is failed - "'The label system:kube-controller-manager is not a valid A-label' in generate_csr_invalid_san_2.msg" - when: select_crypto_backend == 'cryptography' and cryptography_version.stdout is version('2.0', '<') + when: cryptography_version.stdout is version('2.0', '<') - name: "({{ select_crypto_backend }}) Validate OCSP Must Staple CSR (test - everything)" shell: "{{ openssl_binary }} req -noout -in {{ remote_tmp_dir }}/csr_ocsp.csr -text" @@ -156,7 +156,6 @@ - subject_key_identifier_4 is changed - subject_key_identifier_5 is not changed - subject_key_identifier_6 is changed - when: select_crypto_backend != 'pyopenssl' - name: "({{ select_crypto_backend }}) Verify that authority key identifier handling works" assert: @@ -165,7 +164,6 @@ - authority_key_identifier_2 is not changed - authority_key_identifier_3 is changed - authority_key_identifier_4 is changed - when: select_crypto_backend != 'pyopenssl' - name: "({{ select_crypto_backend }}) Verify that authority cert issuer / serial number handling works" assert: @@ -175,7 +173,6 @@ - authority_cert_issuer_sn_3 is changed - authority_cert_issuer_sn_4 is changed - authority_cert_issuer_sn_5 is changed - when: select_crypto_backend != 'pyopenssl' - name: "({{ select_crypto_backend }}) Check backup" assert: @@ -243,38 +240,7 @@ ] - everything_info.name_constraints_critical == true -- name: "({{ select_crypto_backend }}) Check CSR with everything (pyOpenSSL specific)" - assert: - that: - - everything_info.subject_alt_name == [ - "DNS:www.ansible.com", - "IP:1.2.3.4", - "IP:::1", - "email:test@example.org", - "URI:https://example.org/test/index.html", - "RID:1.2.3.4", - ] - - everything_info.extended_key_usage == [ - "Any Extended Key Usage", - "Biometric Info", - "Code Signing", - "E-mail Protection", - "IPSec User", - "OCSP Signing", - "TLS Web Client Authentication", - "TLS Web Server Authentication", - "TLS Web Server Authentication", - "Time Stamping", - "dvcs", - "qcStatements", - ] - - everything_info.name_constraints_permitted == [ - "DNS:www.example.com", - "IP:1.2.3.0/24", - ] - when: select_crypto_backend == 'pyopenssl' - -- name: "({{ select_crypto_backend }}) Check CSR with everything (non-pyOpenSSL specific)" +- name: "({{ select_crypto_backend }}) Check CSR with everything" assert: that: - everything_info.authority_cert_issuer == [ @@ -316,7 +282,6 @@ "IP:1.2.3.0/24", "IP:::1:0:0/112", ] - when: select_crypto_backend != 'pyopenssl' - name: "({{ select_crypto_backend }}) Verify Ed25519 and Ed448 tests (for cryptography >= 2.6, < 2.8)" assert: diff --git a/tests/integration/targets/openssl_csr_info/meta/main.yml b/tests/integration/targets/openssl_csr_info/meta/main.yml index 8aa534dd..49dd4945 100644 --- a/tests/integration/targets/openssl_csr_info/meta/main.yml +++ b/tests/integration/targets/openssl_csr_info/meta/main.yml @@ -1,5 +1,4 @@ dependencies: - setup_openssl - - setup_pyopenssl - setup_remote_tmp_dir - prepare_jinja2_compat diff --git a/tests/integration/targets/openssl_csr_info/tasks/impl.yml b/tests/integration/targets/openssl_csr_info/tasks/impl.yml index b26bf16c..978bc521 100644 --- a/tests/integration/targets/openssl_csr_info/tasks/impl.yml +++ b/tests/integration/targets/openssl_csr_info/tasks/impl.yml @@ -28,11 +28,7 @@ expected_authority_cert_issuer: - "DNS:ca.example.org" - "IP:1.2.3.4" - when: select_crypto_backend != 'pyopenssl' and cryptography_version.stdout is version('1.3', '>=') - -- name: "({{ select_crypto_backend }}) Update result list" - set_fact: - info_results: "{{ info_results + [result] }}" + when: cryptography_version.stdout is version('1.3', '>=') - name: "({{ select_crypto_backend }}) Read CSR" slurp: @@ -56,10 +52,6 @@ select_crypto_backend: '{{ select_crypto_backend }}' register: result -- name: "({{ select_crypto_backend }}) Update result list" - set_fact: - info_results: "{{ info_results + [result] }}" - - name: "({{ select_crypto_backend }}) Get CSR info" openssl_csr_info: path: '{{ remote_tmp_dir }}/csr_3.csr' @@ -76,11 +68,7 @@ expected_authority_cert_issuer: - "DNS:ca.example.org" - "IP:1.2.3.4" - when: select_crypto_backend != 'pyopenssl' and cryptography_version.stdout is version('1.3', '>=') - -- name: "({{ select_crypto_backend }}) Update result list" - set_fact: - info_results: "{{ info_results + [result] }}" + when: cryptography_version.stdout is version('1.3', '>=') - name: "({{ select_crypto_backend }}) Get CSR info" openssl_csr_info: @@ -94,8 +82,4 @@ - result.authority_key_identifier == "44:55:66:77" - result.authority_cert_issuer is none - result.authority_cert_serial_number is none - when: select_crypto_backend != 'pyopenssl' and cryptography_version.stdout is version('1.3', '>=') - -- name: "({{ select_crypto_backend }}) Update result list" - set_fact: - info_results: "{{ info_results + [result] }}" + when: cryptography_version.stdout is version('1.3', '>=') diff --git a/tests/integration/targets/openssl_csr_info/tasks/main.yml b/tests/integration/targets/openssl_csr_info/tasks/main.yml index 7cc1fcb3..566d4cb5 100644 --- a/tests/integration/targets/openssl_csr_info/tasks/main.yml +++ b/tests/integration/targets/openssl_csr_info/tasks/main.yml @@ -119,50 +119,8 @@ useCommonNameForSAN: no authority_key_identifier: '{{ "44:55:66:77" if cryptography_version.stdout is version("1.3", ">=") else omit }}' -- name: Prepare result list - set_fact: - info_results: [] - -- name: Running tests with pyOpenSSL backend - include_tasks: impl.yml - vars: - select_crypto_backend: pyopenssl - when: pyopenssl_version.stdout is version('0.15', '>=') - -- name: Prepare result list - set_fact: - pyopenssl_info_results: "{{ info_results }}" - info_results: [] - - name: Running tests with cryptography backend include_tasks: impl.yml vars: select_crypto_backend: cryptography when: cryptography_version.stdout is version('1.3', '>=') - -- name: Prepare result list - set_fact: - cryptography_info_results: "{{ info_results }}" - -- block: - - name: Dump pyOpenSSL results - debug: - var: pyopenssl_info_results - - name: Dump cryptography results - debug: - var: cryptography_info_results - - name: Compare results - assert: - that: - - ' (item.0 | dict2items | rejectattr("key", "in", keys_to_ignore) | list | items2dict) - == (item.1 | dict2items | rejectattr("key", "in", keys_to_ignore) | list | items2dict)' - quiet: yes - loop: "{{ pyopenssl_info_results | zip(cryptography_info_results) | list }}" - when: pyopenssl_version.stdout is version('0.15', '>=') and cryptography_version.stdout is version('1.3', '>=') - vars: - keys_to_ignore: - - deprecations - - subject_key_identifier - - authority_key_identifier - - authority_cert_issuer - - authority_cert_serial_number diff --git a/tests/integration/targets/openssl_csr_pipe/meta/main.yml b/tests/integration/targets/openssl_csr_pipe/meta/main.yml index ff8af08d..7f98a190 100644 --- a/tests/integration/targets/openssl_csr_pipe/meta/main.yml +++ b/tests/integration/targets/openssl_csr_pipe/meta/main.yml @@ -1,4 +1,3 @@ dependencies: - setup_openssl - - setup_pyopenssl - setup_remote_tmp_dir diff --git a/tests/integration/targets/openssl_csr_pipe/tasks/main.yml b/tests/integration/targets/openssl_csr_pipe/tasks/main.yml index d0a687b2..c6e8594d 100644 --- a/tests/integration/targets/openssl_csr_pipe/tasks/main.yml +++ b/tests/integration/targets/openssl_csr_pipe/tasks/main.yml @@ -14,24 +14,6 @@ subject: commonName: www.ansible.com -- block: - - name: Running tests with pyOpenSSL backend - include_tasks: impl.yml - vars: - select_crypto_backend: pyopenssl - - when: pyopenssl_version.stdout is version('0.15', '>=') - -- name: Remove output directory - file: - path: "{{ remote_tmp_dir }}" - state: absent - -- name: Re-create output directory - file: - path: "{{ remote_tmp_dir }}" - state: directory - - block: - name: Running tests with cryptography backend include_tasks: impl.yml diff --git a/tests/integration/targets/openssl_privatekey/meta/main.yml b/tests/integration/targets/openssl_privatekey/meta/main.yml index ff8af08d..7f98a190 100644 --- a/tests/integration/targets/openssl_privatekey/meta/main.yml +++ b/tests/integration/targets/openssl_privatekey/meta/main.yml @@ -1,4 +1,3 @@ dependencies: - setup_openssl - - setup_pyopenssl - setup_remote_tmp_dir diff --git a/tests/integration/targets/openssl_privatekey/tasks/impl.yml b/tests/integration/targets/openssl_privatekey/tasks/impl.yml index e55322e0..70f57019 100644 --- a/tests/integration/targets/openssl_privatekey/tasks/impl.yml +++ b/tests/integration/targets/openssl_privatekey/tasks/impl.yml @@ -67,7 +67,7 @@ openssl_privatekey: path: '{{ remote_tmp_dir }}/privatekey5.pem' passphrase: ansible - cipher: "{{ 'aes256' if select_crypto_backend == 'pyopenssl' else 'auto' }}" + cipher: auto size: '{{ default_rsa_key_size }}' select_crypto_backend: '{{ select_crypto_backend }}' @@ -75,7 +75,7 @@ openssl_privatekey: path: '{{ remote_tmp_dir }}/privatekey5.pem' passphrase: ansible - cipher: "{{ 'aes256' if select_crypto_backend == 'pyopenssl' else 'auto' }}" + cipher: auto size: '{{ default_rsa_key_size }}' select_crypto_backend: '{{ select_crypto_backend }}' register: privatekey5_idempotence @@ -84,13 +84,10 @@ openssl_privatekey: path: '{{ remote_tmp_dir }}/privatekey6.pem' passphrase: ànsïblé - cipher: "{{ 'aes256' if select_crypto_backend == 'pyopenssl' else 'auto' }}" + cipher: auto size: '{{ default_rsa_key_size }}' select_crypto_backend: '{{ select_crypto_backend }}' -- set_fact: - ecc_types: [] - when: select_crypto_backend == 'pyopenssl' - set_fact: ecc_types: - curve: secp384r1 @@ -150,7 +147,6 @@ - curve: sect163r2 openssl_name: sect163r2 min_cryptography_version: "0.5" - when: select_crypto_backend == 'cryptography' - name: "({{ select_crypto_backend }}) Test ECC key generation" openssl_privatekey: @@ -221,7 +217,7 @@ openssl_privatekey: path: '{{ remote_tmp_dir }}/privatekeypw.pem' passphrase: hunter2 - cipher: "{{ 'aes256' if select_crypto_backend == 'pyopenssl' else 'auto' }}" + cipher: auto size: '{{ default_rsa_key_size }}' select_crypto_backend: '{{ select_crypto_backend }}' backup: yes @@ -231,7 +227,7 @@ openssl_privatekey: path: '{{ remote_tmp_dir }}/privatekeypw.pem' passphrase: hunter2 - cipher: "{{ 'aes256' if select_crypto_backend == 'pyopenssl' else 'auto' }}" + cipher: auto size: '{{ default_rsa_key_size }}' select_crypto_backend: '{{ select_crypto_backend }}' backup: yes @@ -257,7 +253,7 @@ openssl_privatekey: path: '{{ remote_tmp_dir }}/privatekeypw.pem' passphrase: hunter2 - cipher: "{{ 'aes256' if select_crypto_backend == 'pyopenssl' else 'auto' }}" + cipher: auto size: '{{ default_rsa_key_size }}' select_crypto_backend: '{{ select_crypto_backend }}' backup: yes @@ -278,7 +274,7 @@ openssl_privatekey: path: '{{ remote_tmp_dir }}/privatekeypw.pem' passphrase: hunter2 - cipher: "{{ 'aes256' if select_crypto_backend == 'pyopenssl' else 'auto' }}" + cipher: auto size: '{{ default_rsa_key_size }}' select_crypto_backend: '{{ select_crypto_backend }}' backup: yes @@ -289,7 +285,7 @@ openssl_privatekey: path: '{{ remote_tmp_dir }}/privatekeypw.pem' passphrase: hunter2 - cipher: "{{ 'aes256' if select_crypto_backend == 'pyopenssl' else 'auto' }}" + cipher: auto size: '{{ default_rsa_key_size }}' select_crypto_backend: '{{ select_crypto_backend }}' backup: yes @@ -551,7 +547,7 @@ type: RSA size: '{{ default_rsa_key_size }}' passphrase: hunter2 - cipher: "{{ 'aes256' if select_crypto_backend == 'pyopenssl' else 'auto' }}" + cipher: auto select_crypto_backend: '{{ select_crypto_backend }}' loop: "{{ regenerate_values }}" - name: "({{ select_crypto_backend }}) Regenerate - setup broken keys" diff --git a/tests/integration/targets/openssl_privatekey/tasks/main.yml b/tests/integration/targets/openssl_privatekey/tasks/main.yml index 1a4350ff..bf580397 100644 --- a/tests/integration/targets/openssl_privatekey/tasks/main.yml +++ b/tests/integration/targets/openssl_privatekey/tasks/main.yml @@ -36,29 +36,6 @@ path: '{{ remote_tmp_dir }}/privatekey_backend_selection.pem' size: '{{ default_rsa_key_size }}' -- block: - - name: Running tests with pyOpenSSL backend - include_tasks: impl.yml - vars: - select_crypto_backend: pyopenssl - - - import_tasks: ../tests/validate.yml - vars: - select_crypto_backend: pyopenssl - - # FIXME: minimal pyOpenSSL version?! - when: pyopenssl_version.stdout is version('0.6', '>=') - -- name: Remove output directory - file: - path: "{{ remote_tmp_dir }}" - state: absent - -- name: Re-create output directory - file: - path: "{{ remote_tmp_dir }}" - state: directory - - block: - name: Running tests with cryptography backend include_tasks: impl.yml @@ -70,45 +47,3 @@ select_crypto_backend: cryptography when: cryptography_version.stdout is version('0.5', '>=') - -- name: Check that fingerprints do not depend on the backend - block: - - name: "Fingerprint comparison: pyOpenSSL" - openssl_privatekey: - path: '{{ remote_tmp_dir }}/fingerprint-{{ item }}.pem' - type: "{{ item }}" - size: '{{ default_rsa_key_size }}' - select_crypto_backend: pyopenssl - loop: - - RSA - - DSA - register: fingerprint_pyopenssl - - - name: "Fingerprint comparison: cryptography" - openssl_privatekey: - path: '{{ remote_tmp_dir }}/fingerprint-{{ item }}.pem' - type: "{{ item }}" - size: '{{ default_rsa_key_size }}' - select_crypto_backend: cryptography - loop: - - RSA - - DSA - register: fingerprint_cryptography - - - name: Verify that keys were not regenerated - assert: - that: - - fingerprint_cryptography is not changed - - - name: Verify that fingerprints match - assert: - that: item.0.fingerprint[item.2] == item.1.fingerprint[item.2] - when: item.0 is not skipped and item.1 is not skipped - loop: | - {{ query('nested', - fingerprint_pyopenssl.results | zip(fingerprint_cryptography.results), - fingerprint_pyopenssl.results[0].fingerprint.keys() - ) if fingerprint_pyopenssl.results[0].fingerprint else [] }} - loop_control: - label: "{{ [item.0.item, item.2] }}" - when: pyopenssl_version.stdout is version('0.6', '>=') and cryptography_version.stdout is version('0.5', '>=') diff --git a/tests/integration/targets/openssl_privatekey_info/meta/main.yml b/tests/integration/targets/openssl_privatekey_info/meta/main.yml index 8aa534dd..49dd4945 100644 --- a/tests/integration/targets/openssl_privatekey_info/meta/main.yml +++ b/tests/integration/targets/openssl_privatekey_info/meta/main.yml @@ -1,5 +1,4 @@ dependencies: - setup_openssl - - setup_pyopenssl - setup_remote_tmp_dir - prepare_jinja2_compat diff --git a/tests/integration/targets/openssl_privatekey_info/tasks/impl.yml b/tests/integration/targets/openssl_privatekey_info/tasks/impl.yml index 099a7c06..702791ff 100644 --- a/tests/integration/targets/openssl_privatekey_info/tasks/impl.yml +++ b/tests/integration/targets/openssl_privatekey_info/tasks/impl.yml @@ -20,10 +20,6 @@ - "result.public_data.exponent > 5" - "'private_data' not in result" -- name: Update result list - set_fact: - info_results: "{{ info_results | combine({'key1': result}) }}" - - name: ({{select_crypto_backend}}) Read private key slurp: src: '{{ remote_tmp_dir }}/privatekey_1.pem' @@ -62,10 +58,6 @@ - "result.public_data.modulus == result.private_data.p * result.private_data.q" - "result.private_data.exponent > 5" -- name: Update result list - set_fact: - info_results: "{{ info_results | combine({'key2': result}) }}" - - name: ({{select_crypto_backend}}) Get key 3 info (without passphrase) openssl_privatekey_info: path: '{{ remote_tmp_dir }}/privatekey_3.pem' @@ -113,10 +105,6 @@ - "result.public_data.modulus == result.private_data.p * result.private_data.q" - "result.private_data.exponent > 5" -- name: Update result list - set_fact: - info_results: "{{ info_results | combine({'key3': result}) }}" - - name: ({{select_crypto_backend}}) Get key 4 info openssl_privatekey_info: path: '{{ remote_tmp_dir }}/privatekey_4.pem' @@ -124,37 +112,20 @@ select_crypto_backend: '{{ select_crypto_backend }}' register: result -- block: - - name: Check that ECC key info is ok - assert: - that: - - "'public_key' in result" - - "'public_key_fingerprints' in result" - - "'type' in result" - - "result.type == 'ECC'" - - "'public_data' in result" - - "result.public_data.curve is string" - - "result.public_data.x != 0" - - "result.public_data.y != 0" - - "result.public_data.exponent_size == (521 if (ansible_distribution == 'CentOS' and ansible_distribution_major_version == '6') else 256)" - - "'private_data' in result" - - "result.private_data.multiplier > 1024" - - - name: Update result list - set_fact: - info_results: "{{ info_results | combine({'key4': result}) }}" - when: select_crypto_backend != 'pyopenssl' or (pyopenssl_version.stdout is version('16.1.0', '>=') and cryptography_version.stdout is version('0.0', '>')) - - name: Check that ECC key info is ok assert: that: - "'public_key' in result" - "'public_key_fingerprints' in result" - "'type' in result" - - "result.type.startswith('unknown ')" + - "result.type == 'ECC'" - "'public_data' in result" + - "result.public_data.curve is string" + - "result.public_data.x != 0" + - "result.public_data.y != 0" + - "result.public_data.exponent_size == (521 if (ansible_distribution == 'CentOS' and ansible_distribution_major_version == '6') else 256)" - "'private_data' in result" - when: select_crypto_backend == 'pyopenssl' and not (pyopenssl_version.stdout is version('16.1.0', '>=') and cryptography_version.stdout is version('0.0', '>')) + - "result.private_data.multiplier > 1024" - name: ({{select_crypto_backend}}) Get key 5 info openssl_privatekey_info: @@ -177,7 +148,3 @@ - "result.public_data.y > 2" - "'private_data' in result" - "result.private_data.x > 2" - -- name: Update result list - set_fact: - info_results: "{{ info_results | combine({'key5': result}) }}" diff --git a/tests/integration/targets/openssl_privatekey_info/tasks/main.yml b/tests/integration/targets/openssl_privatekey_info/tasks/main.yml index f4e79666..e9c2ca90 100644 --- a/tests/integration/targets/openssl_privatekey_info/tasks/main.yml +++ b/tests/integration/targets/openssl_privatekey_info/tasks/main.yml @@ -36,42 +36,8 @@ type: DSA size: 1024 -- name: Prepare result list - set_fact: - info_results: {} - -- name: Running tests with pyOpenSSL backend - include_tasks: impl.yml - vars: - select_crypto_backend: pyopenssl - when: pyopenssl_version.stdout is version('0.15', '>=') - -- name: Prepare result list - set_fact: - pyopenssl_info_results: "{{ info_results }}" - info_results: {} - - name: Running tests with cryptography backend include_tasks: impl.yml vars: select_crypto_backend: cryptography when: cryptography_version.stdout is version('1.2.3', '>=') - -- name: Prepare result list - set_fact: - cryptography_info_results: "{{ info_results }}" - -- block: - - name: Dump pyOpenSSL results - debug: - var: pyopenssl_info_results - - name: Dump cryptography results - debug: - var: cryptography_info_results - - name: Compare results - assert: - that: - - ' (pyopenssl_info_results[item] | dict2items | rejectattr("key", "equalto", "deprecations") | list | items2dict) - == (cryptography_info_results[item] | dict2items | rejectattr("key", "equalto", "deprecations") | list | items2dict)' - loop: "{{ pyopenssl_info_results.keys() | intersect(cryptography_info_results.keys()) | list }}" - when: pyopenssl_version.stdout is version('0.15', '>=') and cryptography_version.stdout is version('1.2.3', '>=') diff --git a/tests/integration/targets/openssl_privatekey_pipe/meta/main.yml b/tests/integration/targets/openssl_privatekey_pipe/meta/main.yml index ff8af08d..7f98a190 100644 --- a/tests/integration/targets/openssl_privatekey_pipe/meta/main.yml +++ b/tests/integration/targets/openssl_privatekey_pipe/meta/main.yml @@ -1,4 +1,3 @@ dependencies: - setup_openssl - - setup_pyopenssl - setup_remote_tmp_dir diff --git a/tests/integration/targets/openssl_privatekey_pipe/tasks/main.yml b/tests/integration/targets/openssl_privatekey_pipe/tasks/main.yml index d6305557..5a8bdd30 100644 --- a/tests/integration/targets/openssl_privatekey_pipe/tasks/main.yml +++ b/tests/integration/targets/openssl_privatekey_pipe/tasks/main.yml @@ -8,25 +8,6 @@ openssl_privatekey_pipe: size: '{{ default_rsa_key_size }}' -- block: - - name: Running tests with pyOpenSSL backend - include_tasks: impl.yml - vars: - select_crypto_backend: pyopenssl - - # FIXME: minimal pyOpenSSL version?! - when: pyopenssl_version.stdout is version('0.6', '>=') - -- name: Remove output directory - file: - path: "{{ remote_tmp_dir }}" - state: absent - -- name: Re-create output directory - file: - path: "{{ remote_tmp_dir }}" - state: directory - - block: - name: Running tests with cryptography backend include_tasks: impl.yml diff --git a/tests/integration/targets/openssl_publickey/meta/main.yml b/tests/integration/targets/openssl_publickey/meta/main.yml index ff8af08d..7f98a190 100644 --- a/tests/integration/targets/openssl_publickey/meta/main.yml +++ b/tests/integration/targets/openssl_publickey/meta/main.yml @@ -1,4 +1,3 @@ dependencies: - setup_openssl - - setup_pyopenssl - setup_remote_tmp_dir diff --git a/tests/integration/targets/openssl_publickey/tasks/impl.yml b/tests/integration/targets/openssl_publickey/tasks/impl.yml index 9713e5e4..786d2b20 100644 --- a/tests/integration/targets/openssl_publickey/tasks/impl.yml +++ b/tests/integration/targets/openssl_publickey/tasks/impl.yml @@ -90,7 +90,7 @@ openssl_privatekey: path: '{{ remote_tmp_dir }}/privatekey3.pem' passphrase: ansible - cipher: aes256 + cipher: auto size: '{{ default_rsa_key_size }}' - name: "({{ select_crypto_backend }}) Generate publickey3 - with passphrase protected privatekey" diff --git a/tests/integration/targets/openssl_publickey/tasks/main.yml b/tests/integration/targets/openssl_publickey/tasks/main.yml index 1a0f3d91..4ed94823 100644 --- a/tests/integration/targets/openssl_publickey/tasks/main.yml +++ b/tests/integration/targets/openssl_publickey/tasks/main.yml @@ -15,33 +15,6 @@ path: '{{ remote_tmp_dir }}/privatekey_autodetect_public.pem' privatekey_path: '{{ remote_tmp_dir }}/privatekey_autodetect.pem' - when: | - pyopenssl_version.stdout is version('16.0.0', '>=') or - cryptography_version.stdout is version('1.2.3', '>=') - -- block: - - name: Running tests with pyOpenSSL backend - include_tasks: impl.yml - vars: - select_crypto_backend: pyopenssl - - - import_tasks: ../tests/validate.yml - vars: - select_crypto_backend: pyopenssl - - when: pyopenssl_version.stdout is version('16.0.0', '>=') - -- name: Remove output directory - file: - path: "{{ remote_tmp_dir }}" - state: absent - -- name: Re-create output directory - file: - path: "{{ remote_tmp_dir }}" - state: directory - -- block: - name: Running tests with cryptography backend include_tasks: impl.yml vars: diff --git a/tests/integration/targets/openssl_publickey_info/meta/main.yml b/tests/integration/targets/openssl_publickey_info/meta/main.yml index 8aa534dd..49dd4945 100644 --- a/tests/integration/targets/openssl_publickey_info/meta/main.yml +++ b/tests/integration/targets/openssl_publickey_info/meta/main.yml @@ -1,5 +1,4 @@ dependencies: - setup_openssl - - setup_pyopenssl - setup_remote_tmp_dir - prepare_jinja2_compat diff --git a/tests/integration/targets/openssl_publickey_info/tasks/impl.yml b/tests/integration/targets/openssl_publickey_info/tasks/impl.yml index c4ba7b4c..6cfc2615 100644 --- a/tests/integration/targets/openssl_publickey_info/tasks/impl.yml +++ b/tests/integration/targets/openssl_publickey_info/tasks/impl.yml @@ -18,10 +18,6 @@ - "2 ** (result.public_data.size - 1) < result.public_data.modulus < 2 ** result.public_data.size" - "result.public_data.exponent > 5" -- name: Update result list - set_fact: - info_results: "{{ info_results | combine({'key1': result}) }}" - - name: ({{select_crypto_backend}}) Read file slurp: src: '{{ remote_tmp_dir }}/publickey_1.pem' @@ -55,42 +51,23 @@ - "2 ** (result.public_data.size - 1) < result.public_data.modulus < 2 ** result.public_data.size" - "result.public_data.exponent > 5" -- name: Update result list - set_fact: - info_results: "{{ info_results | combine({'key2': result}) }}" - - name: ({{select_crypto_backend}}) Get key 3 info openssl_publickey_info: path: '{{ remote_tmp_dir }}/publickey_3.pem' select_crypto_backend: '{{ select_crypto_backend }}' register: result -- block: - - name: Check that ECC key info is ok - assert: - that: - - "'fingerprints' in result" - - "'type' in result" - - "result.type == 'ECC'" - - "'public_data' in result" - - "result.public_data.curve is string" - - "result.public_data.x != 0" - - "result.public_data.y != 0" - - "result.public_data.exponent_size == (521 if (ansible_distribution == 'CentOS' and ansible_distribution_major_version == '6') else 256)" - - - name: Update result list - set_fact: - info_results: "{{ info_results | combine({'key3': result}) }}" - when: select_crypto_backend != 'pyopenssl' or (pyopenssl_version.stdout is version('16.1.0', '>=') and cryptography_version.stdout is version('0.0', '>')) - - name: Check that ECC key info is ok assert: that: - "'fingerprints' in result" - "'type' in result" - - "result.type.startswith('unknown ')" + - "result.type == 'ECC'" - "'public_data' in result" - when: select_crypto_backend == 'pyopenssl' and not (pyopenssl_version.stdout is version('16.1.0', '>=') and cryptography_version.stdout is version('0.0', '>')) + - "result.public_data.curve is string" + - "result.public_data.x != 0" + - "result.public_data.y != 0" + - "result.public_data.exponent_size == (521 if (ansible_distribution == 'CentOS' and ansible_distribution_major_version == '6') else 256)" - name: ({{select_crypto_backend}}) Get key 4 info openssl_publickey_info: @@ -109,7 +86,3 @@ - "result.public_data.q > 2" - "result.public_data.g >= 2" - "result.public_data.y > 2" - -- name: Update result list - set_fact: - info_results: "{{ info_results | combine({'key4': result}) }}" diff --git a/tests/integration/targets/openssl_publickey_info/tasks/main.yml b/tests/integration/targets/openssl_publickey_info/tasks/main.yml index 7234b925..bc551d2d 100644 --- a/tests/integration/targets/openssl_publickey_info/tasks/main.yml +++ b/tests/integration/targets/openssl_publickey_info/tasks/main.yml @@ -42,38 +42,8 @@ set_fact: info_results: {} -- name: Running tests with pyOpenSSL backend - include_tasks: impl.yml - vars: - select_crypto_backend: pyopenssl - when: pyopenssl_version.stdout is version('16.0.0', '>=') - -- name: Prepare result list - set_fact: - pyopenssl_info_results: "{{ info_results }}" - info_results: {} - - name: Running tests with cryptography backend include_tasks: impl.yml vars: select_crypto_backend: cryptography when: cryptography_version.stdout is version('1.2.3', '>=') - -- name: Prepare result list - set_fact: - cryptography_info_results: "{{ info_results }}" - -- block: - - name: Dump pyOpenSSL results - debug: - var: pyopenssl_info_results - - name: Dump cryptography results - debug: - var: cryptography_info_results - - name: Compare results - assert: - that: - - ' (pyopenssl_info_results[item] | dict2items | rejectattr("key", "equalto", "deprecations") | list | items2dict) - == (cryptography_info_results[item] | dict2items | rejectattr("key", "equalto", "deprecations") | list | items2dict)' - loop: "{{ pyopenssl_info_results.keys() | intersect(cryptography_info_results.keys()) | list }}" - when: pyopenssl_version.stdout is version('16.0.0', '>=') and cryptography_version.stdout is version('1.2.3', '>=') diff --git a/tests/integration/targets/openssl_signature/meta/main.yml b/tests/integration/targets/openssl_signature/meta/main.yml index ff8af08d..7f98a190 100644 --- a/tests/integration/targets/openssl_signature/meta/main.yml +++ b/tests/integration/targets/openssl_signature/meta/main.yml @@ -1,4 +1,3 @@ dependencies: - setup_openssl - - setup_pyopenssl - setup_remote_tmp_dir diff --git a/tests/integration/targets/openssl_signature/tasks/main.yml b/tests/integration/targets/openssl_signature/tasks/main.yml index 9b9999ad..71e80d06 100644 --- a/tests/integration/targets/openssl_signature/tasks/main.yml +++ b/tests/integration/targets/openssl_signature/tasks/main.yml @@ -5,7 +5,7 @@ #################################################################### # Test matrix: -# * pyopenssl or cryptography +# * cryptography # * DSA or ECC or ... # * password protected private key or not @@ -25,11 +25,6 @@ backends: "{{ backends + [ { 'backend': 'cryptography' } ] }}" when: cryptography_version.stdout is version('1.4', '>=') -- name: Add pyopenssl backend - set_fact: - backends: "{{ backends + [ { 'backend': 'pyopenssl' } ] }}" - when: pyopenssl_version.stdout is version('0.11', '>=') - - name: Add RSA tests set_fact: key_types: "{{ key_types + [ { 'type': 'RSA', 'size': default_rsa_key_size } ] }}" @@ -58,14 +53,11 @@ all_tests: >- [ {% for b in backends %} - {% for kt in key_types %} - {% for kp in key_password %} - {# Exclude Ed25519 and Ed448 tests on pyopenssl #} - {% if not (b.backend == 'pyopenssl' and (kt.type == 'Ed25519' or kt.type == 'Ed448')) %} - {{ b | combine (kt) | combine(kp) }}, - {% endif %} - {% endfor %} - {% endfor %} + {% for kt in key_types %} + {% for kp in key_password %} + {{ b | combine (kt) | combine(kp) }}, + {% endfor %} + {% endfor %} {% endfor %} ] diff --git a/tests/integration/targets/x509_certificate/meta/main.yml b/tests/integration/targets/x509_certificate/meta/main.yml index ff8af08d..7f98a190 100644 --- a/tests/integration/targets/x509_certificate/meta/main.yml +++ b/tests/integration/targets/x509_certificate/meta/main.yml @@ -1,4 +1,3 @@ dependencies: - setup_openssl - - setup_pyopenssl - setup_remote_tmp_dir diff --git a/tests/integration/targets/x509_certificate/tasks/expired.yml b/tests/integration/targets/x509_certificate/tasks/expired.yml index 1812828a..dd88fee4 100644 --- a/tests/integration/targets/x509_certificate/tasks/expired.yml +++ b/tests/integration/targets/x509_certificate/tasks/expired.yml @@ -12,20 +12,8 @@ commonName: www.example.com - name: (Expired, {{select_crypto_backend}}) Generate expired selfsigned certificate - x509_certificate: - path: '{{ remote_tmp_dir }}/has_expired_cert.pem' - csr_path: '{{ remote_tmp_dir }}/has_expired_csr.csr' - privatekey_path: '{{ remote_tmp_dir }}/has_expired_privatekey.pem' - provider: selfsigned - selfsigned_digest: sha256 - selfsigned_not_after: "-1s" - selfsigned_not_before: "-100s" - select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend == 'pyopenssl' # cryptography won't allow creating expired certificates - -- name: (Expired, {{select_crypto_backend}}) Generate expired selfsigned certificate + # Cryptography won't allow creating expired certificates; so we create it with 'command' command: "{{ openssl_binary }} x509 -req -days -1 -in {{ remote_tmp_dir }}/has_expired_csr.csr -signkey {{ remote_tmp_dir }}/has_expired_privatekey.pem -out {{ remote_tmp_dir }}/has_expired_cert.pem" - when: select_crypto_backend == 'cryptography' # So we create it with 'command' - name: "(Expired) Check task fails because cert is expired (has_expired: false)" x509_certificate: diff --git a/tests/integration/targets/x509_certificate/tasks/main.yml b/tests/integration/targets/x509_certificate/tasks/main.yml index 8000af78..73df0705 100644 --- a/tests/integration/targets/x509_certificate/tasks/main.yml +++ b/tests/integration/targets/x509_certificate/tasks/main.yml @@ -4,22 +4,6 @@ # and should not be used as examples of how to write Ansible roles # #################################################################### -- name: Running tests with pyOpenSSL backend - include_tasks: impl.yml - vars: - select_crypto_backend: pyopenssl - when: pyopenssl_version.stdout is version('0.15', '>=') - -- name: Remove output directory - file: - path: "{{ remote_tmp_dir }}" - state: absent - -- name: Re-create output directory - file: - path: "{{ remote_tmp_dir }}" - state: directory - - name: Running tests with cryptography backend include_tasks: impl.yml vars: diff --git a/tests/integration/targets/x509_certificate/tasks/ownca.yml b/tests/integration/targets/x509_certificate/tasks/ownca.yml index 5776425e..32630bdb 100644 --- a/tests/integration/targets/x509_certificate/tasks/ownca.yml +++ b/tests/integration/targets/x509_certificate/tasks/ownca.yml @@ -340,7 +340,6 @@ ownca_digest: sha256 ownca_create_subject_key_identifier: always_create select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend != 'pyopenssl' register: ownca_subject_key_identifier_1 - name: (OwnCA, {{select_crypto_backend}}) Create subject key identifier (idempotency) @@ -353,7 +352,6 @@ ownca_digest: sha256 ownca_create_subject_key_identifier: always_create select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend != 'pyopenssl' register: ownca_subject_key_identifier_2 - name: (OwnCA, {{select_crypto_backend}}) Create subject key identifier (remove) @@ -366,7 +364,6 @@ ownca_digest: sha256 ownca_create_subject_key_identifier: never_create select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend != 'pyopenssl' register: ownca_subject_key_identifier_3 - name: (OwnCA, {{select_crypto_backend}}) Create subject key identifier (remove idempotency) @@ -379,7 +376,6 @@ ownca_digest: sha256 ownca_create_subject_key_identifier: never_create select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend != 'pyopenssl' register: ownca_subject_key_identifier_4 - name: (OwnCA, {{select_crypto_backend}}) Create subject key identifier (re-enable) @@ -392,7 +388,6 @@ ownca_digest: sha256 ownca_create_subject_key_identifier: always_create select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend != 'pyopenssl' register: ownca_subject_key_identifier_5 - name: (OwnCA, {{select_crypto_backend}}) Create authority key identifier @@ -405,7 +400,6 @@ ownca_digest: sha256 ownca_create_authority_key_identifier: yes select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend != 'pyopenssl' register: ownca_authority_key_identifier_1 - name: (OwnCA, {{select_crypto_backend}}) Create authority key identifier (idempotency) @@ -418,7 +412,6 @@ ownca_digest: sha256 ownca_create_authority_key_identifier: yes select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend != 'pyopenssl' register: ownca_authority_key_identifier_2 - name: (OwnCA, {{select_crypto_backend}}) Create authority key identifier (remove) @@ -431,7 +424,6 @@ ownca_digest: sha256 ownca_create_authority_key_identifier: no select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend != 'pyopenssl' register: ownca_authority_key_identifier_3 - name: (OwnCA, {{select_crypto_backend}}) Create authority key identifier (remove idempotency) @@ -444,7 +436,6 @@ ownca_digest: sha256 ownca_create_authority_key_identifier: no select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend != 'pyopenssl' register: ownca_authority_key_identifier_4 - name: (OwnCA, {{select_crypto_backend}}) Create authority key identifier (re-add) @@ -457,7 +448,6 @@ ownca_digest: sha256 ownca_create_authority_key_identifier: yes select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend != 'pyopenssl' register: ownca_authority_key_identifier_5 - name: (OwnCA, {{select_crypto_backend}}) Ed25519 and Ed448 tests (for cryptography >= 2.6) diff --git a/tests/integration/targets/x509_certificate/tasks/selfsigned.yml b/tests/integration/targets/x509_certificate/tasks/selfsigned.yml index 5e7d9257..8cdab30e 100644 --- a/tests/integration/targets/x509_certificate/tasks/selfsigned.yml +++ b/tests/integration/targets/x509_certificate/tasks/selfsigned.yml @@ -353,7 +353,6 @@ selfsigned_digest: sha256 selfsigned_create_subject_key_identifier: always_create select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend != 'pyopenssl' register: selfsigned_subject_key_identifier_1 - name: (Selfsigned, {{select_crypto_backend}}) Create subject key identifier test (idempotency) @@ -365,7 +364,6 @@ selfsigned_digest: sha256 selfsigned_create_subject_key_identifier: always_create select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend != 'pyopenssl' register: selfsigned_subject_key_identifier_2 - name: (Selfsigned, {{select_crypto_backend}}) Create subject key identifier test (remove) @@ -377,7 +375,6 @@ selfsigned_digest: sha256 selfsigned_create_subject_key_identifier: never_create select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend != 'pyopenssl' register: selfsigned_subject_key_identifier_3 - name: (Selfsigned, {{select_crypto_backend}}) Create subject key identifier test (remove idempotency) @@ -389,7 +386,6 @@ selfsigned_digest: sha256 selfsigned_create_subject_key_identifier: never_create select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend != 'pyopenssl' register: selfsigned_subject_key_identifier_4 - name: (Selfsigned, {{select_crypto_backend}}) Create subject key identifier test (re-enable) @@ -401,7 +397,6 @@ selfsigned_digest: sha256 selfsigned_create_subject_key_identifier: always_create select_crypto_backend: '{{ select_crypto_backend }}' - when: select_crypto_backend != 'pyopenssl' register: selfsigned_subject_key_identifier_5 - name: (Selfsigned, {{select_crypto_backend}}) Ed25519 and Ed448 tests (for cryptography >= 2.6) diff --git a/tests/integration/targets/x509_certificate/tests/validate_ownca.yml b/tests/integration/targets/x509_certificate/tests/validate_ownca.yml index 6cd3e069..cac0c242 100644 --- a/tests/integration/targets/x509_certificate/tests/validate_ownca.yml +++ b/tests/integration/targets/x509_certificate/tests/validate_ownca.yml @@ -140,7 +140,6 @@ - ownca_subject_key_identifier_3 is changed - ownca_subject_key_identifier_4 is not changed - ownca_subject_key_identifier_5 is changed - when: select_crypto_backend != 'pyopenssl' - name: (OwnCA validation, {{select_crypto_backend}}) Check create authority key identifier assert: @@ -150,7 +149,6 @@ - ownca_authority_key_identifier_3 is changed - ownca_authority_key_identifier_4 is not changed - ownca_authority_key_identifier_5 is changed - when: select_crypto_backend != 'pyopenssl' - name: (OwnCA validation, {{select_crypto_backend}}) Verify Ed25519 and Ed448 tests (for cryptography >= 2.6, < 2.8) assert: diff --git a/tests/integration/targets/x509_certificate/tests/validate_selfsigned.yml b/tests/integration/targets/x509_certificate/tests/validate_selfsigned.yml index 9c43ff25..0ff30fc4 100644 --- a/tests/integration/targets/x509_certificate/tests/validate_selfsigned.yml +++ b/tests/integration/targets/x509_certificate/tests/validate_selfsigned.yml @@ -185,7 +185,6 @@ - selfsigned_subject_key_identifier_3 is changed - selfsigned_subject_key_identifier_4 is not changed - selfsigned_subject_key_identifier_5 is changed - when: select_crypto_backend != 'pyopenssl' - name: (Selfsigned validation, {{select_crypto_backend}}) Verify Ed25519 and Ed448 tests (for cryptography >= 2.6, < 2.8) assert: diff --git a/tests/integration/targets/x509_certificate_info/meta/main.yml b/tests/integration/targets/x509_certificate_info/meta/main.yml index 8aa534dd..49dd4945 100644 --- a/tests/integration/targets/x509_certificate_info/meta/main.yml +++ b/tests/integration/targets/x509_certificate_info/meta/main.yml @@ -1,5 +1,4 @@ dependencies: - setup_openssl - - setup_pyopenssl - setup_remote_tmp_dir - prepare_jinja2_compat diff --git a/tests/integration/targets/x509_certificate_info/tasks/impl.yml b/tests/integration/targets/x509_certificate_info/tasks/impl.yml index ae783213..b0b0cb3b 100644 --- a/tests/integration/targets/x509_certificate_info/tasks/impl.yml +++ b/tests/integration/targets/x509_certificate_info/tasks/impl.yml @@ -31,11 +31,7 @@ expected_authority_cert_issuer: - "DNS:ca.example.org" - "IP:1.2.3.4" - when: select_crypto_backend != 'pyopenssl' and cryptography_version.stdout is version('1.3', '>=') - -- name: Update result list - set_fact: - info_results: "{{ info_results + [result] }}" + when: cryptography_version.stdout is version('1.3', '>=') - name: ({{select_crypto_backend}}) Read file slurp: @@ -68,10 +64,6 @@ - not result.valid_at.past - not result.valid_at.twentydays -- name: Update result list - set_fact: - info_results: "{{ info_results + [result] }}" - - name: ({{select_crypto_backend}}) Get certificate info x509_certificate_info: path: '{{ remote_tmp_dir }}/cert_3.pem' @@ -88,11 +80,7 @@ expected_authority_cert_issuer: - "DNS:ca.example.org" - "IP:1.2.3.4" - when: select_crypto_backend != 'pyopenssl' and cryptography_version.stdout is version('1.3', '>=') - -- name: Update result list - set_fact: - info_results: "{{ info_results + [result] }}" + when: cryptography_version.stdout is version('1.3', '>=') - name: ({{select_crypto_backend}}) Get certificate info x509_certificate_info: @@ -106,11 +94,7 @@ - result.authority_key_identifier == "44:55:66:77" - result.authority_cert_issuer is none - result.authority_cert_serial_number is none - when: select_crypto_backend != 'pyopenssl' and cryptography_version.stdout is version('1.3', '>=') - -- name: Update result list - set_fact: - info_results: "{{ info_results + [result] }}" + when: cryptography_version.stdout is version('1.3', '>=') - name: Copy packed cert 1 to remote copy: @@ -131,7 +115,3 @@ that: - (result.fingerprints.sha256 == '57:7c:f1:f5:dd:cc:6e:e9:f3:17:28:73:17:e4:25:c7:69:74:3e:f7:9a:df:58:20:7a:5a:e4:aa:de:bf:24:5b' if result.fingerprints.sha256 is defined else true) - (result.fingerprints.sha1 == 'b7:79:64:f4:2b:e0:ae:45:74:d4:f3:08:f6:53:cb:39:26:fa:52:6b' if result.fingerprints.sha1 is defined else true) - -- name: Update result list - set_fact: - info_results: "{{ info_results + [result] }}" diff --git a/tests/integration/targets/x509_certificate_info/tasks/main.yml b/tests/integration/targets/x509_certificate_info/tasks/main.yml index d2a34992..04d05c4a 100644 --- a/tests/integration/targets/x509_certificate_info/tasks/main.yml +++ b/tests/integration/targets/x509_certificate_info/tasks/main.yml @@ -134,50 +134,8 @@ - 3 - 4 -- name: Prepare result list - set_fact: - info_results: [] - -- name: Running tests with pyOpenSSL backend - include_tasks: impl.yml - vars: - select_crypto_backend: pyopenssl - when: pyopenssl_version.stdout is version('0.15', '>=') - -- name: Prepare result list - set_fact: - pyopenssl_info_results: "{{ info_results }}" - info_results: [] - - name: Running tests with cryptography backend include_tasks: impl.yml vars: select_crypto_backend: cryptography when: cryptography_version.stdout is version('1.6', '>=') - -- name: Prepare result list - set_fact: - cryptography_info_results: "{{ info_results }}" - -- block: - - name: Dump pyOpenSSL results - debug: - var: pyopenssl_info_results - - name: Dump cryptography results - debug: - var: cryptography_info_results - - name: Compare results - assert: - that: - - ' (item.0 | dict2items | rejectattr("key", "in", keys_to_ignore) | list | items2dict) - == (item.1 | dict2items | rejectattr("key", "in", keys_to_ignore) | list | items2dict)' - quiet: yes - loop: "{{ pyopenssl_info_results | zip(cryptography_info_results) | list }}" - when: pyopenssl_version.stdout is version('0.15', '>=') and cryptography_version.stdout is version('1.6', '>=') - vars: - keys_to_ignore: - - deprecations - - subject_key_identifier - - authority_key_identifier - - authority_cert_issuer - - authority_cert_serial_number diff --git a/tests/integration/targets/x509_certificate_pipe/meta/main.yml b/tests/integration/targets/x509_certificate_pipe/meta/main.yml index ff8af08d..7f98a190 100644 --- a/tests/integration/targets/x509_certificate_pipe/meta/main.yml +++ b/tests/integration/targets/x509_certificate_pipe/meta/main.yml @@ -1,4 +1,3 @@ dependencies: - setup_openssl - - setup_pyopenssl - setup_remote_tmp_dir diff --git a/tests/integration/targets/x509_certificate_pipe/tasks/main.yml b/tests/integration/targets/x509_certificate_pipe/tasks/main.yml index 891cbb0f..712afb35 100644 --- a/tests/integration/targets/x509_certificate_pipe/tasks/main.yml +++ b/tests/integration/targets/x509_certificate_pipe/tasks/main.yml @@ -13,24 +13,6 @@ provider: selfsigned privatekey_path: '{{ remote_tmp_dir }}/privatekey_backend_selection.pem' -- block: - - name: Running tests with pyOpenSSL backend - include_tasks: impl.yml - vars: - select_crypto_backend: pyopenssl - - when: pyopenssl_version.stdout is version('0.15', '>=') - -- name: Remove output directory - file: - path: "{{ remote_tmp_dir }}" - state: absent - -- name: Re-create output directory - file: - path: "{{ remote_tmp_dir }}" - state: directory - - block: - name: Running tests with cryptography backend include_tasks: impl.yml diff --git a/tests/integration/targets/x509_crl/meta/main.yml b/tests/integration/targets/x509_crl/meta/main.yml index f4801bca..7f98a190 100644 --- a/tests/integration/targets/x509_crl/meta/main.yml +++ b/tests/integration/targets/x509_crl/meta/main.yml @@ -1,4 +1,3 @@ dependencies: - setup_openssl - - setup_pyopenssl # the x509_crl* modules don't need this, but the other modules using during the tests do in some situations - setup_remote_tmp_dir diff --git a/tests/unit/requirements.txt b/tests/unit/requirements.txt index 61f5dd4b..c072b0f7 100644 --- a/tests/unit/requirements.txt +++ b/tests/unit/requirements.txt @@ -1,7 +1,6 @@ +bcrypt cryptography ipaddress ; python_version < '3.0' -pyopenssl -bcrypt unittest2 ; python_version < '2.7' importlib ; python_version < '2.7'