From caf7fd2245cdc0875d59a4b7f97afa4c5a8ff8f2 Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Fri, 8 Mar 2019 17:21:18 +0100 Subject: [PATCH] openssl_*: improve passphrase handling for private keys in PyOpenSSL (#53489) * Raise OpenSSLBadPassphraseError if passphrase is wrong. * Improve handling of passphrase errors. Current behavior for modules is: if passphrase is wrong (or wrongly specified), fail. Current behavior for openssl_privatekey is: if passphrase is worng (or wrongly specified), regenerate. * Add changelog. * Add tests. * Adjustments for some versions of PyOpenSSL. * Update lib/ansible/modules/crypto/openssl_certificate.py Improve text. Co-Authored-By: felixfontein --- .../53489-openssl-private-key-passphrase.yml | 6 +++ lib/ansible/module_utils/crypto.py | 48 +++++++++++++++---- .../modules/crypto/openssl_certificate.py | 40 +++++++++++----- lib/ansible/modules/crypto/openssl_csr.py | 7 ++- lib/ansible/modules/crypto/openssl_pkcs12.py | 13 +++-- .../modules/crypto/openssl_privatekey.py | 22 +++++++-- .../modules/crypto/openssl_publickey.py | 13 +++-- .../openssl_certificate/tasks/assertonly.yml | 43 +++++++++++++++++ .../openssl_certificate/tasks/ownca.yml | 35 ++++++++++++++ .../openssl_certificate/tasks/selfsigned.yml | 39 +++++++++++++++ .../tests/validate_ownca.yml | 10 ++++ .../tests/validate_selfsigned.yml | 10 ++++ .../targets/openssl_csr/tasks/impl.yml | 33 +++++++++++++ .../targets/openssl_csr/tests/validate.yml | 10 ++++ .../targets/openssl_pkcs12/tasks/main.yml | 39 +++++++++++++++ .../targets/openssl_pkcs12/tests/validate.yml | 10 ++++ .../targets/openssl_privatekey/tasks/impl.yml | 36 ++++++++++++++ .../openssl_privatekey/tests/validate.yml | 9 ++++ .../targets/openssl_publickey/tasks/main.yml | 30 ++++++++++++ .../openssl_publickey/tests/validate.yml | 10 ++++ 20 files changed, 427 insertions(+), 36 deletions(-) create mode 100644 changelogs/fragments/53489-openssl-private-key-passphrase.yml diff --git a/changelogs/fragments/53489-openssl-private-key-passphrase.yml b/changelogs/fragments/53489-openssl-private-key-passphrase.yml new file mode 100644 index 00000000000..812b5f6916b --- /dev/null +++ b/changelogs/fragments/53489-openssl-private-key-passphrase.yml @@ -0,0 +1,6 @@ +bugfixes: +- "openssl_privatekey - no longer hang or crash when passphrase does not match or was + not specified, but key is protected with one. Also regenerate key if passphrase is + specified but existing key has no passphrase." +- "openssl_csr, openssl_certificate, openssl_publickey - properly validate private key + passphrase; if it doesn't match, fail (and not crash or ignore)." diff --git a/lib/ansible/module_utils/crypto.py b/lib/ansible/module_utils/crypto.py index a114aae03c1..629cc0a0e8c 100644 --- a/lib/ansible/module_utils/crypto.py +++ b/lib/ansible/module_utils/crypto.py @@ -38,6 +38,10 @@ class OpenSSLObjectError(Exception): pass +class OpenSSLBadPassphraseError(OpenSSLObjectError): + pass + + def get_fingerprint_of_bytes(source): """Generate the fingerprint of the given bytes.""" @@ -67,7 +71,7 @@ def get_fingerprint_of_bytes(source): def get_fingerprint(path, passphrase=None): """Generate the fingerprint of the public key. """ - privatekey = load_privatekey(path, passphrase) + privatekey = load_privatekey(path, passphrase, check_passphrase=False) try: publickey = crypto.dump_publickey(crypto.FILETYPE_ASN1, privatekey) return get_fingerprint_of_bytes(publickey) @@ -78,20 +82,46 @@ def get_fingerprint(path, passphrase=None): return None -def load_privatekey(path, passphrase=None): +def load_privatekey(path, passphrase=None, check_passphrase=True): """Load the specified OpenSSL private key.""" try: with open(path, 'rb') as b_priv_key_fh: priv_key_detail = b_priv_key_fh.read() - if passphrase: - return crypto.load_privatekey(crypto.FILETYPE_PEM, - priv_key_detail, - to_bytes(passphrase)) - else: - return crypto.load_privatekey(crypto.FILETYPE_PEM, - priv_key_detail) + # First try: try to load with real passphrase (resp. empty string) + # Will work if this is the correct passphrase, or the key is not + # password-protected. + try: + result = crypto.load_privatekey(crypto.FILETYPE_PEM, + priv_key_detail, + to_bytes(passphrase or '')) + except crypto.Error as e: + if len(e.args) > 0 and len(e.args[0]) > 0 and e.args[0][0][2] == 'bad decrypt': + # This happens in case we have the wrong passphrase. + if passphrase is not None: + raise OpenSSLBadPassphraseError('Wrong passphrase provided for private key!') + else: + raise OpenSSLBadPassphraseError('No passphrase provided, but private key is password-protected!') + raise + if check_passphrase: + # Next we want to make sure that the key is actually protected by + # a passphrase (in case we did try the empty string before, make + # sure that the key is not protected by the empty string) + try: + crypto.load_privatekey(crypto.FILETYPE_PEM, + priv_key_detail, + to_bytes('y' if passphrase == 'x' else 'x')) + if passphrase is not None: + # Since we can load the key without an exception, the + # key isn't password-protected + raise OpenSSLBadPassphraseError('Passphrase provided, but private key is not password-protected!') + except crypto.Error: + if passphrase is None and len(e.args) > 0 and len(e.args[0]) > 0 and e.args[0][0][2] == 'bad decrypt': + # The key is obviously protected by the empty string. + # Don't do this at home (if it's possible at all)... + raise OpenSSLBadPassphraseError('No passphrase provided, but private key is password-protected!') + return result except (IOError, OSError) as exc: raise OpenSSLObjectError(exc) diff --git a/lib/ansible/modules/crypto/openssl_certificate.py b/lib/ansible/modules/crypto/openssl_certificate.py index 57ab1c2acca..56135963b75 100644 --- a/lib/ansible/modules/crypto/openssl_certificate.py +++ b/lib/ansible/modules/crypto/openssl_certificate.py @@ -596,10 +596,13 @@ class Certificate(crypto_utils.OpenSSLObject): self.cert = crypto_utils.load_certificate(self.path) if self.privatekey_path: - self.privatekey = crypto_utils.load_privatekey( - self.privatekey_path, - self.privatekey_passphrase - ) + try: + self.privatekey = crypto_utils.load_privatekey( + self.privatekey_path, + self.privatekey_passphrase + ) + except crypto_utils.OpenSSLBadPassphraseError as exc: + raise CertificateError(exc) return _validate_privatekey() if self.csr_path: @@ -621,9 +624,12 @@ class SelfSignedCertificate(Certificate): self.version = module.params['selfsigned_version'] self.serial_number = randint(1000, 99999) self.csr = crypto_utils.load_certificate_request(self.csr_path) - self.privatekey = crypto_utils.load_privatekey( - self.privatekey_path, self.privatekey_passphrase - ) + try: + self.privatekey = crypto_utils.load_privatekey( + self.privatekey_path, self.privatekey_passphrase + ) + except crypto_utils.OpenSSLBadPassphraseError as exc: + module.fail_json(msg=str(exc)) def generate(self, module): @@ -703,9 +709,12 @@ class OwnCACertificate(Certificate): self.ca_privatekey_passphrase = module.params['ownca_privatekey_passphrase'] self.csr = crypto_utils.load_certificate_request(self.csr_path) self.ca_cert = crypto_utils.load_certificate(self.ca_cert_path) - self.ca_privatekey = crypto_utils.load_privatekey( - self.ca_privatekey_path, self.ca_privatekey_passphrase - ) + try: + self.ca_privatekey = crypto_utils.load_privatekey( + self.ca_privatekey_path, self.ca_privatekey_passphrase + ) + except crypto_utils.OpenSSLBadPassphraseError as exc: + module.fail_json(msg=str(exc)) def generate(self, module): @@ -1003,10 +1012,15 @@ class AssertOnlyCertificate(Certificate): self.assertonly() - if self.privatekey_path and \ - not super(AssertOnlyCertificate, self).check(module, perms_required=False): + try: + if self.privatekey_path and \ + not super(AssertOnlyCertificate, self).check(module, perms_required=False): + self.message.append( + 'Certificate %s and private key %s do not match' % (self.path, self.privatekey_path) + ) + except CertificateError as e: self.message.append( - 'Certificate %s and private key %s does not match' % (self.path, self.privatekey_path) + 'Error while reading private key %s: %s' % (self.privatekey_path, str(e)) ) if len(self.message): diff --git a/lib/ansible/modules/crypto/openssl_csr.py b/lib/ansible/modules/crypto/openssl_csr.py index e2bd8195370..48cb4483e40 100644 --- a/lib/ansible/modules/crypto/openssl_csr.py +++ b/lib/ansible/modules/crypto/openssl_csr.py @@ -528,7 +528,10 @@ class CertificateSigningRequestPyOpenSSL(CertificateSigningRequestBase): return crypto.dump_certificate_request(crypto.FILETYPE_PEM, self.request) def _load_private_key(self): - self.privatekey = crypto_utils.load_privatekey(self.privatekey_path, self.privatekey_passphrase) + try: + self.privatekey = crypto_utils.load_privatekey(self.privatekey_path, self.privatekey_passphrase) + except crypto_utils.OpenSSLBadPassphraseError as exc: + raise CertificateSigningRequestError(exc) def _check_csr(self): def _check_subject(csr): @@ -776,7 +779,7 @@ class CertificateSigningRequestCryptography(CertificateSigningRequestBase): cryptography.x509.NameAttribute(self._get_name_oid(entry[0]), to_text(entry[1])) for entry in self.subject ])) except ValueError as e: - raise CertificateSigningRequestError(str(e)) + raise CertificateSigningRequestError(e) if self.subjectAltName: csr = csr.add_extension(cryptography.x509.SubjectAlternativeName([ diff --git a/lib/ansible/modules/crypto/openssl_pkcs12.py b/lib/ansible/modules/crypto/openssl_pkcs12.py index 7c69543f8bc..1d39d616951 100644 --- a/lib/ansible/modules/crypto/openssl_pkcs12.py +++ b/lib/ansible/modules/crypto/openssl_pkcs12.py @@ -215,6 +215,8 @@ class Pkcs(crypto_utils.OpenSSLObject): self.privatekey_passphrase) except crypto.Error: return False + except crypto_utils.OpenSSLBadPassphraseError: + return False return True if not state_and_perms: @@ -256,10 +258,13 @@ class Pkcs(crypto_utils.OpenSSLObject): self.pkcs12.set_friendlyname(to_bytes(self.friendly_name)) if self.privatekey_path: - self.pkcs12.set_privatekey(crypto_utils.load_privatekey( - self.privatekey_path, - self.privatekey_passphrase) - ) + try: + self.pkcs12.set_privatekey(crypto_utils.load_privatekey( + self.privatekey_path, + self.privatekey_passphrase) + ) + except crypto_utils.OpenSSLBadPassphraseError as exc: + raise PkcsError(exc) try: pkcs12_file = os.open(self.path, diff --git a/lib/ansible/modules/crypto/openssl_privatekey.py b/lib/ansible/modules/crypto/openssl_privatekey.py index 46e30645c75..91f4866f9ee 100644 --- a/lib/ansible/modules/crypto/openssl_privatekey.py +++ b/lib/ansible/modules/crypto/openssl_privatekey.py @@ -365,6 +365,8 @@ class PrivateKeyPyOpenSSL(PrivateKeyBase): return True except crypto.Error: return False + except crypto_utils.OpenSSLBadPassphraseError as exc: + return False def _check_size_and_type(self): def _check_size(privatekey): @@ -373,7 +375,10 @@ class PrivateKeyPyOpenSSL(PrivateKeyBase): def _check_type(privatekey): return self.type == privatekey.type() - privatekey = crypto_utils.load_privatekey(self.path, self.passphrase) + try: + privatekey = crypto_utils.load_privatekey(self.path, self.passphrase) + except crypto_utils.OpenSSLBadPassphraseError as exc: + raise PrivateKeyError(exc) return _check_size(privatekey) and _check_type(privatekey) @@ -513,10 +518,19 @@ class PrivateKeyCryptography(PrivateKeyBase): def _check_passphrase(self): try: - self._load_privatekey() + with open(self.path, 'rb') as f: + return cryptography.hazmat.primitives.serialization.load_pem_private_key( + f.read(), + None if self.passphrase is None else to_bytes(self.passphrase), + backend=self.cryptography_backend + ) return True - except crypto.Error: - return False + except TypeError as e: + if 'Password' in str(e) and 'encrypted' in str(e): + return False + raise PrivateKeyError(e) + except Exception as e: + raise PrivateKeyError(e) def _check_size_and_type(self): privatekey = self._load_privatekey() diff --git a/lib/ansible/modules/crypto/openssl_publickey.py b/lib/ansible/modules/crypto/openssl_publickey.py index 1ae797f36a1..be0f4bd50f4 100644 --- a/lib/ansible/modules/crypto/openssl_publickey.py +++ b/lib/ansible/modules/crypto/openssl_publickey.py @@ -200,6 +200,8 @@ class PublicKey(crypto_utils.OpenSSLObject): publickey_file.write(publickey_content) self.changed = True + except crypto_utils.OpenSSLBadPassphraseError as exc: + raise PublicKeyError(exc) except (IOError, OSError) as exc: raise PublicKeyError(exc) except AttributeError as exc: @@ -237,10 +239,13 @@ class PublicKey(crypto_utils.OpenSSLObject): except (crypto.Error, ValueError): return False - desired_publickey = crypto.dump_publickey( - crypto.FILETYPE_ASN1, - crypto_utils.load_privatekey(self.privatekey_path, self.privatekey_passphrase) - ) + try: + desired_publickey = crypto.dump_publickey( + crypto.FILETYPE_ASN1, + crypto_utils.load_privatekey(self.privatekey_path, self.privatekey_passphrase) + ) + except crypto_utils.OpenSSLBadPassphraseError as exc: + raise PublicKeyError(exc) return current_publickey == desired_publickey diff --git a/test/integration/targets/openssl_certificate/tasks/assertonly.yml b/test/integration/targets/openssl_certificate/tasks/assertonly.yml index 88df62d18e8..cc1f955a842 100644 --- a/test/integration/targets/openssl_certificate/tasks/assertonly.yml +++ b/test/integration/targets/openssl_certificate/tasks/assertonly.yml @@ -3,6 +3,13 @@ openssl_privatekey: path: '{{ output_dir }}/privatekey.pem' +- name: Generate privatekey with password + openssl_privatekey: + path: '{{ output_dir }}/privatekeypw.pem' + passphrase: hunter2 + cipher: auto + select_crypto_backend: cryptography + - name: Generate CSR (no extensions) openssl_csr: path: '{{ output_dir }}/csr_noext.csr' @@ -54,3 +61,39 @@ - "'Found no keyUsage extension' in extension_missing_ku.msg" - extension_missing_eku is failed - "'Found no extendedKeyUsage extension' in extension_missing_eku.msg" + +- name: Check private key passphrase fail 1 + openssl_certificate: + path: '{{ output_dir }}/cert_noext.pem' + privatekey_path: '{{ output_dir }}/privatekey.pem' + privatekey_passphrase: hunter2 + provider: assertonly + ignore_errors: yes + register: passphrase_error_1 + +- name: Check private key passphrase fail 2 + openssl_certificate: + path: '{{ output_dir }}/cert_noext.pem' + privatekey_path: '{{ output_dir }}/privatekeypw.pem' + privatekey_passphrase: wrong_password + provider: assertonly + ignore_errors: yes + register: passphrase_error_2 + +- name: Check private key passphrase fail 3 + openssl_certificate: + path: '{{ output_dir }}/cert_noext.pem' + privatekey_path: '{{ output_dir }}/privatekeypw.pem' + provider: assertonly + ignore_errors: yes + register: passphrase_error_3 + +- name: + assert: + that: + - passphrase_error_1 is failed + - "'assphrase' in passphrase_error_1.msg or 'assword' in passphrase_error_1.msg" + - passphrase_error_2 is failed + - "'assphrase' in passphrase_error_1.msg or 'assword' in passphrase_error_2.msg" + - passphrase_error_3 is failed + - "'assphrase' in passphrase_error_1.msg or 'assword' in passphrase_error_3.msg" diff --git a/test/integration/targets/openssl_certificate/tasks/ownca.yml b/test/integration/targets/openssl_certificate/tasks/ownca.yml index f2ea03fe56d..6b9abcc0079 100644 --- a/test/integration/targets/openssl_certificate/tasks/ownca.yml +++ b/test/integration/targets/openssl_certificate/tasks/ownca.yml @@ -151,4 +151,39 @@ ownca_digest: sha256 register: ownca_certificate_ecc +- name: Generate ownca certificate (failed passphrase 1) + openssl_certificate: + path: '{{ output_dir }}/ownca_cert_pw1.pem' + csr_path: '{{ output_dir }}/csr_ecc.csr' + ownca_path: '{{ output_dir }}/ca_cert.pem' + ownca_privatekey_path: '{{ output_dir }}/ca_privatekey.pem' + ownca_privatekey_passphrase: hunter2 + provider: ownca + ownca_digest: sha256 + ignore_errors: yes + register: passphrase_error_1 + +- name: Generate ownca certificate (failed passphrase 2) + openssl_certificate: + path: '{{ output_dir }}/ownca_cert_pw1.pem' + csr_path: '{{ output_dir }}/csr_ecc.csr' + ownca_path: '{{ output_dir }}/ca_cert.pem' + ownca_privatekey_path: '{{ output_dir }}/privatekeypw.pem' + ownca_privatekey_passphrase: wrong_password + provider: ownca + ownca_digest: sha256 + ignore_errors: yes + register: passphrase_error_2 + +- name: Generate ownca certificate (failed passphrase 3) + openssl_certificate: + path: '{{ output_dir }}/ownca_cert_pw3.pem' + csr_path: '{{ output_dir }}/csr_ecc.csr' + ownca_path: '{{ output_dir }}/ca_cert.pem' + ownca_privatekey_path: '{{ output_dir }}/privatekeypw.pem' + provider: ownca + ownca_digest: sha256 + ignore_errors: yes + register: passphrase_error_3 + - import_tasks: ../tests/validate_ownca.yml diff --git a/test/integration/targets/openssl_certificate/tasks/selfsigned.yml b/test/integration/targets/openssl_certificate/tasks/selfsigned.yml index 24dbe7737a8..f068e027785 100644 --- a/test/integration/targets/openssl_certificate/tasks/selfsigned.yml +++ b/test/integration/targets/openssl_certificate/tasks/selfsigned.yml @@ -3,6 +3,13 @@ openssl_privatekey: path: '{{ output_dir }}/privatekey.pem' +- name: Generate privatekey with password + openssl_privatekey: + path: '{{ output_dir }}/privatekeypw.pem' + passphrase: hunter2 + cipher: auto + select_crypto_backend: cryptography + - name: Generate CSR openssl_csr: path: '{{ output_dir }}/csr.csr' @@ -157,4 +164,36 @@ selfsigned_digest: sha256 register: selfsigned_certificate_ecc +- name: Generate selfsigned certificate (failed passphrase 1) + openssl_certificate: + path: '{{ output_dir }}/cert_pw1.pem' + csr_path: '{{ output_dir }}/csr_ecc.csr' + privatekey_path: '{{ output_dir }}/privatekey.pem' + privatekey_passphrase: hunter2 + provider: selfsigned + selfsigned_digest: sha256 + ignore_errors: yes + register: passphrase_error_1 + +- name: Generate selfsigned certificate (failed passphrase 2) + openssl_certificate: + path: '{{ output_dir }}/cert_pw2.pem' + csr_path: '{{ output_dir }}/csr_ecc.csr' + privatekey_path: '{{ output_dir }}/privatekeypw.pem' + privatekey_passphrase: wrong_password + provider: selfsigned + selfsigned_digest: sha256 + ignore_errors: yes + register: passphrase_error_2 + +- name: Generate selfsigned certificate (failed passphrase 3) + openssl_certificate: + path: '{{ output_dir }}/cert_pw3.pem' + csr_path: '{{ output_dir }}/csr_ecc.csr' + privatekey_path: '{{ output_dir }}/privatekeypw.pem' + provider: selfsigned + selfsigned_digest: sha256 + ignore_errors: yes + register: passphrase_error_3 + - import_tasks: ../tests/validate_selfsigned.yml diff --git a/test/integration/targets/openssl_certificate/tests/validate_ownca.yml b/test/integration/targets/openssl_certificate/tests/validate_ownca.yml index 05b6b2e57fe..b22d57de230 100644 --- a/test/integration/targets/openssl_certificate/tests/validate_ownca.yml +++ b/test/integration/targets/openssl_certificate/tests/validate_ownca.yml @@ -81,3 +81,13 @@ - ownca_cert_ecc_pubkey.stdout == privatekey_ecc_pubkey.stdout # openssl 1.1.x adds a space between the output - ownca_cert_ecc_issuer.stdout in ['CN=Example CA', 'CN = Example CA'] + +- name: + assert: + that: + - passphrase_error_1 is failed + - "'assphrase' in passphrase_error_1.msg or 'assword' in passphrase_error_1.msg" + - passphrase_error_2 is failed + - "'assphrase' in passphrase_error_1.msg or 'assword' in passphrase_error_2.msg" + - passphrase_error_3 is failed + - "'assphrase' in passphrase_error_1.msg or 'assword' in passphrase_error_3.msg" diff --git a/test/integration/targets/openssl_certificate/tests/validate_selfsigned.yml b/test/integration/targets/openssl_certificate/tests/validate_selfsigned.yml index 25cef100d9b..8749418a47c 100644 --- a/test/integration/targets/openssl_certificate/tests/validate_selfsigned.yml +++ b/test/integration/targets/openssl_certificate/tests/validate_selfsigned.yml @@ -82,3 +82,13 @@ assert: that: - cert_ecc_pubkey.stdout == privatekey_ecc_pubkey.stdout + +- name: + assert: + that: + - passphrase_error_1 is failed + - "'assphrase' in passphrase_error_1.msg or 'assword' in passphrase_error_1.msg" + - passphrase_error_2 is failed + - "'assphrase' in passphrase_error_1.msg or 'assword' in passphrase_error_2.msg" + - passphrase_error_3 is failed + - "'assphrase' in passphrase_error_1.msg or 'assword' in passphrase_error_3.msg" diff --git a/test/integration/targets/openssl_csr/tasks/impl.yml b/test/integration/targets/openssl_csr/tasks/impl.yml index 1d63076306d..07791aee805 100644 --- a/test/integration/targets/openssl_csr/tasks/impl.yml +++ b/test/integration/targets/openssl_csr/tasks/impl.yml @@ -241,3 +241,36 @@ select_crypto_backend: '{{ select_crypto_backend }}' register: country_fail_4 ignore_errors: yes + +- name: Generate privatekey with password + openssl_privatekey: + path: '{{ output_dir }}/privatekeypw.pem' + passphrase: hunter2 + cipher: auto + select_crypto_backend: cryptography + +- name: Generate publickey - PEM format + openssl_csr: + path: '{{ output_dir }}/csr_pw1.csr' + privatekey_path: '{{ output_dir }}/privatekey.pem' + privatekey_passphrase: hunter2 + select_crypto_backend: '{{ select_crypto_backend }}' + ignore_errors: yes + register: passphrase_error_1 + +- name: Generate publickey - PEM format + openssl_csr: + path: '{{ output_dir }}/csr_pw2.csr' + privatekey_path: '{{ output_dir }}/privatekeypw.pem' + privatekey_passphrase: wrong_password + select_crypto_backend: '{{ select_crypto_backend }}' + ignore_errors: yes + register: passphrase_error_2 + +- name: Generate publickey - PEM format + openssl_csr: + path: '{{ output_dir }}/csr_pw3.csr' + privatekey_path: '{{ output_dir }}/privatekeypw.pem' + select_crypto_backend: '{{ select_crypto_backend }}' + ignore_errors: yes + register: passphrase_error_3 diff --git a/test/integration/targets/openssl_csr/tests/validate.yml b/test/integration/targets/openssl_csr/tests/validate.yml index e8e46aedaaf..4f99e4b7881 100644 --- a/test/integration/targets/openssl_csr/tests/validate.yml +++ b/test/integration/targets/openssl_csr/tests/validate.yml @@ -109,3 +109,13 @@ - country_idempotent_2 is not changed - country_idempotent_3 is not changed - country_fail_4 is failed + +- name: + assert: + that: + - passphrase_error_1 is failed + - "'assphrase' in passphrase_error_1.msg or 'assword' in passphrase_error_1.msg" + - passphrase_error_2 is failed + - "'assphrase' in passphrase_error_1.msg or 'assword' in passphrase_error_2.msg" + - passphrase_error_3 is failed + - "'assphrase' in passphrase_error_1.msg or 'assword' in passphrase_error_3.msg" diff --git a/test/integration/targets/openssl_pkcs12/tasks/main.yml b/test/integration/targets/openssl_pkcs12/tasks/main.yml index e3803a662a2..c9552441de3 100644 --- a/test/integration/targets/openssl_pkcs12/tasks/main.yml +++ b/test/integration/targets/openssl_pkcs12/tasks/main.yml @@ -53,6 +53,45 @@ action: 'parse' state: 'present' + - name: Generate privatekey with password + openssl_privatekey: + path: '{{ output_dir }}/privatekeypw.pem' + passphrase: hunter2 + cipher: auto + select_crypto_backend: cryptography + + - name: 'Generate PKCS#12 file (password fail 1)' + openssl_pkcs12: + path: "{{ output_dir }}/ansible_pw1.p12" + friendly_name: 'abracadabra' + privatekey_path: "{{ output_dir }}/ansible_pkey.pem" + privatekey_passphrase: hunter2 + certificate_path: "{{ output_dir }}/ansible.crt" + state: present + ignore_errors: yes + register: passphrase_error_1 + + - name: 'Generate PKCS#12 file (password fail 2)' + openssl_pkcs12: + path: "{{ output_dir }}/ansible_pw2.p12" + friendly_name: 'abracadabra' + privatekey_path: '{{ output_dir }}/privatekeypw.pem' + privatekey_passphrase: wrong_password + certificate_path: "{{ output_dir }}/ansible.crt" + state: present + ignore_errors: yes + register: passphrase_error_2 + + - name: 'Generate PKCS#12 file (password fail 3)' + openssl_pkcs12: + path: "{{ output_dir }}/ansible_pw3.p12" + friendly_name: 'abracadabra' + privatekey_path: '{{ output_dir }}/privatekeypw.pem' + certificate_path: "{{ output_dir }}/ansible.crt" + state: present + ignore_errors: yes + register: passphrase_error_3 + - import_tasks: ../tests/validate.yml always: diff --git a/test/integration/targets/openssl_pkcs12/tests/validate.yml b/test/integration/targets/openssl_pkcs12/tests/validate.yml index 5799186ff7c..e0a318aad85 100644 --- a/test/integration/targets/openssl_pkcs12/tests/validate.yml +++ b/test/integration/targets/openssl_pkcs12/tests/validate.yml @@ -14,3 +14,13 @@ - p12_standard.mode == '0400' - p12_force.changed - p12_force_and_mode.mode == '0644' and p12_force_and_mode.changed + +- name: + assert: + that: + - passphrase_error_1 is failed + - "'assphrase' in passphrase_error_1.msg or 'assword' in passphrase_error_1.msg" + - passphrase_error_2 is failed + - "'assphrase' in passphrase_error_1.msg or 'assword' in passphrase_error_2.msg" + - passphrase_error_3 is failed + - "'assphrase' in passphrase_error_1.msg or 'assword' in passphrase_error_3.msg" diff --git a/test/integration/targets/openssl_privatekey/tasks/impl.yml b/test/integration/targets/openssl_privatekey/tasks/impl.yml index 761beaa3a5c..c948349c473 100644 --- a/test/integration/targets/openssl_privatekey/tasks/impl.yml +++ b/test/integration/targets/openssl_privatekey/tasks/impl.yml @@ -142,3 +142,39 @@ loop_control: label: "{{ item.curve }}" register: privatekey_ecc_idempotency + +- name: Generate privatekey with passphrase + openssl_privatekey: + path: '{{ output_dir }}/privatekeypw.pem' + passphrase: hunter2 + cipher: "{{ 'aes256' if select_crypto_backend == 'pyopenssl' else 'auto' }}" + select_crypto_backend: '{{ select_crypto_backend }}' + register: passphrase_1 + +- name: Generate privatekey with passphrase (idempotent) + openssl_privatekey: + path: '{{ output_dir }}/privatekeypw.pem' + passphrase: hunter2 + cipher: "{{ 'aes256' if select_crypto_backend == 'pyopenssl' else 'auto' }}" + select_crypto_backend: '{{ select_crypto_backend }}' + register: passphrase_2 + +- name: Regenerate privatekey without passphrase + openssl_privatekey: + path: '{{ output_dir }}/privatekeypw.pem' + select_crypto_backend: '{{ select_crypto_backend }}' + register: passphrase_3 + +- name: Regenerate privatekey without passphrase (idempotent) + openssl_privatekey: + path: '{{ output_dir }}/privatekeypw.pem' + select_crypto_backend: '{{ select_crypto_backend }}' + register: passphrase_4 + +- name: Regenerate privatekey with passphrase + openssl_privatekey: + path: '{{ output_dir }}/privatekeypw.pem' + passphrase: hunter2 + cipher: "{{ 'aes256' if select_crypto_backend == 'pyopenssl' else 'auto' }}" + select_crypto_backend: '{{ select_crypto_backend }}' + register: passphrase_5 diff --git a/test/integration/targets/openssl_privatekey/tests/validate.yml b/test/integration/targets/openssl_privatekey/tests/validate.yml index 7962de8af61..da5e2ecb571 100644 --- a/test/integration/targets/openssl_privatekey/tests/validate.yml +++ b/test/integration/targets/openssl_privatekey/tests/validate.yml @@ -104,3 +104,12 @@ when: "'skip_reason' not in item" loop_control: label: "{{ item.item.curve }}" + +- name: Validate passphrase changing + assert: + that: + - passphrase_1 is changed + - passphrase_2 is not changed + - passphrase_3 is changed + - passphrase_4 is not changed + - passphrase_5 is changed diff --git a/test/integration/targets/openssl_publickey/tasks/main.yml b/test/integration/targets/openssl_publickey/tasks/main.yml index b8e93933c85..3e9ee3cf2c4 100644 --- a/test/integration/targets/openssl_publickey/tasks/main.yml +++ b/test/integration/targets/openssl_publickey/tasks/main.yml @@ -78,6 +78,36 @@ path: '{{ output_dir }}/publickey5.pub' privatekey_path: '{{ output_dir }}/privatekey5.pem' + - name: Generate privatekey with password + openssl_privatekey: + path: '{{ output_dir }}/privatekeypw.pem' + passphrase: hunter2 + cipher: auto + select_crypto_backend: cryptography + + - name: Generate publickey - PEM format (failed passphrase 1) + openssl_publickey: + path: '{{ output_dir }}/publickey_pw1.pub' + privatekey_path: '{{ output_dir }}/privatekey.pem' + privatekey_passphrase: hunter2 + ignore_errors: yes + register: passphrase_error_1 + + - name: Generate publickey - PEM format (failed passphrase 2) + openssl_publickey: + path: '{{ output_dir }}/publickey_pw2.pub' + privatekey_path: '{{ output_dir }}/privatekeypw.pem' + privatekey_passphrase: wrong_password + ignore_errors: yes + register: passphrase_error_2 + + - name: Generate publickey - PEM format (failed passphrase 3) + openssl_publickey: + path: '{{ output_dir }}/publickey_pw3.pub' + privatekey_path: '{{ output_dir }}/privatekeypw.pem' + ignore_errors: yes + register: passphrase_error_3 + - import_tasks: ../tests/validate.yml when: pyopenssl_version.stdout is version('16.0.0', '>=') diff --git a/test/integration/targets/openssl_publickey/tests/validate.yml b/test/integration/targets/openssl_publickey/tests/validate.yml index 6e422946387..e8a068c5b5c 100644 --- a/test/integration/targets/openssl_publickey/tests/validate.yml +++ b/test/integration/targets/openssl_publickey/tests/validate.yml @@ -96,3 +96,13 @@ assert: that: - publickey5_pubkey.stdout == privatekey5_pubkey.stdout + +- name: + assert: + that: + - passphrase_error_1 is failed + - "'assphrase' in passphrase_error_1.msg or 'assword' in passphrase_error_1.msg" + - passphrase_error_2 is failed + - "'assphrase' in passphrase_error_1.msg or 'assword' in passphrase_error_2.msg" + - passphrase_error_3 is failed + - "'assphrase' in passphrase_error_1.msg or 'assword' in passphrase_error_3.msg"