mirror of https://github.com/ansible/ansible.git
openssl_privatekey: add ECC support (#49416)
* Add cryptography backend for openssl_privatekey. * Adding ECC support. No support for X25519 and X449, since they don't support serialization. * Improve finterprint calculation to work with Python 3. * Add fingerprint check. * Fix typo. * Use separate curve option for elliptic curves, and use type 'ECC'. * Using curve names as defined in IANA registry. * Bump minimal supported cryptography version. Older versions might work as well, but I couldn't test them. * Improve documentation.pull/50080/head
parent
6d952e4124
commit
92ef500185
@ -0,0 +1,144 @@
|
|||||||
|
---
|
||||||
|
- name: Generate privatekey1 - standard
|
||||||
|
openssl_privatekey:
|
||||||
|
path: '{{ output_dir }}/privatekey1.pem'
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
|
||||||
|
- name: Generate privatekey2 - size 2048
|
||||||
|
openssl_privatekey:
|
||||||
|
path: '{{ output_dir }}/privatekey2.pem'
|
||||||
|
size: 2048
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
|
||||||
|
- name: Generate privatekey3 - type DSA
|
||||||
|
openssl_privatekey:
|
||||||
|
path: '{{ output_dir }}/privatekey3.pem'
|
||||||
|
type: DSA
|
||||||
|
size: 3072
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
|
||||||
|
- name: Generate privatekey4 - standard
|
||||||
|
openssl_privatekey:
|
||||||
|
path: '{{ output_dir }}/privatekey4.pem'
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
|
||||||
|
- name: Delete privatekey4 - standard
|
||||||
|
openssl_privatekey:
|
||||||
|
state: absent
|
||||||
|
path: '{{ output_dir }}/privatekey4.pem'
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
|
||||||
|
- name: Generate privatekey5 - standard - with passphrase
|
||||||
|
openssl_privatekey:
|
||||||
|
path: '{{ output_dir }}/privatekey5.pem'
|
||||||
|
passphrase: ansible
|
||||||
|
cipher: "{{ 'aes256' if select_crypto_backend == 'pyopenssl' else 'auto' }}"
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
|
||||||
|
- name: Generate privatekey5 - standard - idempotence
|
||||||
|
openssl_privatekey:
|
||||||
|
path: '{{ output_dir }}/privatekey5.pem'
|
||||||
|
passphrase: ansible
|
||||||
|
cipher: "{{ 'aes256' if select_crypto_backend == 'pyopenssl' else 'auto' }}"
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
register: privatekey5_idempotence
|
||||||
|
|
||||||
|
- name: Generate privatekey6 - standard - with non-ASCII passphrase
|
||||||
|
openssl_privatekey:
|
||||||
|
path: '{{ output_dir }}/privatekey6.pem'
|
||||||
|
passphrase: ànsïblé
|
||||||
|
cipher: "{{ 'aes256' if select_crypto_backend == 'pyopenssl' else 'auto' }}"
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
ecc_types: []
|
||||||
|
when: select_crypto_backend == 'pyopenssl'
|
||||||
|
- set_fact:
|
||||||
|
ecc_types:
|
||||||
|
# - curve: X448
|
||||||
|
# min_cryptography_version: "2.5"
|
||||||
|
# - curve: X25519
|
||||||
|
# min_cryptography_version: "2.0"
|
||||||
|
- curve: secp384r1
|
||||||
|
openssl_name: secp384r1
|
||||||
|
min_cryptography_version: "0.5"
|
||||||
|
- curve: secp521r1
|
||||||
|
openssl_name: secp521r1
|
||||||
|
min_cryptography_version: "0.5"
|
||||||
|
- curve: secp224r1
|
||||||
|
openssl_name: secp224r1
|
||||||
|
min_cryptography_version: "0.5"
|
||||||
|
- curve: secp192r1
|
||||||
|
openssl_name: prime192v1
|
||||||
|
min_cryptography_version: "0.5"
|
||||||
|
- curve: secp256k1
|
||||||
|
openssl_name: secp256k1
|
||||||
|
min_cryptography_version: "0.9"
|
||||||
|
- curve: brainpoolP256r1
|
||||||
|
openssl_name: brainpoolP256r1
|
||||||
|
min_cryptography_version: "2.2"
|
||||||
|
- curve: brainpoolP384r1
|
||||||
|
openssl_name: brainpoolP384r1
|
||||||
|
min_cryptography_version: "2.2"
|
||||||
|
- curve: brainpoolP512r1
|
||||||
|
openssl_name: brainpoolP512r1
|
||||||
|
min_cryptography_version: "2.2"
|
||||||
|
- curve: sect571k1
|
||||||
|
openssl_name: sect571k1
|
||||||
|
min_cryptography_version: "0.5"
|
||||||
|
- curve: sect409k1
|
||||||
|
openssl_name: sect409k1
|
||||||
|
min_cryptography_version: "0.5"
|
||||||
|
- curve: sect283k1
|
||||||
|
openssl_name: sect283k1
|
||||||
|
min_cryptography_version: "0.5"
|
||||||
|
- curve: sect233k1
|
||||||
|
openssl_name: sect233k1
|
||||||
|
min_cryptography_version: "0.5"
|
||||||
|
- curve: sect163k1
|
||||||
|
openssl_name: sect163k1
|
||||||
|
min_cryptography_version: "0.5"
|
||||||
|
- curve: sect571r1
|
||||||
|
openssl_name: sect571r1
|
||||||
|
min_cryptography_version: "0.5"
|
||||||
|
- curve: sect409r1
|
||||||
|
openssl_name: sect409r1
|
||||||
|
min_cryptography_version: "0.5"
|
||||||
|
- curve: sect283r1
|
||||||
|
openssl_name: sect283r1
|
||||||
|
min_cryptography_version: "0.5"
|
||||||
|
- curve: sect233r1
|
||||||
|
openssl_name: sect233r1
|
||||||
|
min_cryptography_version: "0.5"
|
||||||
|
- curve: sect163r2
|
||||||
|
openssl_name: sect163r2
|
||||||
|
min_cryptography_version: "0.5"
|
||||||
|
when: select_crypto_backend == 'cryptography'
|
||||||
|
|
||||||
|
- name: Test ECC key generation
|
||||||
|
openssl_privatekey:
|
||||||
|
path: '{{ output_dir }}/privatekey-{{ item.curve }}.pem'
|
||||||
|
type: ECC
|
||||||
|
curve: "{{ item.curve }}"
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: |
|
||||||
|
cryptography_version.stdout is version(item.min_cryptography_version, '>=') and
|
||||||
|
item.openssl_name in openssl_ecc_list
|
||||||
|
loop: "{{ ecc_types }}"
|
||||||
|
loop_control:
|
||||||
|
label: "{{ item.curve }}"
|
||||||
|
register: privatekey_ecc_generate
|
||||||
|
|
||||||
|
- name: Test ECC key generation (idempotency)
|
||||||
|
openssl_privatekey:
|
||||||
|
path: '{{ output_dir }}/privatekey-{{ item.curve }}.pem'
|
||||||
|
type: ECC
|
||||||
|
curve: "{{ item.curve }}"
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: |
|
||||||
|
cryptography_version.stdout is version(item.min_cryptography_version, '>=') and
|
||||||
|
item.openssl_name in openssl_ecc_list
|
||||||
|
loop: "{{ ecc_types }}"
|
||||||
|
loop_control:
|
||||||
|
label: "{{ item.curve }}"
|
||||||
|
register: privatekey_ecc_idempotency
|
@ -1,43 +1,95 @@
|
|||||||
- name: Generate privatekey1 - standard
|
---
|
||||||
openssl_privatekey:
|
- name: Find out which elliptic curves are supported by installed OpenSSL
|
||||||
path: '{{ output_dir }}/privatekey1.pem'
|
command: openssl ecparam -list_curves
|
||||||
|
register: openssl_ecc
|
||||||
- name: Generate privatekey2 - size 2048
|
|
||||||
openssl_privatekey:
|
- name: Compile list of elliptic curves supported by OpenSSL
|
||||||
path: '{{ output_dir }}/privatekey2.pem'
|
set_fact:
|
||||||
size: 2048
|
openssl_ecc_list: |
|
||||||
|
{{
|
||||||
- name: Generate privatekey3 - type DSA
|
openssl_ecc.stdout_lines
|
||||||
openssl_privatekey:
|
| map('regex_search', '^ *([a-zA-Z0-9_-]+) *: .*$')
|
||||||
path: '{{ output_dir }}/privatekey3.pem'
|
| select()
|
||||||
type: DSA
|
| map('regex_replace', '^ *([a-zA-Z0-9_-]+) *: .*$', '\1')
|
||||||
|
| list
|
||||||
- name: Generate privatekey4 - standard
|
}}
|
||||||
openssl_privatekey:
|
when: ansible_distribution != 'CentOS' or ansible_distribution_major_version != '6'
|
||||||
path: '{{ output_dir }}/privatekey4.pem'
|
# CentOS comes with a very old jinja2 which does not include the map() filter...
|
||||||
|
- name: Compile list of elliptic curves supported by OpenSSL (CentOS 6)
|
||||||
- name: Delete privatekey4 - standard
|
set_fact:
|
||||||
openssl_privatekey:
|
openssl_ecc_list:
|
||||||
|
- secp384r1
|
||||||
|
- secp521r1
|
||||||
|
- prime256v1
|
||||||
|
when: ansible_distribution == 'CentOS' and ansible_distribution_major_version == '6'
|
||||||
|
|
||||||
|
- name: List of elliptic curves supported by OpenSSL
|
||||||
|
debug: var=openssl_ecc_list
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: Running tests with pyOpenSSL backend
|
||||||
|
include_tasks: impl.yml
|
||||||
|
vars:
|
||||||
|
select_crypto_backend: pyopenssl
|
||||||
|
|
||||||
|
- import_tasks: ../tests/validate.yml
|
||||||
|
|
||||||
|
# FIXME: minimal pyOpenSSL version?!
|
||||||
|
when: pyopenssl_version.stdout is version('0.6', '>=')
|
||||||
|
|
||||||
|
- name: Remove output directory
|
||||||
|
file:
|
||||||
|
path: "{{ output_dir }}"
|
||||||
state: absent
|
state: absent
|
||||||
path: '{{ output_dir }}/privatekey4.pem'
|
|
||||||
|
- name: Re-create output directory
|
||||||
- name: Generate privatekey5 - standard - with passphrase
|
file:
|
||||||
openssl_privatekey:
|
path: "{{ output_dir }}"
|
||||||
path: '{{ output_dir }}/privatekey5.pem'
|
state: directory
|
||||||
passphrase: ansible
|
|
||||||
cipher: aes256
|
- block:
|
||||||
|
- name: Running tests with cryptography backend
|
||||||
- name: Generate privatekey5 - standard - idempotence
|
include_tasks: impl.yml
|
||||||
openssl_privatekey:
|
vars:
|
||||||
path: '{{ output_dir }}/privatekey5.pem'
|
select_crypto_backend: cryptography
|
||||||
passphrase: ansible
|
|
||||||
cipher: aes256
|
- import_tasks: ../tests/validate.yml
|
||||||
register: privatekey5_idempotence
|
|
||||||
|
when: cryptography_version.stdout is version('0.5', '>=')
|
||||||
- name: Generate privatekey6 - standard - with non-ASCII passphrase
|
|
||||||
openssl_privatekey:
|
- name: Check that fingerprints do not depend on the backend
|
||||||
path: '{{ output_dir }}/privatekey6.pem'
|
block:
|
||||||
passphrase: ànsïblé
|
- name: "Fingerprint comparison: pyOpenSSL"
|
||||||
cipher: aes256
|
openssl_privatekey:
|
||||||
|
path: '{{ output_dir }}/fingerprint-{{ item }}.pem'
|
||||||
- import_tasks: ../tests/validate.yml
|
type: "{{ item }}"
|
||||||
|
size: 1024
|
||||||
|
select_crypto_backend: pyopenssl
|
||||||
|
loop:
|
||||||
|
- RSA
|
||||||
|
- DSA
|
||||||
|
register: fingerprint_pyopenssl
|
||||||
|
|
||||||
|
- name: "Fingerprint comparison: cryptography"
|
||||||
|
openssl_privatekey:
|
||||||
|
path: '{{ output_dir }}/fingerprint-{{ item }}.pem'
|
||||||
|
type: "{{ item }}"
|
||||||
|
size: 1024
|
||||||
|
select_crypto_backend: cryptography
|
||||||
|
loop:
|
||||||
|
- RSA
|
||||||
|
- DSA
|
||||||
|
register: fingerprint_cryptography
|
||||||
|
|
||||||
|
- 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', '>=')
|
||||||
|
Loading…
Reference in New Issue