openssl_certificate/csr(_info): add support for SubjectKeyIdentifier and AuthorityKeyIdentifier (#60741)
* Add support for SubjectKeyIdentifier and AuthorityKeyIdentifier to _info modules. * Adding SubjectKeyIdentifier and AuthorityKeyIdentifier support to openssl_certificate and openssl_csr. * Fix type of authority_cert_issuer. * Add basic tests. * Add changelog. * Added proper tests for _info modules. * Fix docs bug. * Make sure new features are only used when cryptography backend for openssl_csr is available. * Work around jinja2 being too old on some CI hosts. * Add tests for openssl_csr. * Add openssl_certificate tests. * Fix idempotence test. * Move one level up. * Add ownca_create_authority_key_identifier option. * Add ownca_create_authority_key_identifier option. * Add idempotency check. * Apparently the function call expected different args for cryptography < 2.7. * Fix copy'n'paste errors and typos. * string -> general name. * Add disclaimer. * Implement always_create / create_if_not_provided / never_create for openssl_certificate. * Update changelog and porting guide. * Add comments for defaults.
This commit is contained in:
parent
77e4371460
commit
fa70690e5c
19 changed files with 1071 additions and 6 deletions
|
@ -0,0 +1,6 @@
|
||||||
|
minor_changes:
|
||||||
|
- "openssl_certificate - add support for subject key identifier and authority key identifier extensions. Subject key identifiers are created by default when not explicitly disabled."
|
||||||
|
- "openssl_certificate - the ``ownca`` provider creates authority key identifiers if not explicitly disabled with ``ownca_create_authority_key_identifier: no``."
|
||||||
|
- "openssl_certificate_info - add support for subject key identifier and authority key identifier extensions."
|
||||||
|
- "openssl_csr - add support for subject key identifier and authority key identifier extensions."
|
||||||
|
- "openssl_csr_info - add support for subject key identifier and authority key identifier extensions."
|
|
@ -306,6 +306,8 @@ Noteworthy module changes
|
||||||
* `mysql_db <mysql_db_module>` returns new `db_list` parameter in addition to `db` parameter. This `db_list` parameter refers to list of database names. `db` parameter will be deprecated in version `2.13`.
|
* `mysql_db <mysql_db_module>` returns new `db_list` parameter in addition to `db` parameter. This `db_list` parameter refers to list of database names. `db` parameter will be deprecated in version `2.13`.
|
||||||
* `snow_record <snow_record_module>` and `snow_record_find <snow_record_find_module>` now takes environment variables for `instance`, `username` and `password` parameters. This change marks these parameters as optional.
|
* `snow_record <snow_record_module>` and `snow_record_find <snow_record_find_module>` now takes environment variables for `instance`, `username` and `password` parameters. This change marks these parameters as optional.
|
||||||
* The deprecated ``force`` option in ``win_firewall_rule`` has been removed.
|
* The deprecated ``force`` option in ``win_firewall_rule`` has been removed.
|
||||||
|
* :ref:`openssl_certificate <openssl_certificate_module>`'s ``ownca`` provider creates authority key identifiers if not explicitly disabled with ``ownca_create_authority_key_identifier: no``. This is only the case for the ``cryptography`` backend, which is selected by default if the ``cryptography`` library is available.
|
||||||
|
* :ref:`openssl_certificate <openssl_certificate_module>`'s ``ownca`` and ``selfsigned`` providers create subject key identifiers if not explicitly disabled with ``ownca_create_subject_key_identifier: never_create`` resp. ``selfsigned_create_subject_key_identifier: never_create``. If a subject key identifier is provided by the CSR, it is taken; if not, it is created from the public key. This is only the case for the ``cryptography`` backend, which is selected by default if the ``cryptography`` library is available.
|
||||||
|
|
||||||
|
|
||||||
Plugins
|
Plugins
|
||||||
|
|
|
@ -138,6 +138,21 @@ options:
|
||||||
default: +3650d
|
default: +3650d
|
||||||
aliases: [ selfsigned_notAfter ]
|
aliases: [ selfsigned_notAfter ]
|
||||||
|
|
||||||
|
selfsigned_create_subject_key_identifier:
|
||||||
|
description:
|
||||||
|
- Whether to create the Subject Key Identifier (SKI) from the public key.
|
||||||
|
- A value of C(create_if_not_provided) (default) only creates a SKI when the CSR does not
|
||||||
|
provide one.
|
||||||
|
- A value of C(always_create) always creates a SKI. If the CSR provides one, that one is
|
||||||
|
ignored.
|
||||||
|
- A value of C(never_create) never creates a SKI. If the CSR provides one, that one is used.
|
||||||
|
- This is only used by the C(selfsigned) provider.
|
||||||
|
- Note that this is only supported if the C(cryptography) backend is used!
|
||||||
|
type: str
|
||||||
|
choices: [create_if_not_provided, always_create, never_create]
|
||||||
|
default: create_if_not_provided
|
||||||
|
version_added: "2.9"
|
||||||
|
|
||||||
ownca_path:
|
ownca_path:
|
||||||
description:
|
description:
|
||||||
- Remote absolute path of the CA (Certificate Authority) certificate.
|
- Remote absolute path of the CA (Certificate Authority) certificate.
|
||||||
|
@ -204,6 +219,33 @@ options:
|
||||||
default: +3650d
|
default: +3650d
|
||||||
version_added: "2.7"
|
version_added: "2.7"
|
||||||
|
|
||||||
|
ownca_create_subject_key_identifier:
|
||||||
|
description:
|
||||||
|
- Whether to create the Subject Key Identifier (SKI) from the public key.
|
||||||
|
- A value of C(create_if_not_provided) (default) only creates a SKI when the CSR does not
|
||||||
|
provide one.
|
||||||
|
- A value of C(always_create) always creates a SKI. If the CSR provides one, that one is
|
||||||
|
ignored.
|
||||||
|
- A value of C(never_create) never creates a SKI. If the CSR provides one, that one is used.
|
||||||
|
- This is only used by the C(ownca) provider.
|
||||||
|
- Note that this is only supported if the C(cryptography) backend is used!
|
||||||
|
type: str
|
||||||
|
choices: [create_if_not_provided, always_create, never_create]
|
||||||
|
default: create_if_not_provided
|
||||||
|
version_added: "2.9"
|
||||||
|
|
||||||
|
ownca_create_authority_key_identifier:
|
||||||
|
description:
|
||||||
|
- Create a Authority Key Identifier from the CA's certificate. If the CSR provided
|
||||||
|
a authority key identifier, it is ignored.
|
||||||
|
- The Authority Key Identifier is generated from the CA certificate's Subject Key Identifier,
|
||||||
|
if available. If it is not available, the CA certificate's public key will be used.
|
||||||
|
- This is only used by the C(ownca) provider.
|
||||||
|
- Note that this is only supported if the C(cryptography) backend is used!
|
||||||
|
type: bool
|
||||||
|
default: yes
|
||||||
|
version_added: "2.9"
|
||||||
|
|
||||||
acme_accountkey_path:
|
acme_accountkey_path:
|
||||||
description:
|
description:
|
||||||
- The path to the accountkey for the C(acme) provider.
|
- The path to the accountkey for the C(acme) provider.
|
||||||
|
@ -843,6 +885,11 @@ class Certificate(crypto_utils.OpenSSLObject):
|
||||||
self.backend = backend
|
self.backend = backend
|
||||||
self.module = module
|
self.module = module
|
||||||
|
|
||||||
|
# The following are default values which make sure check() works as
|
||||||
|
# before if providers do not explicitly change these properties.
|
||||||
|
self.create_subject_key_identifier = 'never_create'
|
||||||
|
self.create_authority_key_identifier = False
|
||||||
|
|
||||||
self.backup = module.params['backup']
|
self.backup = module.params['backup']
|
||||||
self.backup_file = None
|
self.backup_file = None
|
||||||
|
|
||||||
|
@ -918,13 +965,21 @@ class Certificate(crypto_utils.OpenSSLObject):
|
||||||
if self.csr.subject != self.cert.subject:
|
if self.csr.subject != self.cert.subject:
|
||||||
return False
|
return False
|
||||||
# Check extensions
|
# Check extensions
|
||||||
cert_exts = self.cert.extensions
|
cert_exts = list(self.cert.extensions)
|
||||||
csr_exts = self.csr.extensions
|
csr_exts = list(self.csr.extensions)
|
||||||
|
if self.create_subject_key_identifier != 'never_create':
|
||||||
|
# Filter out SubjectKeyIdentifier extension before comparison
|
||||||
|
cert_exts = list(filter(lambda x: not isinstance(x.value, x509.SubjectKeyIdentifier), cert_exts))
|
||||||
|
csr_exts = list(filter(lambda x: not isinstance(x.value, x509.SubjectKeyIdentifier), csr_exts))
|
||||||
|
if self.create_authority_key_identifier:
|
||||||
|
# Filter out AuthorityKeyIdentifier extension before comparison
|
||||||
|
cert_exts = list(filter(lambda x: not isinstance(x.value, x509.AuthorityKeyIdentifier), cert_exts))
|
||||||
|
csr_exts = list(filter(lambda x: not isinstance(x.value, x509.AuthorityKeyIdentifier), csr_exts))
|
||||||
if len(cert_exts) != len(csr_exts):
|
if len(cert_exts) != len(csr_exts):
|
||||||
return False
|
return False
|
||||||
for cert_ext in cert_exts:
|
for cert_ext in cert_exts:
|
||||||
try:
|
try:
|
||||||
csr_ext = csr_exts.get_extension_for_oid(cert_ext.oid)
|
csr_ext = self.csr.extensions.get_extension_for_oid(cert_ext.oid)
|
||||||
if cert_ext != csr_ext:
|
if cert_ext != csr_ext:
|
||||||
return False
|
return False
|
||||||
except cryptography.x509.ExtensionNotFound as dummy:
|
except cryptography.x509.ExtensionNotFound as dummy:
|
||||||
|
@ -966,6 +1021,29 @@ class Certificate(crypto_utils.OpenSSLObject):
|
||||||
if not self._validate_csr():
|
if not self._validate_csr():
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
# Check SubjectKeyIdentifier
|
||||||
|
if self.backend == 'cryptography' and self.create_subject_key_identifier != 'never_create':
|
||||||
|
# Get hold of certificate's SKI
|
||||||
|
try:
|
||||||
|
ext = self.cert.extensions.get_extension_for_class(x509.SubjectKeyIdentifier)
|
||||||
|
except cryptography.x509.ExtensionNotFound as dummy:
|
||||||
|
return False
|
||||||
|
# Get hold of CSR's SKI for 'create_if_not_provided'
|
||||||
|
csr_ext = None
|
||||||
|
if self.create_subject_key_identifier == 'create_if_not_provided':
|
||||||
|
try:
|
||||||
|
csr_ext = self.csr.extensions.get_extension_for_class(x509.SubjectKeyIdentifier)
|
||||||
|
except cryptography.x509.ExtensionNotFound as dummy:
|
||||||
|
pass
|
||||||
|
if csr_ext is None:
|
||||||
|
# If CSR had no SKI, or we chose to ignore it ('always_create'), compare with created SKI
|
||||||
|
if ext.value.digest != x509.SubjectKeyIdentifier.from_public_key(self.cert.public_key()).digest:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
# If CSR had SKI and we didn't ignore it ('create_if_not_provided'), compare SKIs
|
||||||
|
if ext.value.digest != csr_ext.value.digest:
|
||||||
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@ -995,6 +1073,7 @@ class SelfSignedCertificateCryptography(Certificate):
|
||||||
"""Generate the self-signed certificate, using the cryptography backend"""
|
"""Generate the self-signed certificate, using the cryptography backend"""
|
||||||
def __init__(self, module):
|
def __init__(self, module):
|
||||||
super(SelfSignedCertificateCryptography, self).__init__(module, 'cryptography')
|
super(SelfSignedCertificateCryptography, self).__init__(module, 'cryptography')
|
||||||
|
self.create_subject_key_identifier = module.params['selfsigned_create_subject_key_identifier']
|
||||||
self.notBefore = self.get_relative_time_option(module.params['selfsigned_not_before'], 'selfsigned_not_before')
|
self.notBefore = self.get_relative_time_option(module.params['selfsigned_not_before'], 'selfsigned_not_before')
|
||||||
self.notAfter = self.get_relative_time_option(module.params['selfsigned_not_after'], 'selfsigned_not_after')
|
self.notAfter = self.get_relative_time_option(module.params['selfsigned_not_after'], 'selfsigned_not_after')
|
||||||
self.digest = crypto_utils.select_message_digest(module.params['selfsigned_digest'])
|
self.digest = crypto_utils.select_message_digest(module.params['selfsigned_digest'])
|
||||||
|
@ -1043,8 +1122,18 @@ class SelfSignedCertificateCryptography(Certificate):
|
||||||
cert_builder = cert_builder.not_valid_before(self.notBefore)
|
cert_builder = cert_builder.not_valid_before(self.notBefore)
|
||||||
cert_builder = cert_builder.not_valid_after(self.notAfter)
|
cert_builder = cert_builder.not_valid_after(self.notAfter)
|
||||||
cert_builder = cert_builder.public_key(self.privatekey.public_key())
|
cert_builder = cert_builder.public_key(self.privatekey.public_key())
|
||||||
|
has_ski = False
|
||||||
for extension in self.csr.extensions:
|
for extension in self.csr.extensions:
|
||||||
|
if isinstance(extension.value, x509.SubjectKeyIdentifier):
|
||||||
|
if self.create_subject_key_identifier == 'always_create':
|
||||||
|
continue
|
||||||
|
has_ski = True
|
||||||
cert_builder = cert_builder.add_extension(extension.value, critical=extension.critical)
|
cert_builder = cert_builder.add_extension(extension.value, critical=extension.critical)
|
||||||
|
if not has_ski and self.create_subject_key_identifier != 'never_create':
|
||||||
|
cert_builder = cert_builder.add_extension(
|
||||||
|
x509.SubjectKeyIdentifier.from_public_key(self.privatekey.public_key()),
|
||||||
|
critical=False
|
||||||
|
)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
raise CertificateError(str(e))
|
raise CertificateError(str(e))
|
||||||
|
|
||||||
|
@ -1098,6 +1187,8 @@ class SelfSignedCertificate(Certificate):
|
||||||
|
|
||||||
def __init__(self, module):
|
def __init__(self, module):
|
||||||
super(SelfSignedCertificate, self).__init__(module, 'pyopenssl')
|
super(SelfSignedCertificate, self).__init__(module, 'pyopenssl')
|
||||||
|
if module.params['selfsigned_create_subject_key_identifier'] != 'create_if_not_provided':
|
||||||
|
module.fail_json(msg='selfsigned_create_subject_key_identifier cannot be used with the pyOpenSSL backend!')
|
||||||
self.notBefore = self.get_relative_time_option(module.params['selfsigned_not_before'], 'selfsigned_not_before')
|
self.notBefore = self.get_relative_time_option(module.params['selfsigned_not_before'], 'selfsigned_not_before')
|
||||||
self.notAfter = self.get_relative_time_option(module.params['selfsigned_not_after'], 'selfsigned_not_after')
|
self.notAfter = self.get_relative_time_option(module.params['selfsigned_not_after'], 'selfsigned_not_after')
|
||||||
self.digest = module.params['selfsigned_digest']
|
self.digest = module.params['selfsigned_digest']
|
||||||
|
@ -1187,6 +1278,8 @@ class OwnCACertificateCryptography(Certificate):
|
||||||
"""Generate the own CA certificate. Using the cryptography backend"""
|
"""Generate the own CA certificate. Using the cryptography backend"""
|
||||||
def __init__(self, module):
|
def __init__(self, module):
|
||||||
super(OwnCACertificateCryptography, self).__init__(module, 'cryptography')
|
super(OwnCACertificateCryptography, self).__init__(module, 'cryptography')
|
||||||
|
self.create_subject_key_identifier = module.params['ownca_create_subject_key_identifier']
|
||||||
|
self.create_authority_key_identifier = module.params['ownca_create_authority_key_identifier']
|
||||||
self.notBefore = self.get_relative_time_option(module.params['ownca_not_before'], 'ownca_not_before')
|
self.notBefore = self.get_relative_time_option(module.params['ownca_not_before'], 'ownca_not_before')
|
||||||
self.notAfter = self.get_relative_time_option(module.params['ownca_not_after'], 'ownca_not_after')
|
self.notAfter = self.get_relative_time_option(module.params['ownca_not_after'], 'ownca_not_after')
|
||||||
self.digest = crypto_utils.select_message_digest(module.params['ownca_digest'])
|
self.digest = crypto_utils.select_message_digest(module.params['ownca_digest'])
|
||||||
|
@ -1243,8 +1336,34 @@ class OwnCACertificateCryptography(Certificate):
|
||||||
cert_builder = cert_builder.not_valid_before(self.notBefore)
|
cert_builder = cert_builder.not_valid_before(self.notBefore)
|
||||||
cert_builder = cert_builder.not_valid_after(self.notAfter)
|
cert_builder = cert_builder.not_valid_after(self.notAfter)
|
||||||
cert_builder = cert_builder.public_key(self.csr.public_key())
|
cert_builder = cert_builder.public_key(self.csr.public_key())
|
||||||
|
has_ski = False
|
||||||
for extension in self.csr.extensions:
|
for extension in self.csr.extensions:
|
||||||
|
if isinstance(extension.value, x509.SubjectKeyIdentifier):
|
||||||
|
if self.create_subject_key_identifier == 'always_create':
|
||||||
|
continue
|
||||||
|
has_ski = True
|
||||||
|
if self.create_authority_key_identifier and isinstance(extension.value, x509.AuthorityKeyIdentifier):
|
||||||
|
continue
|
||||||
cert_builder = cert_builder.add_extension(extension.value, critical=extension.critical)
|
cert_builder = cert_builder.add_extension(extension.value, critical=extension.critical)
|
||||||
|
if not has_ski and self.create_subject_key_identifier != 'never_create':
|
||||||
|
cert_builder = cert_builder.add_extension(
|
||||||
|
x509.SubjectKeyIdentifier.from_public_key(self.csr.public_key()),
|
||||||
|
critical=False
|
||||||
|
)
|
||||||
|
if self.create_authority_key_identifier:
|
||||||
|
try:
|
||||||
|
ext = self.ca_cert.extensions.get_extension_for_class(x509.SubjectKeyIdentifier)
|
||||||
|
cert_builder = cert_builder.add_extension(
|
||||||
|
x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(ext.value)
|
||||||
|
if CRYPTOGRAPHY_VERSION >= LooseVersion('2.7') else
|
||||||
|
x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(ext),
|
||||||
|
critical=False
|
||||||
|
)
|
||||||
|
except cryptography.x509.ExtensionNotFound:
|
||||||
|
cert_builder = cert_builder.add_extension(
|
||||||
|
x509.AuthorityKeyIdentifier.from_issuer_public_key(self.ca_cert.public_key()),
|
||||||
|
critical=False
|
||||||
|
)
|
||||||
|
|
||||||
certificate = cert_builder.sign(
|
certificate = cert_builder.sign(
|
||||||
private_key=self.ca_private_key, algorithm=self.digest,
|
private_key=self.ca_private_key, algorithm=self.digest,
|
||||||
|
@ -1264,6 +1383,32 @@ class OwnCACertificateCryptography(Certificate):
|
||||||
if module.set_fs_attributes_if_different(file_args, False):
|
if module.set_fs_attributes_if_different(file_args, False):
|
||||||
self.changed = True
|
self.changed = True
|
||||||
|
|
||||||
|
def check(self, module, perms_required=True):
|
||||||
|
"""Ensure the resource is in its desired state."""
|
||||||
|
|
||||||
|
if not super(OwnCACertificateCryptography, self).check(module, perms_required):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Check AuthorityKeyIdentifier
|
||||||
|
if self.create_authority_key_identifier:
|
||||||
|
try:
|
||||||
|
ext = self.ca_cert.extensions.get_extension_for_class(x509.SubjectKeyIdentifier)
|
||||||
|
expected_ext = (
|
||||||
|
x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(ext.value)
|
||||||
|
if CRYPTOGRAPHY_VERSION >= LooseVersion('2.7') else
|
||||||
|
x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(ext)
|
||||||
|
)
|
||||||
|
except cryptography.x509.ExtensionNotFound:
|
||||||
|
expected_ext = x509.AuthorityKeyIdentifier.from_issuer_public_key(self.ca_cert.public_key())
|
||||||
|
try:
|
||||||
|
ext = self.cert.extensions.get_extension_for_class(x509.AuthorityKeyIdentifier)
|
||||||
|
if ext.value != expected_ext:
|
||||||
|
return False
|
||||||
|
except cryptography.x509.ExtensionNotFound as dummy:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
def dump(self, check_mode=False):
|
def dump(self, check_mode=False):
|
||||||
|
|
||||||
result = {
|
result = {
|
||||||
|
@ -1303,6 +1448,10 @@ class OwnCACertificate(Certificate):
|
||||||
self.digest = module.params['ownca_digest']
|
self.digest = module.params['ownca_digest']
|
||||||
self.version = module.params['ownca_version']
|
self.version = module.params['ownca_version']
|
||||||
self.serial_number = randint(1000, 99999)
|
self.serial_number = randint(1000, 99999)
|
||||||
|
if module.params['ownca_create_subject_key_identifier'] != 'create_if_not_provided':
|
||||||
|
module.fail_json(msg='ownca_create_subject_key_identifier cannot be used with the pyOpenSSL backend!')
|
||||||
|
if module.params['ownca_create_authority_key_identifier']:
|
||||||
|
module.warn('ownca_create_authority_key_identifier is ignored by the pyOpenSSL backend!')
|
||||||
self.ca_cert_path = module.params['ownca_path']
|
self.ca_cert_path = module.params['ownca_path']
|
||||||
self.ca_privatekey_path = module.params['ownca_privatekey_path']
|
self.ca_privatekey_path = module.params['ownca_privatekey_path']
|
||||||
self.ca_privatekey_passphrase = module.params['ownca_privatekey_passphrase']
|
self.ca_privatekey_passphrase = module.params['ownca_privatekey_passphrase']
|
||||||
|
@ -2268,6 +2417,11 @@ def main():
|
||||||
selfsigned_digest=dict(type='str', default='sha256'),
|
selfsigned_digest=dict(type='str', default='sha256'),
|
||||||
selfsigned_not_before=dict(type='str', default='+0s', aliases=['selfsigned_notBefore']),
|
selfsigned_not_before=dict(type='str', default='+0s', aliases=['selfsigned_notBefore']),
|
||||||
selfsigned_not_after=dict(type='str', default='+3650d', aliases=['selfsigned_notAfter']),
|
selfsigned_not_after=dict(type='str', default='+3650d', aliases=['selfsigned_notAfter']),
|
||||||
|
selfsigned_create_subject_key_identifier=dict(
|
||||||
|
type='str',
|
||||||
|
default='create_if_not_provided',
|
||||||
|
choices=['create_if_not_provided', 'always_create', 'never_create']
|
||||||
|
),
|
||||||
|
|
||||||
# provider: ownca
|
# provider: ownca
|
||||||
ownca_path=dict(type='path'),
|
ownca_path=dict(type='path'),
|
||||||
|
@ -2277,6 +2431,12 @@ def main():
|
||||||
ownca_version=dict(type='int', default=3),
|
ownca_version=dict(type='int', default=3),
|
||||||
ownca_not_before=dict(type='str', default='+0s'),
|
ownca_not_before=dict(type='str', default='+0s'),
|
||||||
ownca_not_after=dict(type='str', default='+3650d'),
|
ownca_not_after=dict(type='str', default='+3650d'),
|
||||||
|
ownca_create_subject_key_identifier=dict(
|
||||||
|
type='str',
|
||||||
|
default='create_if_not_provided',
|
||||||
|
choices=['create_if_not_provided', 'always_create', 'never_create']
|
||||||
|
),
|
||||||
|
ownca_create_authority_key_identifier=dict(type='bool', default=True),
|
||||||
|
|
||||||
# provider: acme
|
# provider: acme
|
||||||
acme_accountkey_path=dict(type='path'),
|
acme_accountkey_path=dict(type='path'),
|
||||||
|
|
|
@ -238,10 +238,45 @@ valid_at:
|
||||||
or not.
|
or not.
|
||||||
returned: success
|
returned: success
|
||||||
type: dict
|
type: dict
|
||||||
|
subject_key_identifier:
|
||||||
|
description:
|
||||||
|
- The certificate's subject key identifier.
|
||||||
|
- The identifier is returned in hexadecimal, with C(:) used to separate bytes.
|
||||||
|
- Is C(none) if the C(SubjectKeyIdentifier) extension is not present.
|
||||||
|
returned: success and if the pyOpenSSL backend is I(not) used
|
||||||
|
type: str
|
||||||
|
sample: '00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22:33'
|
||||||
|
version_added: "2.9"
|
||||||
|
authority_key_identifier:
|
||||||
|
description:
|
||||||
|
- The certificate's authority key identifier.
|
||||||
|
- The identifier is returned in hexadecimal, with C(:) used to separate bytes.
|
||||||
|
- Is C(none) if the C(AuthorityKeyIdentifier) extension is not present.
|
||||||
|
returned: success and if the pyOpenSSL backend is I(not) used
|
||||||
|
type: str
|
||||||
|
sample: '00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22:33'
|
||||||
|
version_added: "2.9"
|
||||||
|
authority_cert_issuer:
|
||||||
|
description:
|
||||||
|
- The certificate's authority cert issuer as a list of general names.
|
||||||
|
- Is C(none) if the C(AuthorityKeyIdentifier) extension is not present.
|
||||||
|
returned: success and if the pyOpenSSL backend is I(not) used
|
||||||
|
type: list
|
||||||
|
sample: "[DNS:www.ansible.com, IP:1.2.3.4]"
|
||||||
|
version_added: "2.9"
|
||||||
|
authority_cert_serial_number:
|
||||||
|
description:
|
||||||
|
- The certificate's authority cert serial number.
|
||||||
|
- Is C(none) if the C(AuthorityKeyIdentifier) extension is not present.
|
||||||
|
returned: success and if the pyOpenSSL backend is I(not) used
|
||||||
|
type: int
|
||||||
|
sample: '12345'
|
||||||
|
version_added: "2.9"
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
import abc
|
import abc
|
||||||
|
import binascii
|
||||||
import datetime
|
import datetime
|
||||||
import os
|
import os
|
||||||
import traceback
|
import traceback
|
||||||
|
@ -392,6 +427,14 @@ class CertificateInfo(crypto_utils.OpenSSLObject):
|
||||||
def _get_public_key(self, binary):
|
def _get_public_key(self, binary):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def _get_subject_key_identifier(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def _get_authority_key_identifier(self):
|
||||||
|
pass
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def _get_serial_number(self):
|
def _get_serial_number(self):
|
||||||
pass
|
pass
|
||||||
|
@ -437,6 +480,21 @@ class CertificateInfo(crypto_utils.OpenSSLObject):
|
||||||
pk = self._get_public_key(binary=True)
|
pk = self._get_public_key(binary=True)
|
||||||
result['public_key_fingerprints'] = crypto_utils.get_fingerprint_of_bytes(pk) if pk is not None else dict()
|
result['public_key_fingerprints'] = crypto_utils.get_fingerprint_of_bytes(pk) if pk is not None else dict()
|
||||||
|
|
||||||
|
if self.backend != 'pyopenssl':
|
||||||
|
ski = self._get_subject_key_identifier()
|
||||||
|
if ski is not None:
|
||||||
|
ski = to_native(binascii.hexlify(ski))
|
||||||
|
ski = ':'.join([ski[i:i + 2] for i in range(0, len(ski), 2)])
|
||||||
|
result['subject_key_identifier'] = ski
|
||||||
|
|
||||||
|
aki, aci, acsn = self._get_authority_key_identifier()
|
||||||
|
if aki is not None:
|
||||||
|
aki = to_native(binascii.hexlify(aki))
|
||||||
|
aki = ':'.join([aki[i:i + 2] for i in range(0, len(aki), 2)])
|
||||||
|
result['authority_key_identifier'] = aki
|
||||||
|
result['authority_cert_issuer'] = aci
|
||||||
|
result['authority_cert_serial_number'] = acsn
|
||||||
|
|
||||||
result['serial_number'] = self._get_serial_number()
|
result['serial_number'] = self._get_serial_number()
|
||||||
result['extensions_by_oid'] = self._get_all_extensions()
|
result['extensions_by_oid'] = self._get_all_extensions()
|
||||||
|
|
||||||
|
@ -563,6 +621,23 @@ class CertificateInfoCryptography(CertificateInfo):
|
||||||
serialization.PublicFormat.SubjectPublicKeyInfo
|
serialization.PublicFormat.SubjectPublicKeyInfo
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _get_subject_key_identifier(self):
|
||||||
|
try:
|
||||||
|
ext = self.cert.extensions.get_extension_for_class(x509.SubjectKeyIdentifier)
|
||||||
|
return ext.value.digest
|
||||||
|
except cryptography.x509.ExtensionNotFound:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _get_authority_key_identifier(self):
|
||||||
|
try:
|
||||||
|
ext = self.cert.extensions.get_extension_for_class(x509.AuthorityKeyIdentifier)
|
||||||
|
issuer = None
|
||||||
|
if ext.value.authority_cert_issuer is not None:
|
||||||
|
issuer = [crypto_utils.cryptography_decode_name(san) for san in ext.value.authority_cert_issuer]
|
||||||
|
return ext.value.key_identifier, issuer, ext.value.authority_cert_serial_number
|
||||||
|
except cryptography.x509.ExtensionNotFound:
|
||||||
|
return None, None, None
|
||||||
|
|
||||||
def _get_serial_number(self):
|
def _get_serial_number(self):
|
||||||
return self.cert.serial_number
|
return self.cert.serial_number
|
||||||
|
|
||||||
|
@ -675,6 +750,14 @@ class CertificateInfoPyOpenSSL(CertificateInfo):
|
||||||
self.module.warn('Your pyOpenSSL version does not support dumping public keys. '
|
self.module.warn('Your pyOpenSSL version does not support dumping public keys. '
|
||||||
'Please upgrade to version 16.0 or newer, or use the cryptography backend.')
|
'Please upgrade to version 16.0 or newer, or use the cryptography backend.')
|
||||||
|
|
||||||
|
def _get_subject_key_identifier(self):
|
||||||
|
# Won't be implemented
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _get_authority_key_identifier(self):
|
||||||
|
# Won't be implemented
|
||||||
|
return None, None, None
|
||||||
|
|
||||||
def _get_serial_number(self):
|
def _get_serial_number(self):
|
||||||
return self.cert.get_serial_number()
|
return self.cert.get_serial_number()
|
||||||
|
|
||||||
|
|
|
@ -200,6 +200,66 @@ options:
|
||||||
type: bool
|
type: bool
|
||||||
default: no
|
default: no
|
||||||
version_added: "2.8"
|
version_added: "2.8"
|
||||||
|
create_subject_key_identifier:
|
||||||
|
description:
|
||||||
|
- Create the Subject Key Identifier from the public key.
|
||||||
|
- "Please note that commercial CAs can ignore the value, respectively use a value of
|
||||||
|
their own choice instead. Specifying this option is mostly useful for self-signed
|
||||||
|
certificates or for own CAs."
|
||||||
|
- Note that this is only supported if the C(cryptography) backend is used!
|
||||||
|
type: bool
|
||||||
|
default: no
|
||||||
|
version_added: "2.9"
|
||||||
|
subject_key_identifier:
|
||||||
|
description:
|
||||||
|
- The subject key identifier as a hex string, where two bytes are separated by colons.
|
||||||
|
- "Example: C(00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22:33)"
|
||||||
|
- "Please note that commercial CAs ignore this value, respectively use a value of their
|
||||||
|
own choice. Specifying this option is mostly useful for self-signed certificates
|
||||||
|
or for own CAs."
|
||||||
|
- Note that this option can only be used if I(create_subject_key_identifier) is C(no).
|
||||||
|
- Note that this is only supported if the C(cryptography) backend is used!
|
||||||
|
type: str
|
||||||
|
version_added: "2.9"
|
||||||
|
authority_key_identifier:
|
||||||
|
description:
|
||||||
|
- The authority key identifier as a hex string, where two bytes are separated by colons.
|
||||||
|
- "Example: C(00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22:33)"
|
||||||
|
- If specified, I(authority_cert_issuer) must also be specified.
|
||||||
|
- "Please note that commercial CAs ignore this value, respectively use a value of their
|
||||||
|
own choice. Specifying this option is mostly useful for self-signed certificates
|
||||||
|
or for own CAs."
|
||||||
|
- Note that this is only supported if the C(cryptography) backend is used!
|
||||||
|
- The C(AuthorityKeyIdentifier) will only be added if at least one of I(authority_key_identifier),
|
||||||
|
I(authority_cert_issuer) and I(authority_cert_serial_number) is specified.
|
||||||
|
type: str
|
||||||
|
version_added: "2.9"
|
||||||
|
authority_cert_issuer:
|
||||||
|
description:
|
||||||
|
- Names that will be present in the authority cert issuer field of the certificate signing request.
|
||||||
|
- Values must be prefixed by their options. (i.e., C(email), C(URI), C(DNS), C(RID), C(IP), C(dirName),
|
||||||
|
C(otherName) and the ones specific to your CA)
|
||||||
|
- "Example: C(DNS:ca.example.org)"
|
||||||
|
- If specified, I(authority_key_identifier) must also be specified.
|
||||||
|
- "Please note that commercial CAs ignore this value, respectively use a value of their
|
||||||
|
own choice. Specifying this option is mostly useful for self-signed certificates
|
||||||
|
or for own CAs."
|
||||||
|
- Note that this is only supported if the C(cryptography) backend is used!
|
||||||
|
- The C(AuthorityKeyIdentifier) will only be added if at least one of I(authority_key_identifier),
|
||||||
|
I(authority_cert_issuer) and I(authority_cert_serial_number) is specified.
|
||||||
|
type: list
|
||||||
|
version_added: "2.9"
|
||||||
|
authority_cert_serial_number:
|
||||||
|
description:
|
||||||
|
- The authority cert serial number.
|
||||||
|
- Note that this is only supported if the C(cryptography) backend is used!
|
||||||
|
- "Please note that commercial CAs ignore this value, respectively use a value of their
|
||||||
|
own choice. Specifying this option is mostly useful for self-signed certificates
|
||||||
|
or for own CAs."
|
||||||
|
- The C(AuthorityKeyIdentifier) will only be added if at least one of I(authority_key_identifier),
|
||||||
|
I(authority_cert_issuer) and I(authority_cert_serial_number) is specified.
|
||||||
|
type: int
|
||||||
|
version_added: "2.9"
|
||||||
extends_documentation_fragment:
|
extends_documentation_fragment:
|
||||||
- files
|
- files
|
||||||
notes:
|
notes:
|
||||||
|
@ -329,6 +389,7 @@ backup_file:
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import abc
|
import abc
|
||||||
|
import binascii
|
||||||
import os
|
import os
|
||||||
import traceback
|
import traceback
|
||||||
from distutils.version import LooseVersion
|
from distutils.version import LooseVersion
|
||||||
|
@ -406,9 +467,17 @@ class CertificateSigningRequestBase(crypto_utils.OpenSSLObject):
|
||||||
self.basicConstraints_critical = module.params['basic_constraints_critical']
|
self.basicConstraints_critical = module.params['basic_constraints_critical']
|
||||||
self.ocspMustStaple = module.params['ocsp_must_staple']
|
self.ocspMustStaple = module.params['ocsp_must_staple']
|
||||||
self.ocspMustStaple_critical = module.params['ocsp_must_staple_critical']
|
self.ocspMustStaple_critical = module.params['ocsp_must_staple_critical']
|
||||||
|
self.create_subject_key_identifier = module.params['create_subject_key_identifier']
|
||||||
|
self.subject_key_identifier = module.params['subject_key_identifier']
|
||||||
|
self.authority_key_identifier = module.params['authority_key_identifier']
|
||||||
|
self.authority_cert_issuer = module.params['authority_cert_issuer']
|
||||||
|
self.authority_cert_serial_number = module.params['authority_cert_serial_number']
|
||||||
self.request = None
|
self.request = None
|
||||||
self.privatekey = None
|
self.privatekey = None
|
||||||
|
|
||||||
|
if self.create_subject_key_identifier and self.subject_key_identifier is not None:
|
||||||
|
module.fail_json(msg='subject_key_identifier cannot be specified if create_subject_key_identifier is true')
|
||||||
|
|
||||||
self.backup = module.params['backup']
|
self.backup = module.params['backup']
|
||||||
self.backup_file = None
|
self.backup_file = None
|
||||||
|
|
||||||
|
@ -432,6 +501,18 @@ class CertificateSigningRequestBase(crypto_utils.OpenSSLObject):
|
||||||
self.subjectAltName = ['DNS:%s' % sub[1]]
|
self.subjectAltName = ['DNS:%s' % sub[1]]
|
||||||
break
|
break
|
||||||
|
|
||||||
|
if self.subject_key_identifier is not None:
|
||||||
|
try:
|
||||||
|
self.subject_key_identifier = binascii.unhexlify(self.subject_key_identifier.replace(':', ''))
|
||||||
|
except Exception as e:
|
||||||
|
raise CertificateSigningRequestError('Cannot parse subject_key_identifier: {0}'.format(e))
|
||||||
|
|
||||||
|
if self.authority_key_identifier is not None:
|
||||||
|
try:
|
||||||
|
self.authority_key_identifier = binascii.unhexlify(self.authority_key_identifier.replace(':', ''))
|
||||||
|
except Exception as e:
|
||||||
|
raise CertificateSigningRequestError('Cannot parse authority_key_identifier: {0}'.format(e))
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def _generate_csr(self):
|
def _generate_csr(self):
|
||||||
pass
|
pass
|
||||||
|
@ -496,6 +577,11 @@ class CertificateSigningRequestBase(crypto_utils.OpenSSLObject):
|
||||||
class CertificateSigningRequestPyOpenSSL(CertificateSigningRequestBase):
|
class CertificateSigningRequestPyOpenSSL(CertificateSigningRequestBase):
|
||||||
|
|
||||||
def __init__(self, module):
|
def __init__(self, module):
|
||||||
|
if module.params['create_subject_key_identifier']:
|
||||||
|
module.fail_json(msg='You cannot use create_subject_key_identifier with the pyOpenSSL backend!')
|
||||||
|
for o in ('subject_key_identifier', 'authority_key_identifier', 'authority_cert_issuer', 'authority_cert_serial_number'):
|
||||||
|
if module.params[o] is not None:
|
||||||
|
module.fail_json(msg='You cannot use {0} with the pyOpenSSL backend!'.format(o))
|
||||||
super(CertificateSigningRequestPyOpenSSL, self).__init__(module)
|
super(CertificateSigningRequestPyOpenSSL, self).__init__(module)
|
||||||
|
|
||||||
def _generate_csr(self):
|
def _generate_csr(self):
|
||||||
|
@ -691,6 +777,23 @@ class CertificateSigningRequestCryptography(CertificateSigningRequestBase):
|
||||||
critical=self.ocspMustStaple_critical
|
critical=self.ocspMustStaple_critical
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if self.create_subject_key_identifier:
|
||||||
|
csr = csr.add_extension(
|
||||||
|
cryptography.x509.SubjectKeyIdentifier.from_public_key(self.privatekey.public_key()),
|
||||||
|
critical=False
|
||||||
|
)
|
||||||
|
elif self.subject_key_identifier is not None:
|
||||||
|
csr = csr.add_extension(cryptography.x509.SubjectKeyIdentifier(self.subject_key_identifier), critical=False)
|
||||||
|
|
||||||
|
if self.authority_key_identifier is not None or self.authority_cert_issuer is not None or self.authority_cert_serial_number is not None:
|
||||||
|
issuers = None
|
||||||
|
if self.authority_cert_issuer is not None:
|
||||||
|
issuers = [crypto_utils.cryptography_get_name(n) for n in self.authority_cert_issuer]
|
||||||
|
csr = csr.add_extension(
|
||||||
|
cryptography.x509.AuthorityKeyIdentifier(self.authority_key_identifier, issuers, self.authority_cert_serial_number),
|
||||||
|
critical=False
|
||||||
|
)
|
||||||
|
|
||||||
digest = None
|
digest = None
|
||||||
if self.digest == 'sha256':
|
if self.digest == 'sha256':
|
||||||
digest = cryptography.hazmat.primitives.hashes.SHA256()
|
digest = cryptography.hazmat.primitives.hashes.SHA256()
|
||||||
|
@ -806,11 +909,42 @@ class CertificateSigningRequestCryptography(CertificateSigningRequestBase):
|
||||||
else:
|
else:
|
||||||
return tlsfeature_ext is None
|
return tlsfeature_ext is None
|
||||||
|
|
||||||
|
def _check_subject_key_identifier(extensions):
|
||||||
|
ext = _find_extension(extensions, cryptography.x509.SubjectKeyIdentifier)
|
||||||
|
if self.create_subject_key_identifier or self.subject_key_identifier is not None:
|
||||||
|
if not ext or ext.critical:
|
||||||
|
return False
|
||||||
|
if self.create_subject_key_identifier:
|
||||||
|
digest = cryptography.x509.SubjectKeyIdentifier.from_public_key(self.privatekey.public_key()).digest
|
||||||
|
return ext.value.digest == digest
|
||||||
|
else:
|
||||||
|
return ext.value.digest == self.subject_key_identifier
|
||||||
|
else:
|
||||||
|
return ext is None
|
||||||
|
|
||||||
|
def _check_authority_key_identifier(extensions):
|
||||||
|
ext = _find_extension(extensions, cryptography.x509.AuthorityKeyIdentifier)
|
||||||
|
if self.authority_key_identifier is not None or self.authority_cert_issuer is not None or self.authority_cert_serial_number is not None:
|
||||||
|
if not ext or ext.critical:
|
||||||
|
return False
|
||||||
|
aci = None
|
||||||
|
csr_aci = None
|
||||||
|
if self.authority_cert_issuer is not None:
|
||||||
|
aci = [str(crypto_utils.cryptography_get_name(n)) for n in self.authority_cert_issuer]
|
||||||
|
if ext.value.authority_cert_issuer is not None:
|
||||||
|
csr_aci = [str(n) for n in ext.value.authority_cert_issuer]
|
||||||
|
return (ext.value.key_identifier == self.authority_key_identifier
|
||||||
|
and csr_aci == aci
|
||||||
|
and ext.value.authority_cert_serial_number == self.authority_cert_serial_number)
|
||||||
|
else:
|
||||||
|
return ext is None
|
||||||
|
|
||||||
def _check_extensions(csr):
|
def _check_extensions(csr):
|
||||||
extensions = csr.extensions
|
extensions = csr.extensions
|
||||||
return (_check_subjectAltName(extensions) and _check_keyUsage(extensions) and
|
return (_check_subjectAltName(extensions) and _check_keyUsage(extensions) and
|
||||||
_check_extenededKeyUsage(extensions) and _check_basicConstraints(extensions) and
|
_check_extenededKeyUsage(extensions) and _check_basicConstraints(extensions) and
|
||||||
_check_ocspMustStaple(extensions))
|
_check_ocspMustStaple(extensions) and _check_subject_key_identifier(extensions) and
|
||||||
|
_check_authority_key_identifier(extensions))
|
||||||
|
|
||||||
def _check_signature(csr):
|
def _check_signature(csr):
|
||||||
if not csr.is_signature_valid:
|
if not csr.is_signature_valid:
|
||||||
|
@ -865,8 +999,14 @@ def main():
|
||||||
ocsp_must_staple=dict(type='bool', default=False, aliases=['ocspMustStaple']),
|
ocsp_must_staple=dict(type='bool', default=False, aliases=['ocspMustStaple']),
|
||||||
ocsp_must_staple_critical=dict(type='bool', default=False, aliases=['ocspMustStaple_critical']),
|
ocsp_must_staple_critical=dict(type='bool', default=False, aliases=['ocspMustStaple_critical']),
|
||||||
backup=dict(type='bool', default=False),
|
backup=dict(type='bool', default=False),
|
||||||
|
create_subject_key_identifier=dict(type='bool', default=False),
|
||||||
|
subject_key_identifier=dict(type='str'),
|
||||||
|
authority_key_identifier=dict(type='str'),
|
||||||
|
authority_cert_issuer=dict(type='list', elements='str'),
|
||||||
|
authority_cert_serial_number=dict(type='int'),
|
||||||
select_crypto_backend=dict(type='str', default='auto', choices=['auto', 'cryptography', 'pyopenssl']),
|
select_crypto_backend=dict(type='str', default='auto', choices=['auto', 'cryptography', 'pyopenssl']),
|
||||||
),
|
),
|
||||||
|
required_together=[('authority_cert_issuer', 'authority_cert_serial_number')],
|
||||||
add_file_common_args=True,
|
add_file_common_args=True,
|
||||||
supports_check_mode=True,
|
supports_check_mode=True,
|
||||||
)
|
)
|
||||||
|
|
|
@ -160,10 +160,45 @@ public_key_fingerprints:
|
||||||
type: dict
|
type: dict
|
||||||
sample: "{'sha256': 'd4:b3:aa:6d:c8:04:ce:4e:ba:f6:29:4d:92:a3:94:b0:c2:ff:bd:bf:33:63:11:43:34:0f:51:b0:95:09:2f:63',
|
sample: "{'sha256': 'd4:b3:aa:6d:c8:04:ce:4e:ba:f6:29:4d:92:a3:94:b0:c2:ff:bd:bf:33:63:11:43:34:0f:51:b0:95:09:2f:63',
|
||||||
'sha512': 'f7:07:4a:f0:b0:f0:e6:8b:95:5f:f9:e6:61:0a:32:68:f1..."
|
'sha512': 'f7:07:4a:f0:b0:f0:e6:8b:95:5f:f9:e6:61:0a:32:68:f1..."
|
||||||
|
subject_key_identifier:
|
||||||
|
description:
|
||||||
|
- The CSR's subject key identifier.
|
||||||
|
- The identifier is returned in hexadecimal, with C(:) used to separate bytes.
|
||||||
|
- Is C(none) if the C(SubjectKeyIdentifier) extension is not present.
|
||||||
|
returned: success and if the pyOpenSSL backend is I(not) used
|
||||||
|
type: str
|
||||||
|
sample: '00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22:33'
|
||||||
|
version_added: "2.9"
|
||||||
|
authority_key_identifier:
|
||||||
|
description:
|
||||||
|
- The CSR's authority key identifier.
|
||||||
|
- The identifier is returned in hexadecimal, with C(:) used to separate bytes.
|
||||||
|
- Is C(none) if the C(AuthorityKeyIdentifier) extension is not present.
|
||||||
|
returned: success and if the pyOpenSSL backend is I(not) used
|
||||||
|
type: str
|
||||||
|
sample: '00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22:33'
|
||||||
|
version_added: "2.9"
|
||||||
|
authority_cert_issuer:
|
||||||
|
description:
|
||||||
|
- The CSR's authority cert issuer as a list of general names.
|
||||||
|
- Is C(none) if the C(AuthorityKeyIdentifier) extension is not present.
|
||||||
|
returned: success and if the pyOpenSSL backend is I(not) used
|
||||||
|
type: list
|
||||||
|
sample: "[DNS:www.ansible.com, IP:1.2.3.4]"
|
||||||
|
version_added: "2.9"
|
||||||
|
authority_cert_serial_number:
|
||||||
|
description:
|
||||||
|
- The CSR's authority cert serial number.
|
||||||
|
- Is C(none) if the C(AuthorityKeyIdentifier) extension is not present.
|
||||||
|
returned: success and if the pyOpenSSL backend is I(not) used
|
||||||
|
type: int
|
||||||
|
sample: '12345'
|
||||||
|
version_added: "2.9"
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
import abc
|
import abc
|
||||||
|
import binascii
|
||||||
import os
|
import os
|
||||||
import traceback
|
import traceback
|
||||||
from distutils.version import LooseVersion
|
from distutils.version import LooseVersion
|
||||||
|
@ -258,6 +293,14 @@ class CertificateSigningRequestInfo(crypto_utils.OpenSSLObject):
|
||||||
def _get_public_key(self, binary):
|
def _get_public_key(self, binary):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def _get_subject_key_identifier(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def _get_authority_key_identifier(self):
|
||||||
|
pass
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def _get_all_extensions(self):
|
def _get_all_extensions(self):
|
||||||
pass
|
pass
|
||||||
|
@ -285,6 +328,21 @@ class CertificateSigningRequestInfo(crypto_utils.OpenSSLObject):
|
||||||
pk = self._get_public_key(binary=True)
|
pk = self._get_public_key(binary=True)
|
||||||
result['public_key_fingerprints'] = crypto_utils.get_fingerprint_of_bytes(pk) if pk is not None else dict()
|
result['public_key_fingerprints'] = crypto_utils.get_fingerprint_of_bytes(pk) if pk is not None else dict()
|
||||||
|
|
||||||
|
if self.backend != 'pyopenssl':
|
||||||
|
ski = self._get_subject_key_identifier()
|
||||||
|
if ski is not None:
|
||||||
|
ski = to_native(binascii.hexlify(ski))
|
||||||
|
ski = ':'.join([ski[i:i + 2] for i in range(0, len(ski), 2)])
|
||||||
|
result['subject_key_identifier'] = ski
|
||||||
|
|
||||||
|
aki, aci, acsn = self._get_authority_key_identifier()
|
||||||
|
if aki is not None:
|
||||||
|
aki = to_native(binascii.hexlify(aki))
|
||||||
|
aki = ':'.join([aki[i:i + 2] for i in range(0, len(aki), 2)])
|
||||||
|
result['authority_key_identifier'] = aki
|
||||||
|
result['authority_cert_issuer'] = aci
|
||||||
|
result['authority_cert_serial_number'] = acsn
|
||||||
|
|
||||||
result['extensions_by_oid'] = self._get_all_extensions()
|
result['extensions_by_oid'] = self._get_all_extensions()
|
||||||
|
|
||||||
result['signature_valid'] = self._is_signature_valid()
|
result['signature_valid'] = self._is_signature_valid()
|
||||||
|
@ -394,6 +452,23 @@ class CertificateSigningRequestInfoCryptography(CertificateSigningRequestInfo):
|
||||||
serialization.PublicFormat.SubjectPublicKeyInfo
|
serialization.PublicFormat.SubjectPublicKeyInfo
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _get_subject_key_identifier(self):
|
||||||
|
try:
|
||||||
|
ext = self.csr.extensions.get_extension_for_class(x509.SubjectKeyIdentifier)
|
||||||
|
return ext.value.digest
|
||||||
|
except cryptography.x509.ExtensionNotFound:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _get_authority_key_identifier(self):
|
||||||
|
try:
|
||||||
|
ext = self.csr.extensions.get_extension_for_class(x509.AuthorityKeyIdentifier)
|
||||||
|
issuer = None
|
||||||
|
if ext.value.authority_cert_issuer is not None:
|
||||||
|
issuer = [crypto_utils.cryptography_decode_name(san) for san in ext.value.authority_cert_issuer]
|
||||||
|
return ext.value.key_identifier, issuer, ext.value.authority_cert_serial_number
|
||||||
|
except cryptography.x509.ExtensionNotFound:
|
||||||
|
return None, None, None
|
||||||
|
|
||||||
def _get_all_extensions(self):
|
def _get_all_extensions(self):
|
||||||
return crypto_utils.cryptography_get_extensions_from_csr(self.csr)
|
return crypto_utils.cryptography_get_extensions_from_csr(self.csr)
|
||||||
|
|
||||||
|
@ -486,6 +561,14 @@ class CertificateSigningRequestInfoPyOpenSSL(CertificateSigningRequestInfo):
|
||||||
self.module.warn('Your pyOpenSSL version does not support dumping public keys. '
|
self.module.warn('Your pyOpenSSL version does not support dumping public keys. '
|
||||||
'Please upgrade to version 16.0 or newer, or use the cryptography backend.')
|
'Please upgrade to version 16.0 or newer, or use the cryptography backend.')
|
||||||
|
|
||||||
|
def _get_subject_key_identifier(self):
|
||||||
|
# Won't be implemented
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _get_authority_key_identifier(self):
|
||||||
|
# Won't be implemented
|
||||||
|
return None, None, None
|
||||||
|
|
||||||
def _get_all_extensions(self):
|
def _get_all_extensions(self):
|
||||||
return crypto_utils.pyopenssl_get_extensions_from_csr(self.csr)
|
return crypto_utils.pyopenssl_get_extensions_from_csr(self.csr)
|
||||||
|
|
||||||
|
|
|
@ -308,4 +308,134 @@
|
||||||
select_crypto_backend: '{{ select_crypto_backend }}'
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
register: ownca_backup_5
|
register: ownca_backup_5
|
||||||
|
|
||||||
|
- name: (OwnCA, {{select_crypto_backend}}) Create subject key identifier
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/ownca_cert_ski.pem'
|
||||||
|
csr_path: '{{ output_dir }}/csr_ecc.csr'
|
||||||
|
ownca_path: '{{ output_dir }}/ca_cert.pem'
|
||||||
|
ownca_privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
provider: ownca
|
||||||
|
ownca_digest: sha256
|
||||||
|
ownca_create_subject_key_identifier: always_create
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: ownca_subject_key_identifier_1
|
||||||
|
|
||||||
|
- name: (OwnCA, {{select_crypto_backend}}) Create subject key identifier (idempotency)
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/ownca_cert_ski.pem'
|
||||||
|
csr_path: '{{ output_dir }}/csr_ecc.csr'
|
||||||
|
ownca_path: '{{ output_dir }}/ca_cert.pem'
|
||||||
|
ownca_privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
provider: ownca
|
||||||
|
ownca_digest: sha256
|
||||||
|
ownca_create_subject_key_identifier: always_create
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: ownca_subject_key_identifier_2
|
||||||
|
|
||||||
|
- name: (OwnCA, {{select_crypto_backend}}) Create subject key identifier (remove)
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/ownca_cert_ski.pem'
|
||||||
|
csr_path: '{{ output_dir }}/csr_ecc.csr'
|
||||||
|
ownca_path: '{{ output_dir }}/ca_cert.pem'
|
||||||
|
ownca_privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
provider: ownca
|
||||||
|
ownca_digest: sha256
|
||||||
|
ownca_create_subject_key_identifier: never_create
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: ownca_subject_key_identifier_3
|
||||||
|
|
||||||
|
- name: (OwnCA, {{select_crypto_backend}}) Create subject key identifier (remove idempotency)
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/ownca_cert_ski.pem'
|
||||||
|
csr_path: '{{ output_dir }}/csr_ecc.csr'
|
||||||
|
ownca_path: '{{ output_dir }}/ca_cert.pem'
|
||||||
|
ownca_privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
provider: ownca
|
||||||
|
ownca_digest: sha256
|
||||||
|
ownca_create_subject_key_identifier: never_create
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: ownca_subject_key_identifier_4
|
||||||
|
|
||||||
|
- name: (OwnCA, {{select_crypto_backend}}) Create subject key identifier (re-enable)
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/ownca_cert_ski.pem'
|
||||||
|
csr_path: '{{ output_dir }}/csr_ecc.csr'
|
||||||
|
ownca_path: '{{ output_dir }}/ca_cert.pem'
|
||||||
|
ownca_privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
provider: ownca
|
||||||
|
ownca_digest: sha256
|
||||||
|
ownca_create_subject_key_identifier: always_create
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: ownca_subject_key_identifier_5
|
||||||
|
|
||||||
|
- name: (OwnCA, {{select_crypto_backend}}) Create authority key identifier
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/ownca_cert_aki.pem'
|
||||||
|
csr_path: '{{ output_dir }}/csr_ecc.csr'
|
||||||
|
ownca_path: '{{ output_dir }}/ca_cert.pem'
|
||||||
|
ownca_privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
provider: ownca
|
||||||
|
ownca_digest: sha256
|
||||||
|
ownca_create_authority_key_identifier: yes
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: ownca_authority_key_identifier_1
|
||||||
|
|
||||||
|
- name: (OwnCA, {{select_crypto_backend}}) Create authority key identifier (idempotency)
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/ownca_cert_aki.pem'
|
||||||
|
csr_path: '{{ output_dir }}/csr_ecc.csr'
|
||||||
|
ownca_path: '{{ output_dir }}/ca_cert.pem'
|
||||||
|
ownca_privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
provider: ownca
|
||||||
|
ownca_digest: sha256
|
||||||
|
ownca_create_authority_key_identifier: yes
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: ownca_authority_key_identifier_2
|
||||||
|
|
||||||
|
- name: (OwnCA, {{select_crypto_backend}}) Create authority key identifier (remove)
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/ownca_cert_aki.pem'
|
||||||
|
csr_path: '{{ output_dir }}/csr_ecc.csr'
|
||||||
|
ownca_path: '{{ output_dir }}/ca_cert.pem'
|
||||||
|
ownca_privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
provider: ownca
|
||||||
|
ownca_digest: sha256
|
||||||
|
ownca_create_authority_key_identifier: no
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: ownca_authority_key_identifier_3
|
||||||
|
|
||||||
|
- name: (OwnCA, {{select_crypto_backend}}) Create authority key identifier (remove idempotency)
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/ownca_cert_aki.pem'
|
||||||
|
csr_path: '{{ output_dir }}/csr_ecc.csr'
|
||||||
|
ownca_path: '{{ output_dir }}/ca_cert.pem'
|
||||||
|
ownca_privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
provider: ownca
|
||||||
|
ownca_digest: sha256
|
||||||
|
ownca_create_authority_key_identifier: no
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: ownca_authority_key_identifier_4
|
||||||
|
|
||||||
|
- name: (OwnCA, {{select_crypto_backend}}) Create authority key identifier (re-add)
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/ownca_cert_aki.pem'
|
||||||
|
csr_path: '{{ output_dir }}/csr_ecc.csr'
|
||||||
|
ownca_path: '{{ output_dir }}/ca_cert.pem'
|
||||||
|
ownca_privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
provider: ownca
|
||||||
|
ownca_digest: sha256
|
||||||
|
ownca_create_authority_key_identifier: yes
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: ownca_authority_key_identifier_5
|
||||||
|
|
||||||
- import_tasks: ../tests/validate_ownca.yml
|
- import_tasks: ../tests/validate_ownca.yml
|
||||||
|
|
|
@ -308,4 +308,64 @@
|
||||||
select_crypto_backend: '{{ select_crypto_backend }}'
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
register: selfsigned_backup_5
|
register: selfsigned_backup_5
|
||||||
|
|
||||||
|
- name: (Selfsigned, {{select_crypto_backend}}) Create subject key identifier test
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/selfsigned_cert_ski.pem'
|
||||||
|
csr_path: '{{ output_dir }}/csr_ecc.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey_ecc.pem'
|
||||||
|
provider: selfsigned
|
||||||
|
selfsigned_digest: sha256
|
||||||
|
selfsigned_create_subject_key_identifier: always_create
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: selfsigned_subject_key_identifier_1
|
||||||
|
|
||||||
|
- name: (Selfsigned, {{select_crypto_backend}}) Create subject key identifier test (idempotency)
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/selfsigned_cert_ski.pem'
|
||||||
|
csr_path: '{{ output_dir }}/csr_ecc.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey_ecc.pem'
|
||||||
|
provider: selfsigned
|
||||||
|
selfsigned_digest: sha256
|
||||||
|
selfsigned_create_subject_key_identifier: always_create
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: selfsigned_subject_key_identifier_2
|
||||||
|
|
||||||
|
- name: (Selfsigned, {{select_crypto_backend}}) Create subject key identifier test (remove)
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/selfsigned_cert_ski.pem'
|
||||||
|
csr_path: '{{ output_dir }}/csr_ecc.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey_ecc.pem'
|
||||||
|
provider: selfsigned
|
||||||
|
selfsigned_digest: sha256
|
||||||
|
selfsigned_create_subject_key_identifier: never_create
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: selfsigned_subject_key_identifier_3
|
||||||
|
|
||||||
|
- name: (Selfsigned, {{select_crypto_backend}}) Create subject key identifier test (remove idempotency)
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/selfsigned_cert_ski.pem'
|
||||||
|
csr_path: '{{ output_dir }}/csr_ecc.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey_ecc.pem'
|
||||||
|
provider: selfsigned
|
||||||
|
selfsigned_digest: sha256
|
||||||
|
selfsigned_create_subject_key_identifier: never_create
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: selfsigned_subject_key_identifier_4
|
||||||
|
|
||||||
|
- name: (Selfsigned, {{select_crypto_backend}}) Create subject key identifier test (re-enable)
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/selfsigned_cert_ski.pem'
|
||||||
|
csr_path: '{{ output_dir }}/csr_ecc.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey_ecc.pem'
|
||||||
|
provider: selfsigned
|
||||||
|
selfsigned_digest: sha256
|
||||||
|
selfsigned_create_subject_key_identifier: always_create
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: selfsigned_subject_key_identifier_5
|
||||||
|
|
||||||
- import_tasks: ../tests/validate_selfsigned.yml
|
- import_tasks: ../tests/validate_selfsigned.yml
|
||||||
|
|
|
@ -120,3 +120,23 @@
|
||||||
- ownca_backup_4.backup_file is string
|
- ownca_backup_4.backup_file is string
|
||||||
- ownca_backup_5 is not changed
|
- ownca_backup_5 is not changed
|
||||||
- ownca_backup_5.backup_file is undefined
|
- ownca_backup_5.backup_file is undefined
|
||||||
|
|
||||||
|
- name: Check create subject key identifier
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- ownca_subject_key_identifier_1 is changed
|
||||||
|
- ownca_subject_key_identifier_2 is not changed
|
||||||
|
- ownca_subject_key_identifier_3 is changed
|
||||||
|
- ownca_subject_key_identifier_4 is not changed
|
||||||
|
- ownca_subject_key_identifier_5 is changed
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
|
||||||
|
- name: Check create authority key identifier
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- ownca_authority_key_identifier_1 is changed
|
||||||
|
- ownca_authority_key_identifier_2 is not changed
|
||||||
|
- ownca_authority_key_identifier_3 is changed
|
||||||
|
- ownca_authority_key_identifier_4 is not changed
|
||||||
|
- ownca_authority_key_identifier_5 is changed
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
|
|
@ -126,3 +126,13 @@
|
||||||
- selfsigned_backup_4.backup_file is string
|
- selfsigned_backup_4.backup_file is string
|
||||||
- selfsigned_backup_5 is not changed
|
- selfsigned_backup_5 is not changed
|
||||||
- selfsigned_backup_5.backup_file is undefined
|
- selfsigned_backup_5.backup_file is undefined
|
||||||
|
|
||||||
|
- name: Check create subject key identifier
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- selfsigned_subject_key_identifier_1 is changed
|
||||||
|
- selfsigned_subject_key_identifier_2 is not changed
|
||||||
|
- selfsigned_subject_key_identifier_3 is changed
|
||||||
|
- selfsigned_subject_key_identifier_4 is not changed
|
||||||
|
- selfsigned_subject_key_identifier_5 is changed
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
|
|
@ -18,6 +18,19 @@
|
||||||
- "['organizationalUnitName', 'Crypto Department'] in result.subject_ordered"
|
- "['organizationalUnitName', 'Crypto Department'] in result.subject_ordered"
|
||||||
- "['organizationalUnitName', 'ACME Department'] in result.subject_ordered"
|
- "['organizationalUnitName', 'ACME Department'] in result.subject_ordered"
|
||||||
|
|
||||||
|
- name: Check SubjectKeyIdentifier and AuthorityKeyIdentifier
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- result.subject_key_identifier == "00:11:22:33"
|
||||||
|
- result.authority_key_identifier == "44:55:66:77"
|
||||||
|
- result.authority_cert_issuer == expected_authority_cert_issuer
|
||||||
|
- result.authority_cert_serial_number == 12345
|
||||||
|
vars:
|
||||||
|
expected_authority_cert_issuer:
|
||||||
|
- "DNS:ca.example.org"
|
||||||
|
- "IP:1.2.3.4"
|
||||||
|
when: select_crypto_backend != 'pyopenssl' and cryptography_version.stdout is version('1.3', '>=')
|
||||||
|
|
||||||
- name: Update result list
|
- name: Update result list
|
||||||
set_fact:
|
set_fact:
|
||||||
info_results: "{{ info_results + [result] }}"
|
info_results: "{{ info_results + [result] }}"
|
||||||
|
@ -47,6 +60,18 @@
|
||||||
select_crypto_backend: '{{ select_crypto_backend }}'
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
|
- name: Check AuthorityKeyIdentifier
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- result.authority_key_identifier is none
|
||||||
|
- result.authority_cert_issuer == expected_authority_cert_issuer
|
||||||
|
- result.authority_cert_serial_number == 12345
|
||||||
|
vars:
|
||||||
|
expected_authority_cert_issuer:
|
||||||
|
- "DNS:ca.example.org"
|
||||||
|
- "IP:1.2.3.4"
|
||||||
|
when: select_crypto_backend != 'pyopenssl' and cryptography_version.stdout is version('1.3', '>=')
|
||||||
|
|
||||||
- name: Update result list
|
- name: Update result list
|
||||||
set_fact:
|
set_fact:
|
||||||
info_results: "{{ info_results + [result] }}"
|
info_results: "{{ info_results + [result] }}"
|
||||||
|
@ -57,6 +82,14 @@
|
||||||
select_crypto_backend: '{{ select_crypto_backend }}'
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
|
- name: Check AuthorityKeyIdentifier
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- result.authority_key_identifier == "44:55:66:77"
|
||||||
|
- result.authority_cert_issuer is none
|
||||||
|
- result.authority_cert_serial_number is none
|
||||||
|
when: select_crypto_backend != 'pyopenssl' and cryptography_version.stdout is version('1.3', '>=')
|
||||||
|
|
||||||
- name: Update result list
|
- name: Update result list
|
||||||
set_fact:
|
set_fact:
|
||||||
info_results: "{{ info_results + [result] }}"
|
info_results: "{{ info_results + [result] }}"
|
||||||
|
|
|
@ -69,6 +69,14 @@
|
||||||
- "pathlen:23"
|
- "pathlen:23"
|
||||||
basic_constraints_critical: yes
|
basic_constraints_critical: yes
|
||||||
ocsp_must_staple: yes
|
ocsp_must_staple: yes
|
||||||
|
subject_key_identifier: '{{ "00:11:22:33" if cryptography_version.stdout is version("1.3", ">=") else omit }}'
|
||||||
|
authority_key_identifier: '{{ "44:55:66:77" if cryptography_version.stdout is version("1.3", ">=") else omit }}'
|
||||||
|
authority_cert_issuer: '{{ value_for_authority_cert_issuer if cryptography_version.stdout is version("1.3", ">=") else omit }}'
|
||||||
|
authority_cert_serial_number: '{{ 12345 if cryptography_version.stdout is version("1.3", ">=") else omit }}'
|
||||||
|
vars:
|
||||||
|
value_for_authority_cert_issuer:
|
||||||
|
- "DNS:ca.example.org"
|
||||||
|
- "IP:1.2.3.4"
|
||||||
|
|
||||||
- name: Generate CSR 2
|
- name: Generate CSR 2
|
||||||
openssl_csr:
|
openssl_csr:
|
||||||
|
@ -90,12 +98,19 @@
|
||||||
- "IP:DEAD:BEEF::1"
|
- "IP:DEAD:BEEF::1"
|
||||||
basic_constraints:
|
basic_constraints:
|
||||||
- "CA:FALSE"
|
- "CA:FALSE"
|
||||||
|
authority_cert_issuer: '{{ value_for_authority_cert_issuer if cryptography_version.stdout is version("1.3", ">=") else omit }}'
|
||||||
|
authority_cert_serial_number: '{{ 12345 if cryptography_version.stdout is version("1.3", ">=") else omit }}'
|
||||||
|
vars:
|
||||||
|
value_for_authority_cert_issuer:
|
||||||
|
- "DNS:ca.example.org"
|
||||||
|
- "IP:1.2.3.4"
|
||||||
|
|
||||||
- name: Generate CSR 4
|
- name: Generate CSR 4
|
||||||
openssl_csr:
|
openssl_csr:
|
||||||
path: '{{ output_dir }}/csr_4.csr'
|
path: '{{ output_dir }}/csr_4.csr'
|
||||||
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
useCommonNameForSAN: no
|
useCommonNameForSAN: no
|
||||||
|
authority_key_identifier: '{{ "44:55:66:77" if cryptography_version.stdout is version("1.3", ">=") else omit }}'
|
||||||
|
|
||||||
- name: Generate selfsigned certificates
|
- name: Generate selfsigned certificates
|
||||||
openssl_certificate:
|
openssl_certificate:
|
||||||
|
@ -147,7 +162,14 @@
|
||||||
- name: Compare results
|
- name: Compare results
|
||||||
assert:
|
assert:
|
||||||
that:
|
that:
|
||||||
- item.0 == item.1
|
- ' (item.0 | dict2items | rejectattr("key", "in", keys_to_ignore) | list | items2dict)
|
||||||
|
== (item.1 | dict2items | rejectattr("key", "in", keys_to_ignore) | list | items2dict)'
|
||||||
quiet: yes
|
quiet: yes
|
||||||
loop: "{{ pyopenssl_info_results | zip(cryptography_info_results) | list }}"
|
loop: "{{ pyopenssl_info_results | zip(cryptography_info_results) | list }}"
|
||||||
when: pyopenssl_version.stdout is version('0.15', '>=') and cryptography_version.stdout is version('1.6', '>=')
|
when: pyopenssl_version.stdout is version('0.15', '>=') and cryptography_version.stdout is version('1.6', '>=')
|
||||||
|
vars:
|
||||||
|
keys_to_ignore:
|
||||||
|
- subject_key_identifier
|
||||||
|
- authority_key_identifier
|
||||||
|
- authority_cert_issuer
|
||||||
|
- authority_cert_serial_number
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
|
||||||
|
def compatibility_in_test(a, b):
|
||||||
|
return a in b
|
||||||
|
|
||||||
|
|
||||||
|
class TestModule:
|
||||||
|
''' Ansible math jinja2 tests '''
|
||||||
|
|
||||||
|
def tests(self):
|
||||||
|
return {
|
||||||
|
'in': compatibility_in_test,
|
||||||
|
}
|
|
@ -339,6 +339,179 @@
|
||||||
select_crypto_backend: '{{ select_crypto_backend }}'
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
register: csr_backup_5
|
register: csr_backup_5
|
||||||
|
|
||||||
|
- name: Generate CSR with subject key identifier
|
||||||
|
openssl_csr:
|
||||||
|
path: '{{ output_dir }}/csr_ski.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
subject:
|
||||||
|
commonName: www.ansible.com
|
||||||
|
subject_key_identifier: "00:11:22:33"
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: subject_key_identifier_1
|
||||||
|
|
||||||
|
- name: Generate CSR with subject key identifier (idempotency)
|
||||||
|
openssl_csr:
|
||||||
|
path: '{{ output_dir }}/csr_ski.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
subject:
|
||||||
|
commonName: www.ansible.com
|
||||||
|
subject_key_identifier: "00:11:22:33"
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: subject_key_identifier_2
|
||||||
|
|
||||||
|
- name: Generate CSR with subject key identifier (change)
|
||||||
|
openssl_csr:
|
||||||
|
path: '{{ output_dir }}/csr_ski.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
subject:
|
||||||
|
commonName: www.ansible.com
|
||||||
|
subject_key_identifier: "44:55:66:77:88"
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: subject_key_identifier_3
|
||||||
|
|
||||||
|
- name: Generate CSR with subject key identifier (auto-create)
|
||||||
|
openssl_csr:
|
||||||
|
path: '{{ output_dir }}/csr_ski.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
subject:
|
||||||
|
commonName: www.ansible.com
|
||||||
|
create_subject_key_identifier: yes
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: subject_key_identifier_4
|
||||||
|
|
||||||
|
- name: Generate CSR with subject key identifier (auto-create idempotency)
|
||||||
|
openssl_csr:
|
||||||
|
path: '{{ output_dir }}/csr_ski.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
subject:
|
||||||
|
commonName: www.ansible.com
|
||||||
|
create_subject_key_identifier: yes
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: subject_key_identifier_5
|
||||||
|
|
||||||
|
- name: Generate CSR with subject key identifier (remove)
|
||||||
|
openssl_csr:
|
||||||
|
path: '{{ output_dir }}/csr_ski.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
subject:
|
||||||
|
commonName: www.ansible.com
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: subject_key_identifier_6
|
||||||
|
|
||||||
|
- name: Generate CSR with authority key identifier
|
||||||
|
openssl_csr:
|
||||||
|
path: '{{ output_dir }}/csr_aki.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
subject:
|
||||||
|
commonName: www.ansible.com
|
||||||
|
authority_key_identifier: "00:11:22:33"
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: authority_key_identifier_1
|
||||||
|
|
||||||
|
- name: Generate CSR with authority key identifier (idempotency)
|
||||||
|
openssl_csr:
|
||||||
|
path: '{{ output_dir }}/csr_aki.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
subject:
|
||||||
|
commonName: www.ansible.com
|
||||||
|
authority_key_identifier: "00:11:22:33"
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: authority_key_identifier_2
|
||||||
|
|
||||||
|
- name: Generate CSR with authority key identifier (change)
|
||||||
|
openssl_csr:
|
||||||
|
path: '{{ output_dir }}/csr_aki.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
subject:
|
||||||
|
commonName: www.ansible.com
|
||||||
|
authority_key_identifier: "44:55:66:77:88"
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: authority_key_identifier_3
|
||||||
|
|
||||||
|
- name: Generate CSR with authority key identifier (remove)
|
||||||
|
openssl_csr:
|
||||||
|
path: '{{ output_dir }}/csr_aki.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
subject:
|
||||||
|
commonName: www.ansible.com
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: authority_key_identifier_4
|
||||||
|
|
||||||
|
- name: Generate CSR with authority cert issuer / serial number
|
||||||
|
openssl_csr:
|
||||||
|
path: '{{ output_dir }}/csr_acisn.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
subject:
|
||||||
|
commonName: www.ansible.com
|
||||||
|
authority_cert_issuer:
|
||||||
|
- "DNS:ca.example.org"
|
||||||
|
- "IP:1.2.3.4"
|
||||||
|
authority_cert_serial_number: 12345
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: authority_cert_issuer_sn_1
|
||||||
|
|
||||||
|
- name: Generate CSR with authority cert issuer / serial number (idempotency)
|
||||||
|
openssl_csr:
|
||||||
|
path: '{{ output_dir }}/csr_acisn.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
subject:
|
||||||
|
commonName: www.ansible.com
|
||||||
|
authority_cert_issuer:
|
||||||
|
- "DNS:ca.example.org"
|
||||||
|
- "IP:1.2.3.4"
|
||||||
|
authority_cert_serial_number: 12345
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: authority_cert_issuer_sn_2
|
||||||
|
|
||||||
|
- name: Generate CSR with authority cert issuer / serial number (change issuer)
|
||||||
|
openssl_csr:
|
||||||
|
path: '{{ output_dir }}/csr_acisn.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
subject:
|
||||||
|
commonName: www.ansible.com
|
||||||
|
authority_cert_issuer:
|
||||||
|
- "IP:1.2.3.4"
|
||||||
|
- "DNS:ca.example.org"
|
||||||
|
authority_cert_serial_number: 12345
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: authority_cert_issuer_sn_3
|
||||||
|
|
||||||
|
- name: Generate CSR with authority cert issuer / serial number (change serial number)
|
||||||
|
openssl_csr:
|
||||||
|
path: '{{ output_dir }}/csr_acisn.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
subject:
|
||||||
|
commonName: www.ansible.com
|
||||||
|
authority_cert_issuer:
|
||||||
|
- "IP:1.2.3.4"
|
||||||
|
- "DNS:ca.example.org"
|
||||||
|
authority_cert_serial_number: 54321
|
||||||
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: authority_cert_issuer_sn_4
|
||||||
|
|
||||||
|
- name: Generate CSR with authority cert issuer / serial number (remove)
|
||||||
|
openssl_csr:
|
||||||
|
path: '{{ output_dir }}/csr_acisn.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
subject:
|
||||||
|
commonName: www.ansible.com
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
register: authority_cert_issuer_sn_5
|
||||||
|
|
||||||
- name: Generate CSR with everything
|
- name: Generate CSR with everything
|
||||||
openssl_csr:
|
openssl_csr:
|
||||||
path: '{{ output_dir }}/csr_everything.csr'
|
path: '{{ output_dir }}/csr_everything.csr'
|
||||||
|
@ -396,7 +569,15 @@
|
||||||
- "pathlen:23"
|
- "pathlen:23"
|
||||||
basic_constraints_critical: yes
|
basic_constraints_critical: yes
|
||||||
ocsp_must_staple: yes
|
ocsp_must_staple: yes
|
||||||
|
subject_key_identifier: '{{ "00:11:22:33" if select_crypto_backend != "pyopenssl" else omit }}'
|
||||||
|
authority_key_identifier: '{{ "44:55:66:77" if select_crypto_backend != "pyopenssl" else omit }}'
|
||||||
|
authority_cert_issuer: '{{ value_for_authority_cert_issuer if select_crypto_backend != "pyopenssl" else omit }}'
|
||||||
|
authority_cert_serial_number: '{{ 12345 if select_crypto_backend != "pyopenssl" else omit }}'
|
||||||
select_crypto_backend: '{{ select_crypto_backend }}'
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
vars:
|
||||||
|
value_for_authority_cert_issuer:
|
||||||
|
- "DNS:ca.example.org"
|
||||||
|
- "IP:1.2.3.4"
|
||||||
register: everything_1
|
register: everything_1
|
||||||
|
|
||||||
- name: Generate CSR with everything (idempotent, check mode)
|
- name: Generate CSR with everything (idempotent, check mode)
|
||||||
|
@ -456,7 +637,15 @@
|
||||||
- "pathlen:23"
|
- "pathlen:23"
|
||||||
basic_constraints_critical: yes
|
basic_constraints_critical: yes
|
||||||
ocsp_must_staple: yes
|
ocsp_must_staple: yes
|
||||||
|
subject_key_identifier: '{{ "00:11:22:33" if select_crypto_backend != "pyopenssl" else omit }}'
|
||||||
|
authority_key_identifier: '{{ "44:55:66:77" if select_crypto_backend != "pyopenssl" else omit }}'
|
||||||
|
authority_cert_issuer: '{{ value_for_authority_cert_issuer if select_crypto_backend != "pyopenssl" else omit }}'
|
||||||
|
authority_cert_serial_number: '{{ 12345 if select_crypto_backend != "pyopenssl" else omit }}'
|
||||||
select_crypto_backend: '{{ select_crypto_backend }}'
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
vars:
|
||||||
|
value_for_authority_cert_issuer:
|
||||||
|
- "DNS:ca.example.org"
|
||||||
|
- "IP:1.2.3.4"
|
||||||
check_mode: yes
|
check_mode: yes
|
||||||
register: everything_2
|
register: everything_2
|
||||||
|
|
||||||
|
@ -517,5 +706,13 @@
|
||||||
- "pathlen:23"
|
- "pathlen:23"
|
||||||
basic_constraints_critical: yes
|
basic_constraints_critical: yes
|
||||||
ocsp_must_staple: yes
|
ocsp_must_staple: yes
|
||||||
|
subject_key_identifier: '{{ "00:11:22:33" if select_crypto_backend != "pyopenssl" else omit }}'
|
||||||
|
authority_key_identifier: '{{ "44:55:66:77" if select_crypto_backend != "pyopenssl" else omit }}'
|
||||||
|
authority_cert_issuer: '{{ value_for_authority_cert_issuer if select_crypto_backend != "pyopenssl" else omit }}'
|
||||||
|
authority_cert_serial_number: '{{ 12345 if select_crypto_backend != "pyopenssl" else omit }}'
|
||||||
select_crypto_backend: '{{ select_crypto_backend }}'
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
|
vars:
|
||||||
|
value_for_authority_cert_issuer:
|
||||||
|
- "DNS:ca.example.org"
|
||||||
|
- "IP:1.2.3.4"
|
||||||
register: everything_3
|
register: everything_3
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
select_crypto_backend: pyopenssl
|
select_crypto_backend: pyopenssl
|
||||||
|
|
||||||
- import_tasks: ../tests/validate.yml
|
- import_tasks: ../tests/validate.yml
|
||||||
|
vars:
|
||||||
|
select_crypto_backend: pyopenssl
|
||||||
|
|
||||||
when: pyopenssl_version.stdout is version('0.15', '>=')
|
when: pyopenssl_version.stdout is version('0.15', '>=')
|
||||||
|
|
||||||
|
@ -36,5 +38,7 @@
|
||||||
select_crypto_backend: cryptography
|
select_crypto_backend: cryptography
|
||||||
|
|
||||||
- import_tasks: ../tests/validate.yml
|
- import_tasks: ../tests/validate.yml
|
||||||
|
vars:
|
||||||
|
select_crypto_backend: pyopenssl
|
||||||
|
|
||||||
when: cryptography_version.stdout is version('1.3', '>=')
|
when: cryptography_version.stdout is version('1.3', '>=')
|
||||||
|
|
|
@ -125,6 +125,36 @@
|
||||||
that:
|
that:
|
||||||
- output_broken is changed
|
- output_broken is changed
|
||||||
|
|
||||||
|
- name: Verify that subject key identifier handling works
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- subject_key_identifier_1 is changed
|
||||||
|
- subject_key_identifier_2 is not changed
|
||||||
|
- subject_key_identifier_3 is changed
|
||||||
|
- subject_key_identifier_4 is changed
|
||||||
|
- subject_key_identifier_5 is not changed
|
||||||
|
- subject_key_identifier_6 is not changed
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
|
||||||
|
- name: Verify that authority key identifier handling works
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- authority_key_identifier_1 is changed
|
||||||
|
- authority_key_identifier_2 is not changed
|
||||||
|
- authority_key_identifier_3 is changed
|
||||||
|
- authority_key_identifier_4 is changed
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
|
||||||
|
- name: Verify that authority cert issuer / serial number handling works
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- authority_cert_issuer_sn_1 is changed
|
||||||
|
- authority_cert_issuer_sn_2 is not changed
|
||||||
|
- authority_cert_issuer_sn_3 is changed
|
||||||
|
- authority_cert_issuer_sn_4 is changed
|
||||||
|
- authority_cert_issuer_sn_5 is changed
|
||||||
|
when: select_crypto_backend != 'pyopenssl'
|
||||||
|
|
||||||
- name: Check backup
|
- name: Check backup
|
||||||
assert:
|
assert:
|
||||||
that:
|
that:
|
||||||
|
|
|
@ -15,6 +15,19 @@
|
||||||
- "['organizationalUnitName', 'Crypto Department'] in result.subject_ordered"
|
- "['organizationalUnitName', 'Crypto Department'] in result.subject_ordered"
|
||||||
- "['organizationalUnitName', 'ACME Department'] in result.subject_ordered"
|
- "['organizationalUnitName', 'ACME Department'] in result.subject_ordered"
|
||||||
|
|
||||||
|
- name: Check SubjectKeyIdentifier and AuthorityKeyIdentifier
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- result.subject_key_identifier == "00:11:22:33"
|
||||||
|
- result.authority_key_identifier == "44:55:66:77"
|
||||||
|
- result.authority_cert_issuer == expected_authority_cert_issuer
|
||||||
|
- result.authority_cert_serial_number == 12345
|
||||||
|
vars:
|
||||||
|
expected_authority_cert_issuer:
|
||||||
|
- "DNS:ca.example.org"
|
||||||
|
- "IP:1.2.3.4"
|
||||||
|
when: select_crypto_backend != 'pyopenssl' and cryptography_version.stdout is version('1.3', '>=')
|
||||||
|
|
||||||
- name: Update result list
|
- name: Update result list
|
||||||
set_fact:
|
set_fact:
|
||||||
info_results: "{{ info_results + [result] }}"
|
info_results: "{{ info_results + [result] }}"
|
||||||
|
@ -35,6 +48,18 @@
|
||||||
select_crypto_backend: '{{ select_crypto_backend }}'
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
|
- name: Check AuthorityKeyIdentifier
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- result.authority_key_identifier is none
|
||||||
|
- result.authority_cert_issuer == expected_authority_cert_issuer
|
||||||
|
- result.authority_cert_serial_number == 12345
|
||||||
|
vars:
|
||||||
|
expected_authority_cert_issuer:
|
||||||
|
- "DNS:ca.example.org"
|
||||||
|
- "IP:1.2.3.4"
|
||||||
|
when: select_crypto_backend != 'pyopenssl' and cryptography_version.stdout is version('1.3', '>=')
|
||||||
|
|
||||||
- name: Update result list
|
- name: Update result list
|
||||||
set_fact:
|
set_fact:
|
||||||
info_results: "{{ info_results + [result] }}"
|
info_results: "{{ info_results + [result] }}"
|
||||||
|
@ -45,6 +70,14 @@
|
||||||
select_crypto_backend: '{{ select_crypto_backend }}'
|
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
|
- name: Check AuthorityKeyIdentifier
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- result.authority_key_identifier == "44:55:66:77"
|
||||||
|
- result.authority_cert_issuer is none
|
||||||
|
- result.authority_cert_serial_number is none
|
||||||
|
when: select_crypto_backend != 'pyopenssl' and cryptography_version.stdout is version('1.3', '>=')
|
||||||
|
|
||||||
- name: Update result list
|
- name: Update result list
|
||||||
set_fact:
|
set_fact:
|
||||||
info_results: "{{ info_results + [result] }}"
|
info_results: "{{ info_results + [result] }}"
|
||||||
|
|
|
@ -69,6 +69,14 @@
|
||||||
- "pathlen:23"
|
- "pathlen:23"
|
||||||
basic_constraints_critical: yes
|
basic_constraints_critical: yes
|
||||||
ocsp_must_staple: yes
|
ocsp_must_staple: yes
|
||||||
|
subject_key_identifier: '{{ "00:11:22:33" if cryptography_version.stdout is version("1.3", ">=") else omit }}'
|
||||||
|
authority_key_identifier: '{{ "44:55:66:77" if cryptography_version.stdout is version("1.3", ">=") else omit }}'
|
||||||
|
authority_cert_issuer: '{{ value_for_authority_cert_issuer if cryptography_version.stdout is version("1.3", ">=") else omit }}'
|
||||||
|
authority_cert_serial_number: '{{ 12345 if cryptography_version.stdout is version("1.3", ">=") else omit }}'
|
||||||
|
vars:
|
||||||
|
value_for_authority_cert_issuer:
|
||||||
|
- "DNS:ca.example.org"
|
||||||
|
- "IP:1.2.3.4"
|
||||||
|
|
||||||
- name: Generate CSR 2
|
- name: Generate CSR 2
|
||||||
openssl_csr:
|
openssl_csr:
|
||||||
|
@ -90,12 +98,19 @@
|
||||||
- "IP:DEAD:BEEF::1"
|
- "IP:DEAD:BEEF::1"
|
||||||
basic_constraints:
|
basic_constraints:
|
||||||
- "CA:FALSE"
|
- "CA:FALSE"
|
||||||
|
authority_cert_issuer: '{{ value_for_authority_cert_issuer if cryptography_version.stdout is version("1.3", ">=") else omit }}'
|
||||||
|
authority_cert_serial_number: '{{ 12345 if cryptography_version.stdout is version("1.3", ">=") else omit }}'
|
||||||
|
vars:
|
||||||
|
value_for_authority_cert_issuer:
|
||||||
|
- "DNS:ca.example.org"
|
||||||
|
- "IP:1.2.3.4"
|
||||||
|
|
||||||
- name: Generate CSR 4
|
- name: Generate CSR 4
|
||||||
openssl_csr:
|
openssl_csr:
|
||||||
path: '{{ output_dir }}/csr_4.csr'
|
path: '{{ output_dir }}/csr_4.csr'
|
||||||
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
useCommonNameForSAN: no
|
useCommonNameForSAN: no
|
||||||
|
authority_key_identifier: '{{ "44:55:66:77" if cryptography_version.stdout is version("1.3", ">=") else omit }}'
|
||||||
|
|
||||||
- name: Prepare result list
|
- name: Prepare result list
|
||||||
set_fact:
|
set_fact:
|
||||||
|
@ -132,7 +147,14 @@
|
||||||
- name: Compare results
|
- name: Compare results
|
||||||
assert:
|
assert:
|
||||||
that:
|
that:
|
||||||
- item.0 == item.1
|
- ' (item.0 | dict2items | rejectattr("key", "in", keys_to_ignore) | list | items2dict)
|
||||||
|
== (item.1 | dict2items | rejectattr("key", "in", keys_to_ignore) | list | items2dict)'
|
||||||
quiet: yes
|
quiet: yes
|
||||||
loop: "{{ pyopenssl_info_results | zip(cryptography_info_results) | list }}"
|
loop: "{{ pyopenssl_info_results | zip(cryptography_info_results) | list }}"
|
||||||
when: pyopenssl_version.stdout is version('0.15', '>=') and cryptography_version.stdout is version('1.3', '>=')
|
when: pyopenssl_version.stdout is version('0.15', '>=') and cryptography_version.stdout is version('1.3', '>=')
|
||||||
|
vars:
|
||||||
|
keys_to_ignore:
|
||||||
|
- subject_key_identifier
|
||||||
|
- authority_key_identifier
|
||||||
|
- authority_cert_issuer
|
||||||
|
- authority_cert_serial_number
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
|
||||||
|
def compatibility_in_test(a, b):
|
||||||
|
return a in b
|
||||||
|
|
||||||
|
|
||||||
|
class TestModule:
|
||||||
|
''' Ansible math jinja2 tests '''
|
||||||
|
|
||||||
|
def tests(self):
|
||||||
|
return {
|
||||||
|
'in': compatibility_in_test,
|
||||||
|
}
|
Loading…
Reference in a new issue