mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-07-22 12:50:22 -07:00
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 <felix@fontein.de>
This commit is contained in:
parent
1d91e03119
commit
caf7fd2245
20 changed files with 427 additions and 36 deletions
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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', '>=')
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue