openssl_pkcs12: add cryptography backend (#234)
* Began refactoring. * Continue. * Factor PyOpenSSL backend out. * Add basic cryptography backend. * Update plugins/modules/openssl_pkcs12.py Co-authored-by: Ajpantuso <ajpantuso@gmail.com> * Only run tests when new enough pyOpenSSL or cryptography is around. * Reduce required pyOpenSSL version from 17.1.0 to 0.15. I have no idea why 17.1.0 was there (in the tests), and not something smaller. The module itself did not mention any version. * Linting. * Linting. * Increase compatibility by selecting pyopenssl backend when iter_size or maciter_size is used. * Improve docs, add changelog fragment. * Move hackish code to cryptography_support. * Update plugins/modules/openssl_pkcs12.py Co-authored-by: Ajpantuso <ajpantuso@gmail.com> * Update plugins/modules/openssl_pkcs12.py Co-authored-by: Ajpantuso <ajpantuso@gmail.com> * Streamline cert creation. * Convert range to list. Co-authored-by: Ajpantuso <ajpantuso@gmail.com>pull/239/head
parent
0a0d0f2bdf
commit
e9bc7c7163
|
@ -0,0 +1,4 @@
|
||||||
|
minor_changes:
|
||||||
|
- "openssl_pkcs12 - added option ``select_crypto_backend`` and a ``cryptography`` backend.
|
||||||
|
This requires cryptography 3.0 or newer, and does not support the ``iter_size`` and ``maciter_size`` options
|
||||||
|
(https://github.com/ansible-collections/community.crypto/pull/234)."
|
|
@ -35,6 +35,15 @@ except ImportError:
|
||||||
# Error handled in the calling module.
|
# Error handled in the calling module.
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
# This is a separate try/except since this is only present in cryptography 2.5 or newer
|
||||||
|
from cryptography.hazmat.primitives.serialization.pkcs12 import (
|
||||||
|
load_key_and_certificates as _load_key_and_certificates,
|
||||||
|
)
|
||||||
|
except ImportError:
|
||||||
|
# Error handled in the calling module.
|
||||||
|
_load_key_and_certificates = None
|
||||||
|
|
||||||
from .basic import (
|
from .basic import (
|
||||||
CRYPTOGRAPHY_HAS_ED25519,
|
CRYPTOGRAPHY_HAS_ED25519,
|
||||||
CRYPTOGRAPHY_HAS_ED448,
|
CRYPTOGRAPHY_HAS_ED448,
|
||||||
|
@ -428,3 +437,21 @@ def cryptography_serial_number_of_cert(cert):
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# The property was called "serial" before cryptography 1.4
|
# The property was called "serial" before cryptography 1.4
|
||||||
return cert.serial
|
return cert.serial
|
||||||
|
|
||||||
|
|
||||||
|
def parse_pkcs12(pkcs12_bytes, passphrase=None):
|
||||||
|
'''Returns a tuple (private_key, certificate, additional_certificates, friendly_name).
|
||||||
|
'''
|
||||||
|
if _load_key_and_certificates is None:
|
||||||
|
raise ValueError('load_key_and_certificates() not present in the current cryptography version')
|
||||||
|
private_key, certificate, additional_certificates = _load_key_and_certificates(pkcs12_bytes, passphrase)
|
||||||
|
|
||||||
|
friendly_name = None
|
||||||
|
if certificate:
|
||||||
|
# See https://github.com/pyca/cryptography/issues/5760#issuecomment-842687238
|
||||||
|
maybe_name = certificate._backend._lib.X509_alias_get0(
|
||||||
|
certificate._x509, certificate._backend._ffi.NULL)
|
||||||
|
if maybe_name != certificate._backend._ffi.NULL:
|
||||||
|
friendly_name = certificate._backend._ffi.string(maybe_name)
|
||||||
|
|
||||||
|
return private_key, certificate, additional_certificates, friendly_name
|
||||||
|
|
|
@ -16,8 +16,14 @@ author:
|
||||||
short_description: Generate OpenSSL PKCS#12 archive
|
short_description: Generate OpenSSL PKCS#12 archive
|
||||||
description:
|
description:
|
||||||
- This module allows one to (re-)generate PKCS#12.
|
- This module allows one to (re-)generate PKCS#12.
|
||||||
|
- The module can use the cryptography Python library, or the pyOpenSSL Python
|
||||||
|
library. By default, it tries to detect which one is available, assuming none of the
|
||||||
|
I(iter_size) and I(maciter_size) options are used. This can be overridden with the
|
||||||
|
I(select_crypto_backend) option.
|
||||||
|
# Please note that the C(pyopenssl) backend has been deprecated in community.crypto x.y.0,
|
||||||
|
# and will be removed in community.crypto (x+1).0.0.
|
||||||
requirements:
|
requirements:
|
||||||
- python-pyOpenSSL
|
- PyOpenSSL >= 0.15 or cryptography >= 3.0
|
||||||
options:
|
options:
|
||||||
action:
|
action:
|
||||||
description:
|
description:
|
||||||
|
@ -58,16 +64,21 @@ options:
|
||||||
iter_size:
|
iter_size:
|
||||||
description:
|
description:
|
||||||
- Number of times to repeat the encryption step.
|
- Number of times to repeat the encryption step.
|
||||||
|
- This is not considered during idempotency checks.
|
||||||
|
- This is only used by the C(pyopenssl) backend. When using it, the default is C(2048).
|
||||||
type: int
|
type: int
|
||||||
default: 2048
|
|
||||||
maciter_size:
|
maciter_size:
|
||||||
description:
|
description:
|
||||||
- Number of times to repeat the MAC step.
|
- Number of times to repeat the MAC step.
|
||||||
|
- This is not considered during idempotency checks.
|
||||||
|
- This is only used by the C(pyopenssl) backend. When using it, the default is C(1).
|
||||||
type: int
|
type: int
|
||||||
default: 1
|
|
||||||
passphrase:
|
passphrase:
|
||||||
description:
|
description:
|
||||||
- The PKCS#12 password.
|
- The PKCS#12 password.
|
||||||
|
- "B(Note:) PKCS12 encryption is not secure and should not be used as a security mechanism.
|
||||||
|
If you need to store or send a PKCS12 file safely, you should additionally encrypt it
|
||||||
|
with something else."
|
||||||
type: str
|
type: str
|
||||||
path:
|
path:
|
||||||
description:
|
description:
|
||||||
|
@ -105,6 +116,21 @@ options:
|
||||||
type: bool
|
type: bool
|
||||||
default: no
|
default: no
|
||||||
version_added: "1.0.0"
|
version_added: "1.0.0"
|
||||||
|
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 one of I(iter_size) or I(maciter_size) is used, C(auto) will always result in C(pyopenssl) to be chosen
|
||||||
|
for backwards compatibility.
|
||||||
|
- If set to C(pyopenssl), will try to use the L(pyOpenSSL,https://pypi.org/project/pyOpenSSL/) library.
|
||||||
|
- 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 community.crypto x.y.0, and will be
|
||||||
|
# removed in community.crypto (x+1).0.0.
|
||||||
|
# From that point on, only the C(cryptography) backend will be available.
|
||||||
|
type: str
|
||||||
|
default: auto
|
||||||
|
choices: [ auto, cryptography, pyopenssl ]
|
||||||
|
version_added: 1.7.0
|
||||||
extends_documentation_fragment:
|
extends_documentation_fragment:
|
||||||
- files
|
- files
|
||||||
seealso:
|
seealso:
|
||||||
|
@ -207,11 +233,14 @@ pkcs12:
|
||||||
version_added: "1.0.0"
|
version_added: "1.0.0"
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
import abc
|
||||||
import base64
|
import base64
|
||||||
import os
|
import os
|
||||||
import stat
|
import stat
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
from distutils.version import LooseVersion
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||||
from ansible.module_utils._text import to_bytes, to_native
|
from ansible.module_utils._text import to_bytes, to_native
|
||||||
|
|
||||||
|
@ -225,6 +254,10 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.basic impo
|
||||||
OpenSSLBadPassphraseError,
|
OpenSSLBadPassphraseError,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from ansible_collections.community.crypto.plugins.module_utils.crypto.cryptography_support import (
|
||||||
|
parse_pkcs12,
|
||||||
|
)
|
||||||
|
|
||||||
from ansible_collections.community.crypto.plugins.module_utils.crypto.support import (
|
from ansible_collections.community.crypto.plugins.module_utils.crypto.support import (
|
||||||
OpenSSLObject,
|
OpenSSLObject,
|
||||||
load_privatekey,
|
load_privatekey,
|
||||||
|
@ -235,23 +268,40 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.pem import
|
||||||
split_pem_list,
|
split_pem_list,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
MINIMAL_CRYPTOGRAPHY_VERSION = '3.0'
|
||||||
|
MINIMAL_PYOPENSSL_VERSION = '0.15'
|
||||||
|
|
||||||
PYOPENSSL_IMP_ERR = None
|
PYOPENSSL_IMP_ERR = None
|
||||||
try:
|
try:
|
||||||
|
import OpenSSL
|
||||||
from OpenSSL import crypto
|
from OpenSSL import crypto
|
||||||
|
PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
PYOPENSSL_IMP_ERR = traceback.format_exc()
|
PYOPENSSL_IMP_ERR = traceback.format_exc()
|
||||||
pyopenssl_found = False
|
PYOPENSSL_FOUND = False
|
||||||
else:
|
else:
|
||||||
pyopenssl_found = True
|
PYOPENSSL_FOUND = True
|
||||||
|
|
||||||
|
CRYPTOGRAPHY_IMP_ERR = None
|
||||||
|
try:
|
||||||
|
import cryptography
|
||||||
|
from cryptography.hazmat.primitives import serialization
|
||||||
|
from cryptography.hazmat.primitives.serialization.pkcs12 import serialize_key_and_certificates
|
||||||
|
CRYPTOGRAPHY_VERSION = LooseVersion(cryptography.__version__)
|
||||||
|
except ImportError:
|
||||||
|
CRYPTOGRAPHY_IMP_ERR = traceback.format_exc()
|
||||||
|
CRYPTOGRAPHY_FOUND = False
|
||||||
|
else:
|
||||||
|
CRYPTOGRAPHY_FOUND = True
|
||||||
|
|
||||||
|
|
||||||
def load_certificate_set(filename):
|
def load_certificate_set(filename, backend):
|
||||||
'''
|
'''
|
||||||
Load list of concatenated PEM files, and return a list of parsed certificates.
|
Load list of concatenated PEM files, and return a list of parsed certificates.
|
||||||
'''
|
'''
|
||||||
with open(filename, 'rb') as f:
|
with open(filename, 'rb') as f:
|
||||||
data = f.read().decode('utf-8')
|
data = f.read().decode('utf-8')
|
||||||
return [load_certificate(None, content=cert) for cert in split_pem_list(data)]
|
return [load_certificate(None, content=cert.encode('utf-8'), backend=backend) for cert in split_pem_list(data)]
|
||||||
|
|
||||||
|
|
||||||
class PkcsError(OpenSSLObjectError):
|
class PkcsError(OpenSSLObjectError):
|
||||||
|
@ -259,21 +309,21 @@ class PkcsError(OpenSSLObjectError):
|
||||||
|
|
||||||
|
|
||||||
class Pkcs(OpenSSLObject):
|
class Pkcs(OpenSSLObject):
|
||||||
|
def __init__(self, module, backend):
|
||||||
def __init__(self, module):
|
|
||||||
super(Pkcs, self).__init__(
|
super(Pkcs, self).__init__(
|
||||||
module.params['path'],
|
module.params['path'],
|
||||||
module.params['state'],
|
module.params['state'],
|
||||||
module.params['force'],
|
module.params['force'],
|
||||||
module.check_mode
|
module.check_mode
|
||||||
)
|
)
|
||||||
|
self.backend = backend
|
||||||
self.action = module.params['action']
|
self.action = module.params['action']
|
||||||
self.other_certificates = module.params['other_certificates']
|
self.other_certificates = module.params['other_certificates']
|
||||||
self.other_certificates_parse_all = module.params['other_certificates_parse_all']
|
self.other_certificates_parse_all = module.params['other_certificates_parse_all']
|
||||||
self.certificate_path = module.params['certificate_path']
|
self.certificate_path = module.params['certificate_path']
|
||||||
self.friendly_name = module.params['friendly_name']
|
self.friendly_name = module.params['friendly_name']
|
||||||
self.iter_size = module.params['iter_size']
|
self.iter_size = module.params['iter_size'] or 2048
|
||||||
self.maciter_size = module.params['maciter_size']
|
self.maciter_size = module.params['maciter_size'] or 1
|
||||||
self.passphrase = module.params['passphrase']
|
self.passphrase = module.params['passphrase']
|
||||||
self.pkcs12 = None
|
self.pkcs12 = None
|
||||||
self.privatekey_passphrase = module.params['privatekey_passphrase']
|
self.privatekey_passphrase = module.params['privatekey_passphrase']
|
||||||
|
@ -293,12 +343,37 @@ class Pkcs(OpenSSLObject):
|
||||||
filenames = list(self.other_certificates)
|
filenames = list(self.other_certificates)
|
||||||
self.other_certificates = []
|
self.other_certificates = []
|
||||||
for other_cert_bundle in filenames:
|
for other_cert_bundle in filenames:
|
||||||
self.other_certificates.extend(load_certificate_set(other_cert_bundle))
|
self.other_certificates.extend(load_certificate_set(other_cert_bundle, self.backend))
|
||||||
else:
|
else:
|
||||||
self.other_certificates = [
|
self.other_certificates = [
|
||||||
load_certificate(other_cert) for other_cert in self.other_certificates
|
load_certificate(other_cert, backend=self.backend) for other_cert in self.other_certificates
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def generate_bytes(self, module):
|
||||||
|
"""Generate PKCS#12 file archive."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def parse_bytes(self, pkcs12_content):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def _dump_privatekey(self, pkcs12):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def _dump_certificate(self, pkcs12):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def _dump_other_certificates(self, pkcs12):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def _get_friendly_name(self, pkcs12):
|
||||||
|
pass
|
||||||
|
|
||||||
def check(self, module, perms_required=True):
|
def check(self, module, perms_required=True):
|
||||||
"""Ensure the resource is in its desired state."""
|
"""Ensure the resource is in its desired state."""
|
||||||
|
|
||||||
|
@ -307,10 +382,8 @@ class Pkcs(OpenSSLObject):
|
||||||
def _check_pkey_passphrase():
|
def _check_pkey_passphrase():
|
||||||
if self.privatekey_passphrase:
|
if self.privatekey_passphrase:
|
||||||
try:
|
try:
|
||||||
load_privatekey(self.privatekey_path, self.privatekey_passphrase)
|
load_privatekey(self.privatekey_path, self.privatekey_passphrase, backend=self.backend)
|
||||||
except crypto.Error:
|
except OpenSSLObjectError:
|
||||||
return False
|
|
||||||
except OpenSSLBadPassphraseError:
|
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -318,32 +391,28 @@ class Pkcs(OpenSSLObject):
|
||||||
return state_and_perms
|
return state_and_perms
|
||||||
|
|
||||||
if os.path.exists(self.path) and module.params['action'] == 'export':
|
if os.path.exists(self.path) and module.params['action'] == 'export':
|
||||||
dummy = self.generate(module)
|
dummy = self.generate_bytes(module)
|
||||||
self.src = self.path
|
self.src = self.path
|
||||||
try:
|
try:
|
||||||
pkcs12_privatekey, pkcs12_certificate, pkcs12_other_certificates, pkcs12_friendly_name = self.parse()
|
pkcs12_privatekey, pkcs12_certificate, pkcs12_other_certificates, pkcs12_friendly_name = self.parse()
|
||||||
except crypto.Error:
|
except OpenSSLObjectError:
|
||||||
return False
|
return False
|
||||||
if (pkcs12_privatekey is not None) and (self.privatekey_path is not None):
|
if (pkcs12_privatekey is not None) and (self.privatekey_path is not None):
|
||||||
expected_pkey = crypto.dump_privatekey(crypto.FILETYPE_PEM,
|
expected_pkey = self._dump_privatekey(self.pkcs12)
|
||||||
self.pkcs12.get_privatekey())
|
|
||||||
if pkcs12_privatekey != expected_pkey:
|
if pkcs12_privatekey != expected_pkey:
|
||||||
return False
|
return False
|
||||||
elif bool(pkcs12_privatekey) != bool(self.privatekey_path):
|
elif bool(pkcs12_privatekey) != bool(self.privatekey_path):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if (pkcs12_certificate is not None) and (self.certificate_path is not None):
|
if (pkcs12_certificate is not None) and (self.certificate_path is not None):
|
||||||
|
expected_cert = self._dump_certificate(self.pkcs12)
|
||||||
expected_cert = crypto.dump_certificate(crypto.FILETYPE_PEM,
|
|
||||||
self.pkcs12.get_certificate())
|
|
||||||
if pkcs12_certificate != expected_cert:
|
if pkcs12_certificate != expected_cert:
|
||||||
return False
|
return False
|
||||||
elif bool(pkcs12_certificate) != bool(self.certificate_path):
|
elif bool(pkcs12_certificate) != bool(self.certificate_path):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if (pkcs12_other_certificates is not None) and (self.other_certificates is not None):
|
if (pkcs12_other_certificates is not None) and (self.other_certificates is not None):
|
||||||
expected_other_certs = [crypto.dump_certificate(crypto.FILETYPE_PEM,
|
expected_other_certs = self._dump_other_certificates(self.pkcs12)
|
||||||
other_cert) for other_cert in self.pkcs12.get_ca_certificates()]
|
|
||||||
if set(pkcs12_other_certificates) != set(expected_other_certs):
|
if set(pkcs12_other_certificates) != set(expected_other_certs):
|
||||||
return False
|
return False
|
||||||
elif bool(pkcs12_other_certificates) != bool(self.other_certificates):
|
elif bool(pkcs12_other_certificates) != bool(self.other_certificates):
|
||||||
|
@ -352,15 +421,16 @@ class Pkcs(OpenSSLObject):
|
||||||
if pkcs12_privatekey:
|
if pkcs12_privatekey:
|
||||||
# This check is required because pyOpenSSL will not return a friendly name
|
# This check is required because pyOpenSSL will not return a friendly name
|
||||||
# if the private key is not set in the file
|
# if the private key is not set in the file
|
||||||
if ((self.pkcs12.get_friendlyname() is not None) and (pkcs12_friendly_name is not None)):
|
friendly_name = self._get_friendly_name(self.pkcs12)
|
||||||
if self.pkcs12.get_friendlyname() != pkcs12_friendly_name:
|
if ((friendly_name is not None) and (pkcs12_friendly_name is not None)):
|
||||||
|
if friendly_name != pkcs12_friendly_name:
|
||||||
return False
|
return False
|
||||||
elif bool(self.pkcs12.get_friendlyname()) != bool(pkcs12_friendly_name):
|
elif bool(friendly_name) != bool(pkcs12_friendly_name):
|
||||||
return False
|
return False
|
||||||
elif module.params['action'] == 'parse' and os.path.exists(self.src) and os.path.exists(self.path):
|
elif module.params['action'] == 'parse' and os.path.exists(self.src) and os.path.exists(self.path):
|
||||||
try:
|
try:
|
||||||
pkey, cert, other_certs, friendly_name = self.parse()
|
pkey, cert, other_certs, friendly_name = self.parse()
|
||||||
except crypto.Error:
|
except OpenSSLObjectError:
|
||||||
return False
|
return False
|
||||||
expected_content = to_bytes(
|
expected_content = to_bytes(
|
||||||
''.join([to_native(pem) for pem in [pkey, cert] + other_certs if pem is not None])
|
''.join([to_native(pem) for pem in [pkey, cert] + other_certs if pem is not None])
|
||||||
|
@ -390,27 +460,6 @@ class Pkcs(OpenSSLObject):
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def generate(self, module):
|
|
||||||
"""Generate PKCS#12 file archive."""
|
|
||||||
self.pkcs12 = crypto.PKCS12()
|
|
||||||
|
|
||||||
if self.other_certificates:
|
|
||||||
self.pkcs12.set_ca_certificates(self.other_certificates)
|
|
||||||
|
|
||||||
if self.certificate_path:
|
|
||||||
self.pkcs12.set_certificate(load_certificate(self.certificate_path))
|
|
||||||
|
|
||||||
if self.friendly_name:
|
|
||||||
self.pkcs12.set_friendlyname(to_bytes(self.friendly_name))
|
|
||||||
|
|
||||||
if self.privatekey_path:
|
|
||||||
try:
|
|
||||||
self.pkcs12.set_privatekey(load_privatekey(self.privatekey_path, self.privatekey_passphrase))
|
|
||||||
except OpenSSLBadPassphraseError as exc:
|
|
||||||
raise PkcsError(exc)
|
|
||||||
|
|
||||||
return self.pkcs12.export(self.passphrase, self.iter_size, self.maciter_size)
|
|
||||||
|
|
||||||
def remove(self, module):
|
def remove(self, module):
|
||||||
if self.backup:
|
if self.backup:
|
||||||
self.backup_file = module.backup_local(self.path)
|
self.backup_file = module.backup_local(self.path)
|
||||||
|
@ -422,8 +471,51 @@ class Pkcs(OpenSSLObject):
|
||||||
try:
|
try:
|
||||||
with open(self.src, 'rb') as pkcs12_fh:
|
with open(self.src, 'rb') as pkcs12_fh:
|
||||||
pkcs12_content = pkcs12_fh.read()
|
pkcs12_content = pkcs12_fh.read()
|
||||||
p12 = crypto.load_pkcs12(pkcs12_content,
|
return self.parse_bytes(pkcs12_content)
|
||||||
self.passphrase)
|
except IOError as exc:
|
||||||
|
raise PkcsError(exc)
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def write(self, module, content, mode=None):
|
||||||
|
"""Write the PKCS#12 file."""
|
||||||
|
if self.backup:
|
||||||
|
self.backup_file = module.backup_local(self.path)
|
||||||
|
write_file(module, content, mode)
|
||||||
|
if self.return_content:
|
||||||
|
self.pkcs12_bytes = content
|
||||||
|
|
||||||
|
|
||||||
|
class PkcsPyOpenSSL(Pkcs):
|
||||||
|
def __init__(self, module):
|
||||||
|
super(PkcsPyOpenSSL, self).__init__(module, 'pyopenssl')
|
||||||
|
|
||||||
|
def generate_bytes(self, module):
|
||||||
|
"""Generate PKCS#12 file archive."""
|
||||||
|
self.pkcs12 = crypto.PKCS12()
|
||||||
|
|
||||||
|
if self.other_certificates:
|
||||||
|
self.pkcs12.set_ca_certificates(self.other_certificates)
|
||||||
|
|
||||||
|
if self.certificate_path:
|
||||||
|
self.pkcs12.set_certificate(load_certificate(self.certificate_path, backend=self.backend))
|
||||||
|
|
||||||
|
if self.friendly_name:
|
||||||
|
self.pkcs12.set_friendlyname(to_bytes(self.friendly_name))
|
||||||
|
|
||||||
|
if self.privatekey_path:
|
||||||
|
try:
|
||||||
|
self.pkcs12.set_privatekey(
|
||||||
|
load_privatekey(self.privatekey_path, self.privatekey_passphrase, backend=self.backend))
|
||||||
|
except OpenSSLBadPassphraseError as exc:
|
||||||
|
raise PkcsError(exc)
|
||||||
|
|
||||||
|
return self.pkcs12.export(self.passphrase, self.iter_size, self.maciter_size)
|
||||||
|
|
||||||
|
def parse_bytes(self, pkcs12_content):
|
||||||
|
try:
|
||||||
|
p12 = crypto.load_pkcs12(pkcs12_content, self.passphrase)
|
||||||
pkey = p12.get_privatekey()
|
pkey = p12.get_privatekey()
|
||||||
if pkey is not None:
|
if pkey is not None:
|
||||||
pkey = crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey)
|
pkey = crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey)
|
||||||
|
@ -438,17 +530,143 @@ class Pkcs(OpenSSLObject):
|
||||||
friendly_name = p12.get_friendlyname()
|
friendly_name = p12.get_friendlyname()
|
||||||
|
|
||||||
return (pkey, crt, other_certs, friendly_name)
|
return (pkey, crt, other_certs, friendly_name)
|
||||||
|
except crypto.Error as exc:
|
||||||
except IOError as exc:
|
|
||||||
raise PkcsError(exc)
|
raise PkcsError(exc)
|
||||||
|
|
||||||
def write(self, module, content, mode=None):
|
def _dump_privatekey(self, pkcs12):
|
||||||
"""Write the PKCS#12 file."""
|
pk = pkcs12.get_privatekey()
|
||||||
if self.backup:
|
return crypto.dump_privatekey(crypto.FILETYPE_PEM, pk) if pk else None
|
||||||
self.backup_file = module.backup_local(self.path)
|
|
||||||
write_file(module, content, mode)
|
def _dump_certificate(self, pkcs12):
|
||||||
if self.return_content:
|
cert = pkcs12.get_certificate()
|
||||||
self.pkcs12_bytes = content
|
return crypto.dump_certificate(crypto.FILETYPE_PEM, cert) if cert else None
|
||||||
|
|
||||||
|
def _dump_other_certificates(self, pkcs12):
|
||||||
|
return [
|
||||||
|
crypto.dump_certificate(crypto.FILETYPE_PEM, other_cert)
|
||||||
|
for other_cert in pkcs12.get_ca_certificates()
|
||||||
|
]
|
||||||
|
|
||||||
|
def _get_friendly_name(self, pkcs12):
|
||||||
|
return pkcs12.get_friendlyname()
|
||||||
|
|
||||||
|
|
||||||
|
class PkcsCryptography(Pkcs):
|
||||||
|
def __init__(self, module):
|
||||||
|
super(PkcsCryptography, self).__init__(module, 'cryptography')
|
||||||
|
|
||||||
|
def generate_bytes(self, module):
|
||||||
|
"""Generate PKCS#12 file archive."""
|
||||||
|
pkey = None
|
||||||
|
if self.privatekey_path:
|
||||||
|
try:
|
||||||
|
pkey = load_privatekey(self.privatekey_path, self.privatekey_passphrase, backend=self.backend)
|
||||||
|
except OpenSSLBadPassphraseError as exc:
|
||||||
|
raise PkcsError(exc)
|
||||||
|
|
||||||
|
cert = None
|
||||||
|
if self.certificate_path:
|
||||||
|
cert = load_certificate(self.certificate_path, backend=self.backend)
|
||||||
|
|
||||||
|
friendly_name = to_bytes(self.friendly_name) if self.friendly_name is not None else None
|
||||||
|
|
||||||
|
# Store fake object which can be used to retrieve the components back
|
||||||
|
self.pkcs12 = (pkey, cert, self.other_certificates, friendly_name)
|
||||||
|
|
||||||
|
return serialize_key_and_certificates(
|
||||||
|
friendly_name,
|
||||||
|
pkey,
|
||||||
|
cert,
|
||||||
|
self.other_certificates,
|
||||||
|
serialization.BestAvailableEncryption(to_bytes(self.passphrase))
|
||||||
|
if self.passphrase else serialization.NoEncryption(),
|
||||||
|
)
|
||||||
|
|
||||||
|
def parse_bytes(self, pkcs12_content):
|
||||||
|
try:
|
||||||
|
private_key, certificate, additional_certificates, friendly_name = parse_pkcs12(
|
||||||
|
pkcs12_content, self.passphrase)
|
||||||
|
|
||||||
|
pkey = None
|
||||||
|
if private_key is not None:
|
||||||
|
pkey = private_key.private_bytes(
|
||||||
|
encoding=serialization.Encoding.PEM,
|
||||||
|
format=serialization.PrivateFormat.TraditionalOpenSSL,
|
||||||
|
encryption_algorithm=serialization.NoEncryption(),
|
||||||
|
)
|
||||||
|
|
||||||
|
crt = None
|
||||||
|
if certificate is not None:
|
||||||
|
crt = certificate.public_bytes(serialization.Encoding.PEM)
|
||||||
|
|
||||||
|
other_certs = []
|
||||||
|
if additional_certificates is not None:
|
||||||
|
other_certs = [
|
||||||
|
other_cert.public_bytes(serialization.Encoding.PEM)
|
||||||
|
for other_cert in additional_certificates
|
||||||
|
]
|
||||||
|
|
||||||
|
return (pkey, crt, other_certs, friendly_name)
|
||||||
|
except ValueError as exc:
|
||||||
|
raise PkcsError(exc)
|
||||||
|
|
||||||
|
# The following methods will get self.pkcs12 passed, which is computed as:
|
||||||
|
#
|
||||||
|
# self.pkcs12 = (pkey, cert, self.other_certificates, self.friendly_name)
|
||||||
|
|
||||||
|
def _dump_privatekey(self, pkcs12):
|
||||||
|
return pkcs12[0].private_bytes(
|
||||||
|
encoding=serialization.Encoding.PEM,
|
||||||
|
format=serialization.PrivateFormat.TraditionalOpenSSL,
|
||||||
|
encryption_algorithm=serialization.NoEncryption(),
|
||||||
|
) if pkcs12[0] else None
|
||||||
|
|
||||||
|
def _dump_certificate(self, pkcs12):
|
||||||
|
return pkcs12[1].public_bytes(serialization.Encoding.PEM) if pkcs12[1] else None
|
||||||
|
|
||||||
|
def _dump_other_certificates(self, pkcs12):
|
||||||
|
return [other_cert.public_bytes(serialization.Encoding.PEM) for other_cert in pkcs12[2]]
|
||||||
|
|
||||||
|
def _get_friendly_name(self, pkcs12):
|
||||||
|
return pkcs12[3]
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
# If no restrictions are provided, first try cryptography, then pyOpenSSL
|
||||||
|
if module.params['iter_size'] is not None or module.params['maciter_size'] is not None:
|
||||||
|
# If iter_size or maciter_size is specified, use pyOpenSSL backend
|
||||||
|
backend = 'pyopenssl'
|
||||||
|
elif 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))
|
||||||
|
|
||||||
|
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='x.0.0', collection_name='community.crypto')
|
||||||
|
return backend, PkcsPyOpenSSL(module)
|
||||||
|
elif backend == 'cryptography':
|
||||||
|
if not CRYPTOGRAPHY_FOUND:
|
||||||
|
module.fail_json(msg=missing_required_lib('cryptography >= {0}'.format(MINIMAL_CRYPTOGRAPHY_VERSION)),
|
||||||
|
exception=CRYPTOGRAPHY_IMP_ERR)
|
||||||
|
return backend, PkcsCryptography(module)
|
||||||
|
else:
|
||||||
|
raise ValueError('Unsupported value for backend: {0}'.format(backend))
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
@ -459,8 +677,8 @@ def main():
|
||||||
certificate_path=dict(type='path'),
|
certificate_path=dict(type='path'),
|
||||||
force=dict(type='bool', default=False),
|
force=dict(type='bool', default=False),
|
||||||
friendly_name=dict(type='str', aliases=['name']),
|
friendly_name=dict(type='str', aliases=['name']),
|
||||||
iter_size=dict(type='int', default=2048),
|
iter_size=dict(type='int'),
|
||||||
maciter_size=dict(type='int', default=1),
|
maciter_size=dict(type='int'),
|
||||||
passphrase=dict(type='str', no_log=True),
|
passphrase=dict(type='str', no_log=True),
|
||||||
path=dict(type='path', required=True),
|
path=dict(type='path', required=True),
|
||||||
privatekey_passphrase=dict(type='str', no_log=True),
|
privatekey_passphrase=dict(type='str', no_log=True),
|
||||||
|
@ -469,6 +687,7 @@ def main():
|
||||||
src=dict(type='path'),
|
src=dict(type='path'),
|
||||||
backup=dict(type='bool', default=False),
|
backup=dict(type='bool', default=False),
|
||||||
return_content=dict(type='bool', default=False),
|
return_content=dict(type='bool', default=False),
|
||||||
|
select_crypto_backend=dict(type='str', default='auto', choices=['auto', 'cryptography', 'pyopenssl']),
|
||||||
)
|
)
|
||||||
|
|
||||||
required_if = [
|
required_if = [
|
||||||
|
@ -482,8 +701,7 @@ def main():
|
||||||
supports_check_mode=True,
|
supports_check_mode=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
if not pyopenssl_found:
|
backend, pkcs12 = select_backend(module, module.params['select_crypto_backend'])
|
||||||
module.fail_json(msg=missing_required_lib('pyOpenSSL'), exception=PYOPENSSL_IMP_ERR)
|
|
||||||
|
|
||||||
base_dir = os.path.dirname(module.params['path']) or '.'
|
base_dir = os.path.dirname(module.params['path']) or '.'
|
||||||
if not os.path.isdir(base_dir):
|
if not os.path.isdir(base_dir):
|
||||||
|
@ -493,7 +711,6 @@ def main():
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
pkcs12 = Pkcs(module)
|
|
||||||
changed = False
|
changed = False
|
||||||
|
|
||||||
if module.params['state'] == 'present':
|
if module.params['state'] == 'present':
|
||||||
|
@ -506,7 +723,7 @@ def main():
|
||||||
if module.params['action'] == 'export':
|
if module.params['action'] == 'export':
|
||||||
if not module.params['friendly_name']:
|
if not module.params['friendly_name']:
|
||||||
module.fail_json(msg='Friendly_name is required')
|
module.fail_json(msg='Friendly_name is required')
|
||||||
pkcs12_content = pkcs12.generate(module)
|
pkcs12_content = pkcs12.generate_bytes(module)
|
||||||
pkcs12.write(module, pkcs12_content, 0o600)
|
pkcs12.write(module, pkcs12_content, 0o600)
|
||||||
changed = True
|
changed = True
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -1,246 +1,237 @@
|
||||||
- block:
|
- block:
|
||||||
- name: Generate privatekey
|
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file"
|
||||||
openssl_privatekey:
|
|
||||||
path: '{{ output_dir }}/ansible_pkey.pem'
|
|
||||||
size: '{{ default_rsa_key_size_certifiates }}'
|
|
||||||
- name: Generate privatekey2
|
|
||||||
openssl_privatekey:
|
|
||||||
path: '{{ output_dir }}/ansible_pkey2.pem'
|
|
||||||
size: '{{ default_rsa_key_size_certifiates }}'
|
|
||||||
- name: Generate privatekey3
|
|
||||||
openssl_privatekey:
|
|
||||||
path: '{{ output_dir }}/ansible_pkey3.pem'
|
|
||||||
size: '{{ default_rsa_key_size_certifiates }}'
|
|
||||||
- name: Generate CSR
|
|
||||||
openssl_csr:
|
|
||||||
path: '{{ output_dir }}/ansible.csr'
|
|
||||||
privatekey_path: '{{ output_dir }}/ansible_pkey.pem'
|
|
||||||
commonName: www.ansible.com
|
|
||||||
- name: Generate CSR 2
|
|
||||||
openssl_csr:
|
|
||||||
path: '{{ output_dir }}/ansible2.csr'
|
|
||||||
privatekey_path: '{{ output_dir }}/ansible_pkey2.pem'
|
|
||||||
commonName: www2.ansible.com
|
|
||||||
- name: Generate CSR 3
|
|
||||||
openssl_csr:
|
|
||||||
path: '{{ output_dir }}/ansible3.csr'
|
|
||||||
privatekey_path: '{{ output_dir }}/ansible_pkey3.pem'
|
|
||||||
commonName: www3.ansible.com
|
|
||||||
- name: Generate certificate
|
|
||||||
x509_certificate:
|
|
||||||
path: '{{ output_dir }}/{{ item.name }}.crt'
|
|
||||||
privatekey_path: '{{ output_dir }}/{{ item.pkey }}'
|
|
||||||
csr_path: '{{ output_dir }}/{{ item.name }}.csr'
|
|
||||||
provider: selfsigned
|
|
||||||
loop:
|
|
||||||
- name: ansible
|
|
||||||
pkey: ansible_pkey.pem
|
|
||||||
- name: ansible2
|
|
||||||
pkey: ansible_pkey2.pem
|
|
||||||
- name: ansible3
|
|
||||||
pkey: ansible_pkey3.pem
|
|
||||||
- name: Generate concatenated PEM file
|
|
||||||
copy:
|
|
||||||
dest: '{{ output_dir }}/ansible23.crt'
|
|
||||||
content: |
|
|
||||||
{{ lookup("file", output_dir ~ "/ansible2.crt") }}
|
|
||||||
{{ lookup("file", output_dir ~ "/ansible3.crt") }}
|
|
||||||
- name: Generate PKCS#12 file
|
|
||||||
openssl_pkcs12:
|
openssl_pkcs12:
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
path: '{{ output_dir }}/ansible.p12'
|
path: '{{ output_dir }}/ansible.p12'
|
||||||
friendly_name: abracadabra
|
friendly_name: abracadabra
|
||||||
privatekey_path: '{{ output_dir }}/ansible_pkey.pem'
|
privatekey_path: '{{ output_dir }}/ansible_pkey1.pem'
|
||||||
certificate_path: '{{ output_dir }}/ansible.crt'
|
certificate_path: '{{ output_dir }}/ansible1.crt'
|
||||||
state: present
|
state: present
|
||||||
return_content: true
|
return_content: true
|
||||||
register: p12_standard
|
register: p12_standard
|
||||||
- name: Generate PKCS#12 file again, idempotency
|
|
||||||
|
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file again, idempotency"
|
||||||
openssl_pkcs12:
|
openssl_pkcs12:
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
path: '{{ output_dir }}/ansible.p12'
|
path: '{{ output_dir }}/ansible.p12'
|
||||||
friendly_name: abracadabra
|
friendly_name: abracadabra
|
||||||
privatekey_path: '{{ output_dir }}/ansible_pkey.pem'
|
privatekey_path: '{{ output_dir }}/ansible_pkey1.pem'
|
||||||
certificate_path: '{{ output_dir }}/ansible.crt'
|
certificate_path: '{{ output_dir }}/ansible1.crt'
|
||||||
state: present
|
state: present
|
||||||
return_content: true
|
return_content: true
|
||||||
register: p12_standard_idempotency
|
register: p12_standard_idempotency
|
||||||
- name: Read ansible.p12
|
|
||||||
|
- name: "({{ select_crypto_backend }}) Read ansible.p12"
|
||||||
slurp:
|
slurp:
|
||||||
src: '{{ output_dir }}/ansible.p12'
|
src: '{{ output_dir }}/ansible.p12'
|
||||||
register: ansible_p12_content
|
register: ansible_p12_content
|
||||||
- name: Validate PKCS#12
|
|
||||||
|
- name: "({{ select_crypto_backend }}) Validate PKCS#12"
|
||||||
assert:
|
assert:
|
||||||
that:
|
that:
|
||||||
- p12_standard.pkcs12 == ansible_p12_content.content
|
- p12_standard.pkcs12 == ansible_p12_content.content
|
||||||
- p12_standard_idempotency.pkcs12 == p12_standard.pkcs12
|
- p12_standard_idempotency.pkcs12 == p12_standard.pkcs12
|
||||||
- name: Generate PKCS#12 file (force)
|
|
||||||
|
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file (force)"
|
||||||
openssl_pkcs12:
|
openssl_pkcs12:
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
path: '{{ output_dir }}/ansible.p12'
|
path: '{{ output_dir }}/ansible.p12'
|
||||||
friendly_name: abracadabra
|
friendly_name: abracadabra
|
||||||
privatekey_path: '{{ output_dir }}/ansible_pkey.pem'
|
privatekey_path: '{{ output_dir }}/ansible_pkey1.pem'
|
||||||
certificate_path: '{{ output_dir }}/ansible.crt'
|
certificate_path: '{{ output_dir }}/ansible1.crt'
|
||||||
state: present
|
state: present
|
||||||
force: true
|
force: true
|
||||||
register: p12_force
|
register: p12_force
|
||||||
- name: Generate PKCS#12 file (force + change mode)
|
|
||||||
|
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file (force + change mode)"
|
||||||
openssl_pkcs12:
|
openssl_pkcs12:
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
path: '{{ output_dir }}/ansible.p12'
|
path: '{{ output_dir }}/ansible.p12'
|
||||||
friendly_name: abracadabra
|
friendly_name: abracadabra
|
||||||
privatekey_path: '{{ output_dir }}/ansible_pkey.pem'
|
privatekey_path: '{{ output_dir }}/ansible_pkey1.pem'
|
||||||
certificate_path: '{{ output_dir }}/ansible.crt'
|
certificate_path: '{{ output_dir }}/ansible1.crt'
|
||||||
state: present
|
state: present
|
||||||
force: true
|
force: true
|
||||||
mode: '0644'
|
mode: '0644'
|
||||||
register: p12_force_and_mode
|
register: p12_force_and_mode
|
||||||
- name: Dump PKCS#12
|
|
||||||
|
- name: "({{ select_crypto_backend }}) Dump PKCS#12"
|
||||||
openssl_pkcs12:
|
openssl_pkcs12:
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
src: '{{ output_dir }}/ansible.p12'
|
src: '{{ output_dir }}/ansible.p12'
|
||||||
path: '{{ output_dir }}/ansible_parse.pem'
|
path: '{{ output_dir }}/ansible_parse.pem'
|
||||||
action: parse
|
action: parse
|
||||||
state: present
|
state: present
|
||||||
register: p12_dumped
|
register: p12_dumped
|
||||||
- name: Dump PKCS#12 file again, idempotency
|
|
||||||
|
- name: "({{ select_crypto_backend }}) Dump PKCS#12 file again, idempotency"
|
||||||
openssl_pkcs12:
|
openssl_pkcs12:
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
src: '{{ output_dir }}/ansible.p12'
|
src: '{{ output_dir }}/ansible.p12'
|
||||||
path: '{{ output_dir }}/ansible_parse.pem'
|
path: '{{ output_dir }}/ansible_parse.pem'
|
||||||
action: parse
|
action: parse
|
||||||
state: present
|
state: present
|
||||||
register: p12_dumped_idempotency
|
register: p12_dumped_idempotency
|
||||||
- name: Dump PKCS#12, check mode
|
|
||||||
|
- name: "({{ select_crypto_backend }}) Dump PKCS#12, check mode"
|
||||||
openssl_pkcs12:
|
openssl_pkcs12:
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
src: '{{ output_dir }}/ansible.p12'
|
src: '{{ output_dir }}/ansible.p12'
|
||||||
path: '{{ output_dir }}/ansible_parse.pem'
|
path: '{{ output_dir }}/ansible_parse.pem'
|
||||||
action: parse
|
action: parse
|
||||||
state: present
|
state: present
|
||||||
check_mode: true
|
check_mode: true
|
||||||
register: p12_dumped_check_mode
|
register: p12_dumped_check_mode
|
||||||
- name: Generate PKCS#12 file with multiple certs
|
|
||||||
|
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file with multiple certs"
|
||||||
openssl_pkcs12:
|
openssl_pkcs12:
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
path: '{{ output_dir }}/ansible_multi_certs.p12'
|
path: '{{ output_dir }}/ansible_multi_certs.p12'
|
||||||
friendly_name: abracadabra
|
friendly_name: abracadabra
|
||||||
privatekey_path: '{{ output_dir }}/ansible_pkey.pem'
|
privatekey_path: '{{ output_dir }}/ansible_pkey1.pem'
|
||||||
certificate_path: '{{ output_dir }}/ansible.crt'
|
certificate_path: '{{ output_dir }}/ansible1.crt'
|
||||||
other_certificates:
|
other_certificates:
|
||||||
- '{{ output_dir }}/ansible2.crt'
|
- '{{ output_dir }}/ansible2.crt'
|
||||||
- '{{ output_dir }}/ansible3.crt'
|
- '{{ output_dir }}/ansible3.crt'
|
||||||
state: present
|
state: present
|
||||||
register: p12_multiple_certs
|
register: p12_multiple_certs
|
||||||
- name: Generate PKCS#12 file with multiple certs, again (idempotency)
|
|
||||||
|
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file with multiple certs, again (idempotency)"
|
||||||
openssl_pkcs12:
|
openssl_pkcs12:
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
path: '{{ output_dir }}/ansible_multi_certs.p12'
|
path: '{{ output_dir }}/ansible_multi_certs.p12'
|
||||||
friendly_name: abracadabra
|
friendly_name: abracadabra
|
||||||
privatekey_path: '{{ output_dir }}/ansible_pkey.pem'
|
privatekey_path: '{{ output_dir }}/ansible_pkey1.pem'
|
||||||
certificate_path: '{{ output_dir }}/ansible.crt'
|
certificate_path: '{{ output_dir }}/ansible1.crt'
|
||||||
other_certificates:
|
other_certificates:
|
||||||
- '{{ output_dir }}/ansible2.crt'
|
- '{{ output_dir }}/ansible2.crt'
|
||||||
- '{{ output_dir }}/ansible3.crt'
|
- '{{ output_dir }}/ansible3.crt'
|
||||||
state: present
|
state: present
|
||||||
register: p12_multiple_certs_idempotency
|
register: p12_multiple_certs_idempotency
|
||||||
- name: Dump PKCS#12 with multiple certs
|
|
||||||
|
- name: "({{ select_crypto_backend }}) Dump PKCS#12 with multiple certs"
|
||||||
openssl_pkcs12:
|
openssl_pkcs12:
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
src: '{{ output_dir }}/ansible_multi_certs.p12'
|
src: '{{ output_dir }}/ansible_multi_certs.p12'
|
||||||
path: '{{ output_dir }}/ansible_parse_multi_certs.pem'
|
path: '{{ output_dir }}/ansible_parse_multi_certs.pem'
|
||||||
action: parse
|
action: parse
|
||||||
state: present
|
state: present
|
||||||
- name: Generate privatekey with password
|
|
||||||
openssl_privatekey:
|
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file (password fail 1)"
|
||||||
path: '{{ output_dir }}/privatekeypw.pem'
|
|
||||||
passphrase: hunter2
|
|
||||||
cipher: auto
|
|
||||||
size: '{{ default_rsa_key_size }}'
|
|
||||||
select_crypto_backend: cryptography
|
|
||||||
- name: Generate PKCS#12 file (password fail 1)
|
|
||||||
openssl_pkcs12:
|
openssl_pkcs12:
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
path: '{{ output_dir }}/ansible_pw1.p12'
|
path: '{{ output_dir }}/ansible_pw1.p12'
|
||||||
friendly_name: abracadabra
|
friendly_name: abracadabra
|
||||||
privatekey_path: '{{ output_dir }}/ansible_pkey.pem'
|
privatekey_path: '{{ output_dir }}/ansible_pkey1.pem'
|
||||||
privatekey_passphrase: hunter2
|
privatekey_passphrase: hunter2
|
||||||
certificate_path: '{{ output_dir }}/ansible.crt'
|
certificate_path: '{{ output_dir }}/ansible1.crt'
|
||||||
state: present
|
state: present
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
register: passphrase_error_1
|
register: passphrase_error_1
|
||||||
- name: Generate PKCS#12 file (password fail 2)
|
|
||||||
|
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file (password fail 2)"
|
||||||
openssl_pkcs12:
|
openssl_pkcs12:
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
path: '{{ output_dir }}/ansible_pw2.p12'
|
path: '{{ output_dir }}/ansible_pw2.p12'
|
||||||
friendly_name: abracadabra
|
friendly_name: abracadabra
|
||||||
privatekey_path: '{{ output_dir }}/privatekeypw.pem'
|
privatekey_path: '{{ output_dir }}/privatekeypw.pem'
|
||||||
privatekey_passphrase: wrong_password
|
privatekey_passphrase: wrong_password
|
||||||
certificate_path: '{{ output_dir }}/ansible.crt'
|
certificate_path: '{{ output_dir }}/ansible1.crt'
|
||||||
state: present
|
state: present
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
register: passphrase_error_2
|
register: passphrase_error_2
|
||||||
- name: Generate PKCS#12 file (password fail 3)
|
|
||||||
|
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file (password fail 3)"
|
||||||
openssl_pkcs12:
|
openssl_pkcs12:
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
path: '{{ output_dir }}/ansible_pw3.p12'
|
path: '{{ output_dir }}/ansible_pw3.p12'
|
||||||
friendly_name: abracadabra
|
friendly_name: abracadabra
|
||||||
privatekey_path: '{{ output_dir }}/privatekeypw.pem'
|
privatekey_path: '{{ output_dir }}/privatekeypw.pem'
|
||||||
certificate_path: '{{ output_dir }}/ansible.crt'
|
certificate_path: '{{ output_dir }}/ansible1.crt'
|
||||||
state: present
|
state: present
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
register: passphrase_error_3
|
register: passphrase_error_3
|
||||||
- name: Generate PKCS#12 file, no privatekey
|
|
||||||
|
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file, no privatekey"
|
||||||
openssl_pkcs12:
|
openssl_pkcs12:
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
path: '{{ output_dir }}/ansible_no_pkey.p12'
|
path: '{{ output_dir }}/ansible_no_pkey.p12'
|
||||||
friendly_name: abracadabra
|
friendly_name: abracadabra
|
||||||
certificate_path: '{{ output_dir }}/ansible.crt'
|
certificate_path: '{{ output_dir }}/ansible1.crt'
|
||||||
state: present
|
state: present
|
||||||
register: p12_no_pkey
|
register: p12_no_pkey
|
||||||
- name: Create broken PKCS#12
|
|
||||||
|
- name: "({{ select_crypto_backend }}) Create broken PKCS#12"
|
||||||
copy:
|
copy:
|
||||||
dest: '{{ output_dir }}/broken.p12'
|
dest: '{{ output_dir }}/broken.p12'
|
||||||
content: broken
|
content: broken
|
||||||
- name: Regenerate broken PKCS#12
|
|
||||||
|
- name: "({{ select_crypto_backend }}) Regenerate broken PKCS#12"
|
||||||
openssl_pkcs12:
|
openssl_pkcs12:
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
path: '{{ output_dir }}/broken.p12'
|
path: '{{ output_dir }}/broken.p12'
|
||||||
friendly_name: abracadabra
|
friendly_name: abracadabra
|
||||||
privatekey_path: '{{ output_dir }}/ansible_pkey.pem'
|
privatekey_path: '{{ output_dir }}/ansible_pkey1.pem'
|
||||||
certificate_path: '{{ output_dir }}/ansible.crt'
|
certificate_path: '{{ output_dir }}/ansible1.crt'
|
||||||
state: present
|
state: present
|
||||||
force: true
|
force: true
|
||||||
mode: '0644'
|
mode: '0644'
|
||||||
register: output_broken
|
register: output_broken
|
||||||
- name: Generate PKCS#12 file
|
|
||||||
|
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file"
|
||||||
openssl_pkcs12:
|
openssl_pkcs12:
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
path: '{{ output_dir }}/ansible_backup.p12'
|
path: '{{ output_dir }}/ansible_backup.p12'
|
||||||
friendly_name: abracadabra
|
friendly_name: abracadabra
|
||||||
privatekey_path: '{{ output_dir }}/ansible_pkey.pem'
|
privatekey_path: '{{ output_dir }}/ansible_pkey1.pem'
|
||||||
certificate_path: '{{ output_dir }}/ansible.crt'
|
certificate_path: '{{ output_dir }}/ansible1.crt'
|
||||||
state: present
|
state: present
|
||||||
backup: true
|
backup: true
|
||||||
register: p12_backup_1
|
register: p12_backup_1
|
||||||
- name: Generate PKCS#12 file (idempotent)
|
|
||||||
|
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file (idempotent)"
|
||||||
openssl_pkcs12:
|
openssl_pkcs12:
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
path: '{{ output_dir }}/ansible_backup.p12'
|
path: '{{ output_dir }}/ansible_backup.p12'
|
||||||
friendly_name: abracadabra
|
friendly_name: abracadabra
|
||||||
privatekey_path: '{{ output_dir }}/ansible_pkey.pem'
|
privatekey_path: '{{ output_dir }}/ansible_pkey1.pem'
|
||||||
certificate_path: '{{ output_dir }}/ansible.crt'
|
certificate_path: '{{ output_dir }}/ansible1.crt'
|
||||||
state: present
|
state: present
|
||||||
backup: true
|
backup: true
|
||||||
register: p12_backup_2
|
register: p12_backup_2
|
||||||
- name: Generate PKCS#12 file (change)
|
|
||||||
|
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file (change)"
|
||||||
openssl_pkcs12:
|
openssl_pkcs12:
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
path: '{{ output_dir }}/ansible_backup.p12'
|
path: '{{ output_dir }}/ansible_backup.p12'
|
||||||
friendly_name: abra
|
friendly_name: abra
|
||||||
privatekey_path: '{{ output_dir }}/ansible_pkey.pem'
|
privatekey_path: '{{ output_dir }}/ansible_pkey1.pem'
|
||||||
certificate_path: '{{ output_dir }}/ansible.crt'
|
certificate_path: '{{ output_dir }}/ansible1.crt'
|
||||||
state: present
|
state: present
|
||||||
force: true
|
force: true
|
||||||
backup: true
|
backup: true
|
||||||
register: p12_backup_3
|
register: p12_backup_3
|
||||||
- name: Generate PKCS#12 file (remove)
|
|
||||||
|
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file (remove)"
|
||||||
openssl_pkcs12:
|
openssl_pkcs12:
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
path: '{{ output_dir }}/ansible_backup.p12'
|
path: '{{ output_dir }}/ansible_backup.p12'
|
||||||
state: absent
|
state: absent
|
||||||
backup: true
|
backup: true
|
||||||
return_content: true
|
return_content: true
|
||||||
register: p12_backup_4
|
register: p12_backup_4
|
||||||
- name: Generate PKCS#12 file (remove, idempotent)
|
|
||||||
|
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file (remove, idempotent)"
|
||||||
openssl_pkcs12:
|
openssl_pkcs12:
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
path: '{{ output_dir }}/ansible_backup.p12'
|
path: '{{ output_dir }}/ansible_backup.p12'
|
||||||
state: absent
|
state: absent
|
||||||
backup: true
|
backup: true
|
||||||
register: p12_backup_5
|
register: p12_backup_5
|
||||||
- name: Generate 'empty' PKCS#12 file
|
|
||||||
|
- name: "({{ select_crypto_backend }}) Generate 'empty' PKCS#12 file"
|
||||||
openssl_pkcs12:
|
openssl_pkcs12:
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
path: '{{ output_dir }}/ansible_empty.p12'
|
path: '{{ output_dir }}/ansible_empty.p12'
|
||||||
friendly_name: abracadabra
|
friendly_name: abracadabra
|
||||||
other_certificates:
|
other_certificates:
|
||||||
|
@ -248,8 +239,11 @@
|
||||||
- '{{ output_dir }}/ansible3.crt'
|
- '{{ output_dir }}/ansible3.crt'
|
||||||
state: present
|
state: present
|
||||||
register: p12_empty
|
register: p12_empty
|
||||||
- name: Generate 'empty' PKCS#12 file (idempotent)
|
|
||||||
|
|
||||||
|
- name: "({{ select_crypto_backend }}) Generate 'empty' PKCS#12 file (idempotent)"
|
||||||
openssl_pkcs12:
|
openssl_pkcs12:
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
path: '{{ output_dir }}/ansible_empty.p12'
|
path: '{{ output_dir }}/ansible_empty.p12'
|
||||||
friendly_name: abracadabra
|
friendly_name: abracadabra
|
||||||
other_certificates:
|
other_certificates:
|
||||||
|
@ -257,8 +251,10 @@
|
||||||
- '{{ output_dir }}/ansible2.crt'
|
- '{{ output_dir }}/ansible2.crt'
|
||||||
state: present
|
state: present
|
||||||
register: p12_empty_idem
|
register: p12_empty_idem
|
||||||
- name: Generate 'empty' PKCS#12 file (idempotent, concatenated other certificates)
|
|
||||||
|
- name: "({{ select_crypto_backend }}) Generate 'empty' PKCS#12 file (idempotent, concatenated other certificates)"
|
||||||
openssl_pkcs12:
|
openssl_pkcs12:
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
path: '{{ output_dir }}/ansible_empty.p12'
|
path: '{{ output_dir }}/ansible_empty.p12'
|
||||||
friendly_name: abracadabra
|
friendly_name: abracadabra
|
||||||
other_certificates:
|
other_certificates:
|
||||||
|
@ -266,14 +262,18 @@
|
||||||
other_certificates_parse_all: true
|
other_certificates_parse_all: true
|
||||||
state: present
|
state: present
|
||||||
register: p12_empty_concat_idem
|
register: p12_empty_concat_idem
|
||||||
- name: Generate 'empty' PKCS#12 file (parse)
|
|
||||||
|
- name: "({{ select_crypto_backend }}) Generate 'empty' PKCS#12 file (parse)"
|
||||||
openssl_pkcs12:
|
openssl_pkcs12:
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
src: '{{ output_dir }}/ansible_empty.p12'
|
src: '{{ output_dir }}/ansible_empty.p12'
|
||||||
path: '{{ output_dir }}/ansible_empty.pem'
|
path: '{{ output_dir }}/ansible_empty.pem'
|
||||||
action: parse
|
action: parse
|
||||||
|
|
||||||
- import_tasks: ../tests/validate.yml
|
- import_tasks: ../tests/validate.yml
|
||||||
|
|
||||||
always:
|
always:
|
||||||
- name: Delete PKCS#12 file
|
- name: "({{ select_crypto_backend }}) Delete PKCS#12 file"
|
||||||
openssl_pkcs12:
|
openssl_pkcs12:
|
||||||
state: absent
|
state: absent
|
||||||
path: '{{ output_dir }}/{{ item }}.p12'
|
path: '{{ output_dir }}/{{ item }}.p12'
|
||||||
|
|
|
@ -4,6 +4,69 @@
|
||||||
# and should not be used as examples of how to write Ansible roles #
|
# and should not be used as examples of how to write Ansible roles #
|
||||||
####################################################################
|
####################################################################
|
||||||
|
|
||||||
- name: Run tests
|
- block:
|
||||||
include_tasks: impl.yml
|
- name: Generate private keys
|
||||||
when: pyopenssl_version.stdout is version('17.1.0', '>=')
|
openssl_privatekey:
|
||||||
|
path: '{{ output_dir }}/ansible_pkey{{ item }}.pem'
|
||||||
|
size: '{{ default_rsa_key_size_certifiates }}'
|
||||||
|
loop: "{{ range(1, 4) | list }}"
|
||||||
|
|
||||||
|
- name: Generate privatekey with password
|
||||||
|
openssl_privatekey:
|
||||||
|
path: '{{ output_dir }}/privatekeypw.pem'
|
||||||
|
passphrase: hunter2
|
||||||
|
cipher: auto
|
||||||
|
size: '{{ default_rsa_key_size }}'
|
||||||
|
|
||||||
|
- name: Generate CSRs
|
||||||
|
openssl_csr:
|
||||||
|
path: '{{ output_dir }}/ansible{{ item }}.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/ansible_pkey{{ item }}.pem'
|
||||||
|
commonName: www{{ item }}.ansible.com
|
||||||
|
loop: "{{ range(1, 4) | list }}"
|
||||||
|
|
||||||
|
- name: Generate certificate
|
||||||
|
x509_certificate:
|
||||||
|
path: '{{ output_dir }}/ansible{{ item }}.crt'
|
||||||
|
privatekey_path: '{{ output_dir }}/ansible_pkey{{ item }}.pem'
|
||||||
|
csr_path: '{{ output_dir }}/ansible{{ item }}.csr'
|
||||||
|
provider: selfsigned
|
||||||
|
loop: "{{ range(1, 4) | list }}"
|
||||||
|
|
||||||
|
- name: Generate concatenated PEM file
|
||||||
|
copy:
|
||||||
|
dest: '{{ output_dir }}/ansible23.crt'
|
||||||
|
content: |
|
||||||
|
{{ lookup("file", output_dir ~ "/ansible2.crt") }}
|
||||||
|
{{ lookup("file", output_dir ~ "/ansible3.crt") }}
|
||||||
|
|
||||||
|
- name: Generate PKCS#12 file with backend autodetection
|
||||||
|
openssl_pkcs12:
|
||||||
|
path: '{{ output_dir }}/ansible.p12'
|
||||||
|
friendly_name: abracadabra
|
||||||
|
privatekey_path: '{{ output_dir }}/ansible_pkey1.pem'
|
||||||
|
certificate_path: '{{ output_dir }}/ansible1.crt'
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Delete result
|
||||||
|
file:
|
||||||
|
path: '{{ output_dir }}/ansible.p12'
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: Running tests with pyOpenSSL backend
|
||||||
|
include_tasks: impl.yml
|
||||||
|
vars:
|
||||||
|
select_crypto_backend: pyopenssl
|
||||||
|
|
||||||
|
when: pyopenssl_version.stdout is version('0.15', '>=')
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: Running tests with cryptography backend
|
||||||
|
include_tasks: impl.yml
|
||||||
|
vars:
|
||||||
|
select_crypto_backend: cryptography
|
||||||
|
|
||||||
|
when: cryptography_version.stdout is version('3.0', '>=')
|
||||||
|
|
||||||
|
when: pyopenssl_version.stdout is version('0.15', '>=') or cryptography_version.stdout is version('3.0', '>=')
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
---
|
---
|
||||||
- name: 'Validate PKCS#12'
|
- name: '({{ select_crypto_backend }}) Validate PKCS#12'
|
||||||
command: "{{ openssl_binary }} pkcs12 -info -in {{ output_dir }}/ansible.p12 -nodes -passin pass:''"
|
command: "{{ openssl_binary }} pkcs12 -info -in {{ output_dir }}/ansible.p12 -nodes -passin pass:''"
|
||||||
register: p12
|
register: p12
|
||||||
|
|
||||||
- name: 'Validate PKCS#12 with no private key'
|
- name: '({{ select_crypto_backend }}) Validate PKCS#12 with no private key'
|
||||||
command: "{{ openssl_binary }} pkcs12 -info -in {{ output_dir }}/ansible_no_pkey.p12 -nodes -passin pass:''"
|
command: "{{ openssl_binary }} pkcs12 -info -in {{ output_dir }}/ansible_no_pkey.p12 -nodes -passin pass:''"
|
||||||
register: p12_validate_no_pkey
|
register: p12_validate_no_pkey
|
||||||
|
|
||||||
- name: 'Validate PKCS#12 with multiple certs'
|
- name: '({{ select_crypto_backend }}) Validate PKCS#12 with multiple certs'
|
||||||
shell: "{{ openssl_binary }} pkcs12 -info -in {{ output_dir }}/ansible_multi_certs.p12 -nodes -passin pass:'' | grep subject"
|
shell: "{{ openssl_binary }} pkcs12 -info -in {{ output_dir }}/ansible_multi_certs.p12 -nodes -passin pass:'' | grep subject"
|
||||||
register: p12_validate_multi_certs
|
register: p12_validate_multi_certs
|
||||||
|
|
||||||
- name: 'Validate PKCS#12 (assert)'
|
- name: '({{ select_crypto_backend }}) Validate PKCS#12 (assert)'
|
||||||
assert:
|
assert:
|
||||||
that:
|
that:
|
||||||
- p12.stdout_lines[2].split(':')[-1].strip() == 'abracadabra'
|
- p12.stdout_lines[2].split(':')[-1].strip() == 'abracadabra'
|
||||||
|
@ -25,11 +25,11 @@
|
||||||
- not p12_multiple_certs_idempotency.changed
|
- not p12_multiple_certs_idempotency.changed
|
||||||
- not p12_dumped_idempotency.changed
|
- not p12_dumped_idempotency.changed
|
||||||
- not p12_dumped_check_mode.changed
|
- not p12_dumped_check_mode.changed
|
||||||
- "'www.' in p12_validate_multi_certs.stdout"
|
- "'www1.' in p12_validate_multi_certs.stdout"
|
||||||
- "'www2.' in p12_validate_multi_certs.stdout"
|
- "'www2.' in p12_validate_multi_certs.stdout"
|
||||||
- "'www3.' in p12_validate_multi_certs.stdout"
|
- "'www3.' in p12_validate_multi_certs.stdout"
|
||||||
|
|
||||||
- name: Check passphrase on private key
|
- name: '({{ select_crypto_backend }}) Check passphrase on private key'
|
||||||
assert:
|
assert:
|
||||||
that:
|
that:
|
||||||
- passphrase_error_1 is failed
|
- passphrase_error_1 is failed
|
||||||
|
@ -39,12 +39,12 @@
|
||||||
- passphrase_error_3 is failed
|
- passphrase_error_3 is failed
|
||||||
- "'assphrase' in passphrase_error_3.msg or 'assword' in passphrase_error_3.msg or 'serializ' in passphrase_error_3.msg"
|
- "'assphrase' in passphrase_error_3.msg or 'assword' in passphrase_error_3.msg or 'serializ' in passphrase_error_3.msg"
|
||||||
|
|
||||||
- name: "Verify that broken PKCS#12 will be regenerated"
|
- name: '({{ select_crypto_backend }}) Verify that broken PKCS#12 will be regenerated'
|
||||||
assert:
|
assert:
|
||||||
that:
|
that:
|
||||||
- output_broken is changed
|
- output_broken is changed
|
||||||
|
|
||||||
- name: Check backup
|
- name: '({{ select_crypto_backend }}) Check backup'
|
||||||
assert:
|
assert:
|
||||||
that:
|
that:
|
||||||
- p12_backup_1 is changed
|
- p12_backup_1 is changed
|
||||||
|
@ -59,10 +59,16 @@
|
||||||
- p12_backup_5.backup_file is undefined
|
- p12_backup_5.backup_file is undefined
|
||||||
- p12_backup_4.pkcs12 is none
|
- p12_backup_4.pkcs12 is none
|
||||||
|
|
||||||
- name: Check 'empty' file
|
- name: '({{ select_crypto_backend }}) Load "empty" file'
|
||||||
|
set_fact:
|
||||||
|
empty_contents: "{{ lookup('file', output_dir ~ '/ansible_empty.pem') }}"
|
||||||
|
empty_expected_pyopenssl: "{{ lookup('file', output_dir ~ '/ansible3.crt') ~ '\n' ~ lookup('file', output_dir ~ '/ansible2.crt') }}"
|
||||||
|
empty_expected_cryptography: "{{ lookup('file', output_dir ~ '/ansible2.crt') ~ '\n' ~ lookup('file', output_dir ~ '/ansible3.crt') }}"
|
||||||
|
|
||||||
|
- name: '({{ select_crypto_backend }}) Check "empty" file'
|
||||||
assert:
|
assert:
|
||||||
that:
|
that:
|
||||||
- p12_empty is changed
|
- p12_empty is changed
|
||||||
- p12_empty_idem is not changed
|
- p12_empty_idem is not changed
|
||||||
- p12_empty_concat_idem is not changed
|
- p12_empty_concat_idem is not changed
|
||||||
- "lookup('file', output_dir ~ '/ansible_empty.pem') == lookup('file', output_dir ~ '/ansible3.crt') ~ '\n' ~ lookup('file', output_dir ~ '/ansible2.crt')"
|
- empty_contents == (empty_expected_pyopenssl if select_crypto_backend == 'pyopenssl' else empty_expected_cryptography)
|
||||||
|
|
Loading…
Reference in New Issue