openssl_csr: Allow user to specify criticality of extensions (#28173)
Allow user to mark the x509v3 extensions as critical, by specifying the $extension_critical boolean, where $extension is the name of the extension. Currently this module supports only 3 differents x509v3 extensions: * keyUsage * extendedKeyUsage * subjectAtlName There are more to come.
This commit is contained in:
parent
f668f41822
commit
8ed7417ff9
1 changed files with 31 additions and 12 deletions
|
@ -103,12 +103,20 @@ options:
|
||||||
description:
|
description:
|
||||||
- SAN extension to attach to the certificate signing request
|
- SAN extension to attach to the certificate signing request
|
||||||
- This can either be a 'comma separated string' or a YAML list.
|
- This can either be a 'comma separated string' or a YAML list.
|
||||||
|
subjectAltName_critical:
|
||||||
|
required: false
|
||||||
|
description:
|
||||||
|
- Should the subjectAltName extension be considered as critical
|
||||||
keyUsage:
|
keyUsage:
|
||||||
required: false
|
required: false
|
||||||
description:
|
description:
|
||||||
- This defines the purpose (e.g. encipherment, signature, certificate signing)
|
- This defines the purpose (e.g. encipherment, signature, certificate signing)
|
||||||
of the key contained in the certificate.
|
of the key contained in the certificate.
|
||||||
- This can either be a 'comma separated string' or a YAML list.
|
- This can either be a 'comma separated string' or a YAML list.
|
||||||
|
keyUsage_critical:
|
||||||
|
required: false
|
||||||
|
description:
|
||||||
|
- Should the keyUsage extension be considered as critical
|
||||||
extendedKeyUsage:
|
extendedKeyUsage:
|
||||||
required: false
|
required: false
|
||||||
aliases: [ 'extKeyUsage' ]
|
aliases: [ 'extKeyUsage' ]
|
||||||
|
@ -116,6 +124,11 @@ options:
|
||||||
- Additional restrictions (e.g. client authentication, server authentication)
|
- Additional restrictions (e.g. client authentication, server authentication)
|
||||||
on the allowed purposes for which the public key may be used.
|
on the allowed purposes for which the public key may be used.
|
||||||
- This can either be a 'comma separated string' or a YAML list.
|
- This can either be a 'comma separated string' or a YAML list.
|
||||||
|
extendedKeyUsage_critical:
|
||||||
|
required: false
|
||||||
|
aliases: [ 'extKeyUsage_critical' ]
|
||||||
|
description:
|
||||||
|
- Should the extkeyUsage extension be considered as critical
|
||||||
|
|
||||||
notes:
|
notes:
|
||||||
- "If the certificate signing request already exists it will be checked whether subjectAltName,
|
- "If the certificate signing request already exists it will be checked whether subjectAltName,
|
||||||
|
@ -239,8 +252,11 @@ class CertificateSigningRequest(crypto_utils.OpenSSLObject):
|
||||||
self.privatekey_passphrase = module.params['privatekey_passphrase']
|
self.privatekey_passphrase = module.params['privatekey_passphrase']
|
||||||
self.version = module.params['version']
|
self.version = module.params['version']
|
||||||
self.subjectAltName = module.params['subjectAltName']
|
self.subjectAltName = module.params['subjectAltName']
|
||||||
|
self.subjectAltName_critical = module.params['subjectAltName_critical']
|
||||||
self.keyUsage = module.params['keyUsage']
|
self.keyUsage = module.params['keyUsage']
|
||||||
|
self.keyUsage_critical = module.params['keyUsage_critical']
|
||||||
self.extendedKeyUsage = module.params['extendedKeyUsage']
|
self.extendedKeyUsage = module.params['extendedKeyUsage']
|
||||||
|
self.extendedKeyUsage_critical = module.params['extendedKeyUsage_critical']
|
||||||
self.request = None
|
self.request = None
|
||||||
self.privatekey = None
|
self.privatekey = None
|
||||||
|
|
||||||
|
@ -271,15 +287,15 @@ class CertificateSigningRequest(crypto_utils.OpenSSLObject):
|
||||||
setattr(subject, key, value)
|
setattr(subject, key, value)
|
||||||
|
|
||||||
altnames = ', '.join(self.subjectAltName)
|
altnames = ', '.join(self.subjectAltName)
|
||||||
extensions = [crypto.X509Extension(b"subjectAltName", False, altnames.encode('ascii'))]
|
extensions = [crypto.X509Extension(b"subjectAltName", self.subjectAltName_critical, altnames.encode('ascii'))]
|
||||||
|
|
||||||
if self.keyUsage:
|
if self.keyUsage:
|
||||||
usages = ', '.join(self.keyUsage)
|
usages = ', '.join(self.keyUsage)
|
||||||
extensions.append(crypto.X509Extension(b"keyUsage", False, usages.encode('ascii')))
|
extensions.append(crypto.X509Extension(b"keyUsage", self.keyUsage_critical, usages.encode('ascii')))
|
||||||
|
|
||||||
if self.extendedKeyUsage:
|
if self.extendedKeyUsage:
|
||||||
usages = ', '.join(self.extendedKeyUsage)
|
usages = ', '.join(self.extendedKeyUsage)
|
||||||
extensions.append(crypto.X509Extension(b"extendedKeyUsage", False, usages.encode('ascii')))
|
extensions.append(crypto.X509Extension(b"extendedKeyUsage", self.extendedKeyUsage_critical, usages.encode('ascii')))
|
||||||
|
|
||||||
req.add_extensions(extensions)
|
req.add_extensions(extensions)
|
||||||
|
|
||||||
|
@ -315,13 +331,13 @@ class CertificateSigningRequest(crypto_utils.OpenSSLObject):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _check_subjectAltName(extensions):
|
def _check_subjectAltName(extensions):
|
||||||
altnames_ext = next((ext.__str__() for ext in extensions if ext.get_short_name() == b'subjectAltName'), '')
|
altnames_ext = next((ext for ext in extensions if ext.get_short_name() == b'subjectAltName'), '')
|
||||||
altnames = [altname.strip() for altname in altnames_ext.split(',')]
|
altnames = [altname.strip() for altname in str(altnames_ext).split(',')]
|
||||||
# apperently openssl returns 'IP address' not 'IP' as specifier when converting the subjectAltName to string
|
# apperently openssl returns 'IP address' not 'IP' as specifier when converting the subjectAltName to string
|
||||||
# although it won't accept this specifier when generating the CSR. (https://github.com/openssl/openssl/issues/4004)
|
# although it won't accept this specifier when generating the CSR. (https://github.com/openssl/openssl/issues/4004)
|
||||||
altnames = [name if not name.startswith('IP Address:') else "IP:" + name.split(':', 1)[1] for name in altnames]
|
altnames = [name if not name.startswith('IP Address:') else "IP:" + name.split(':', 1)[1] for name in altnames]
|
||||||
if self.subjectAltName:
|
if self.subjectAltName:
|
||||||
if set(altnames) != set(self.subjectAltName):
|
if set(altnames) != set(self.subjectAltName) or altnames_ext.get_critical() != self.subjectAltName_critical:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
if altnames:
|
if altnames:
|
||||||
|
@ -329,22 +345,22 @@ class CertificateSigningRequest(crypto_utils.OpenSSLObject):
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _check_keyUsage_(extensions, extName, expected, long):
|
def _check_keyUsage_(extensions, extName, expected, critical, long):
|
||||||
usages_ext = [str(ext) for ext in extensions if ext.get_short_name() == extName]
|
usages_ext = [ext for ext in extensions if ext.get_short_name() == extName]
|
||||||
if (not usages_ext and expected) or (usages_ext and not expected):
|
if (not usages_ext and expected) or (usages_ext and not expected):
|
||||||
return False
|
return False
|
||||||
elif not usages_ext and not expected:
|
elif not usages_ext and not expected:
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
current = [usage.strip() for usage in usages_ext[0].split(',')]
|
current = [usage.strip() for usage in str(usages_ext[0]).split(',')]
|
||||||
expected = [long[usage] if usage in long else usage for usage in expected]
|
expected = [long[usage] if usage in long else usage for usage in expected]
|
||||||
return current == expected
|
return current == expected and usages_ext[0].get_critical() == critical
|
||||||
|
|
||||||
def _check_keyUsage(extensions):
|
def _check_keyUsage(extensions):
|
||||||
return _check_keyUsage_(extensions, b'keyUsage', self.keyUsage, crypto_utils.keyUsageLong)
|
return _check_keyUsage_(extensions, b'keyUsage', self.keyUsage, self.keyUsage_critical, crypto_utils.keyUsageLong)
|
||||||
|
|
||||||
def _check_extenededKeyUsage(extensions):
|
def _check_extenededKeyUsage(extensions):
|
||||||
return _check_keyUsage_(extensions, b'extendedKeyUsage', self.extendedKeyUsage, crypto_utils.extendedKeyUsageLong)
|
return _check_keyUsage_(extensions, b'extendedKeyUsage', self.extendedKeyUsage, self.extendedKeyUsage_critical, crypto_utils.extendedKeyUsageLong)
|
||||||
|
|
||||||
def _check_extensions(csr):
|
def _check_extensions(csr):
|
||||||
extensions = csr.get_extensions()
|
extensions = csr.get_extensions()
|
||||||
|
@ -397,8 +413,11 @@ def main():
|
||||||
commonName=dict(aliases=['CN'], type='str'),
|
commonName=dict(aliases=['CN'], type='str'),
|
||||||
emailAddress=dict(aliases=['E'], type='str'),
|
emailAddress=dict(aliases=['E'], type='str'),
|
||||||
subjectAltName=dict(type='list'),
|
subjectAltName=dict(type='list'),
|
||||||
|
subjectAltName_critical=dict(default=False, type='bool'),
|
||||||
keyUsage=dict(type='list'),
|
keyUsage=dict(type='list'),
|
||||||
|
keyUsage_critical=dict(default=False, type='bool'),
|
||||||
extendedKeyUsage=dict(aliases=['extKeyUsage'], type='list'),
|
extendedKeyUsage=dict(aliases=['extKeyUsage'], type='list'),
|
||||||
|
extendedKeyUsage_critical=dict(default=False, aliases=['extKeyUsage_critical'], type='bool'),
|
||||||
),
|
),
|
||||||
add_file_common_args=True,
|
add_file_common_args=True,
|
||||||
supports_check_mode=True,
|
supports_check_mode=True,
|
||||||
|
|
Loading…
Reference in a new issue