openssl_csr: added support for the OCSP Must Staple extension (#35082)
* Added support for the OCSP Must Staple extension. * Trying to clean up magic constants a bit.
This commit is contained in:
parent
273a3d1d51
commit
d1f19125a5
3 changed files with 93 additions and 5 deletions
|
@ -22,7 +22,8 @@ short_description: Generate OpenSSL Certificate Signing Request (CSR)
|
|||
description:
|
||||
- "This module allows one to (re)generate OpenSSL certificate signing requests.
|
||||
It uses the pyOpenSSL python library to interact with openssl. This module supports
|
||||
the subjectAltName as well as the keyUsage and extendedKeyUsage extensions."
|
||||
the subjectAltName, keyUsage, extendedKeyUsage, basicConstraints and OCSP Must Staple
|
||||
extensions."
|
||||
requirements:
|
||||
- "python-pyOpenSSL >= 0.15"
|
||||
options:
|
||||
|
@ -148,12 +149,29 @@ options:
|
|||
description:
|
||||
- Should the basicConstraints extension be considered as critical
|
||||
version_added: 2.5
|
||||
ocsp_must_staple:
|
||||
required: false
|
||||
aliases: ['ocspMustStaple']
|
||||
description:
|
||||
- Indicates that the certificate should contain the OCSP Must Staple
|
||||
extension (U(https://tools.ietf.org/html/rfc7633)).
|
||||
version_added: 2.5
|
||||
ocsp_must_staple_critical:
|
||||
required: false
|
||||
aliases: [ 'ocspMustStaple_critical' ]
|
||||
description:
|
||||
- Should the OCSP Must Staple extension be considered as critical
|
||||
- "Warning: according to the RFC, this extension should not be marked
|
||||
as critical, as old clients not knowing about OCSP Must Staple
|
||||
are required to reject such certificates
|
||||
(see U(https://tools.ietf.org/html/rfc7633#section-4))."
|
||||
version_added: 2.5
|
||||
extends_documentation_fragment: files
|
||||
|
||||
notes:
|
||||
- "If the certificate signing request already exists it will be checked whether subjectAltName,
|
||||
keyUsage and extendedKeyUsage only contain the requested values and if the request was signed
|
||||
by the given private key"
|
||||
keyUsage, extendedKeyUsage and basicConstraints only contain the requested values, whether
|
||||
OCSP Must Staple is as requested, and if the request was signed by the given private key."
|
||||
'''
|
||||
|
||||
|
||||
|
@ -204,6 +222,13 @@ EXAMPLES = '''
|
|||
- keyAgreement
|
||||
extended_key_usage:
|
||||
- clientAuth
|
||||
|
||||
# Generate an OpenSSL Certificate Signing Request with OCSP Must Staple
|
||||
- openssl_csr:
|
||||
path: /etc/ssl/csr/www.ansible.com.csr
|
||||
privatekey_path: /etc/ssl/private/ansible.com.pem
|
||||
common_name: www.ansible.com
|
||||
ocsp_must_staple: true
|
||||
'''
|
||||
|
||||
|
||||
|
@ -243,6 +268,12 @@ basicConstraints:
|
|||
returned: changed or success
|
||||
type: list
|
||||
sample: ['CA:TRUE', 'pathLenConstraint:0']
|
||||
ocsp_must_staple:
|
||||
description: Indicates whether the certificate has the OCSP
|
||||
Must Staple feature enabled
|
||||
returned: changed or success
|
||||
type: bool
|
||||
sample: false
|
||||
'''
|
||||
|
||||
import os
|
||||
|
@ -258,6 +289,14 @@ except ImportError:
|
|||
pyopenssl_found = False
|
||||
else:
|
||||
pyopenssl_found = True
|
||||
if OpenSSL.SSL.OPENSSL_VERSION_NUMBER >= 0x10100000:
|
||||
# OpenSSL 1.1.0 or newer
|
||||
MUST_STAPLE_NAME = b"tlsfeature"
|
||||
MUST_STAPLE_VALUE = b"status_request"
|
||||
else:
|
||||
# OpenSSL 1.0.x or older
|
||||
MUST_STAPLE_NAME = b"1.3.6.1.5.5.7.1.24"
|
||||
MUST_STAPLE_VALUE = b"DER:30:03:02:01:05"
|
||||
|
||||
|
||||
class CertificateSigningRequestError(crypto_utils.OpenSSLObjectError):
|
||||
|
@ -285,6 +324,8 @@ class CertificateSigningRequest(crypto_utils.OpenSSLObject):
|
|||
self.extendedKeyUsage_critical = module.params['extendedKeyUsage_critical']
|
||||
self.basicConstraints = module.params['basicConstraints']
|
||||
self.basicConstraints_critical = module.params['basicConstraints_critical']
|
||||
self.ocspMustStaple = module.params['ocspMustStaple']
|
||||
self.ocspMustStaple_critical = module.params['ocspMustStaple_critical']
|
||||
self.request = None
|
||||
self.privatekey = None
|
||||
|
||||
|
@ -338,6 +379,9 @@ class CertificateSigningRequest(crypto_utils.OpenSSLObject):
|
|||
usages = ', '.join(self.basicConstraints)
|
||||
extensions.append(crypto.X509Extension(b"basicConstraints", self.basicConstraints_critical, usages.encode('ascii')))
|
||||
|
||||
if self.ocspMustStaple:
|
||||
extensions.append(crypto.X509Extension(MUST_STAPLE_NAME, self.ocspMustStaple_critical, MUST_STAPLE_VALUE))
|
||||
|
||||
if extensions:
|
||||
req.add_extensions(extensions)
|
||||
|
||||
|
@ -407,10 +451,21 @@ class CertificateSigningRequest(crypto_utils.OpenSSLObject):
|
|||
def _check_basicConstraints(extensions):
|
||||
return _check_keyUsage_(extensions, b'basicConstraints', self.basicConstraints, self.basicConstraints_critical)
|
||||
|
||||
def _check_ocspMustStaple(extensions):
|
||||
oms_ext = [ext for ext in extensions if ext.get_short_name() == MUST_STAPLE_NAME and str(ext) == MUST_STAPLE_VALUE]
|
||||
if OpenSSL.SSL.OPENSSL_VERSION_NUMBER < 0x10100000:
|
||||
# Older versions of libssl don't know about OCSP Must Staple
|
||||
oms_ext.extend([ext for ext in extensions if ext.get_short_name() == b'UNDEF' and ext.get_data() == b'\x30\x03\x02\x01\x05'])
|
||||
if self.ocspMustStaple:
|
||||
return len(oms_ext) > 0 and oms_ext[0].get_critical() == self.ocspMustStaple_critical
|
||||
else:
|
||||
return len(oms_ext) == 0
|
||||
|
||||
def _check_extensions(csr):
|
||||
extensions = csr.get_extensions()
|
||||
return (_check_subjectAltName(extensions) and _check_keyUsage(extensions) and
|
||||
_check_extenededKeyUsage(extensions) and _check_basicConstraints(extensions))
|
||||
_check_extenededKeyUsage(extensions) and _check_basicConstraints(extensions) and
|
||||
_check_ocspMustStaple(extensions))
|
||||
|
||||
def _check_signature(csr):
|
||||
try:
|
||||
|
@ -436,6 +491,7 @@ class CertificateSigningRequest(crypto_utils.OpenSSLObject):
|
|||
'keyUsage': self.keyUsage,
|
||||
'extendedKeyUsage': self.extendedKeyUsage,
|
||||
'basicConstraints': self.basicConstraints,
|
||||
'ocspMustStaple': self.ocspMustStaple,
|
||||
'changed': self.changed
|
||||
}
|
||||
|
||||
|
@ -468,6 +524,8 @@ def main():
|
|||
extendedKeyUsage_critical=dict(aliases=['extKeyUsage_critical', 'extended_key_usage_critical'], default=False, type='bool'),
|
||||
basicConstraints=dict(aliases=['basic_constraints'], type='list'),
|
||||
basicConstraints_critical=dict(aliases=['basic_constraints_critical'], default=False, type='bool'),
|
||||
ocspMustStaple=dict(aliases=['ocsp_must_staple'], default=False, type='bool'),
|
||||
ocspMustStaple_critical=dict(aliases=['ocsp_must_staple_critical'], default=False, type='bool'),
|
||||
),
|
||||
add_file_common_args=True,
|
||||
supports_check_mode=True,
|
||||
|
|
|
@ -51,6 +51,21 @@
|
|||
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||
commonName: www.ansible.com
|
||||
|
||||
- name: Generate CSR with OCSP Must Staple
|
||||
openssl_csr:
|
||||
path: '{{ output_dir }}/csr_ocsp.csr'
|
||||
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||
subject_alt_name: "DNS:www.ansible.com"
|
||||
ocsp_must_staple: true
|
||||
|
||||
- name: Generate CSR with OCSP Must Staple (test idempotency)
|
||||
openssl_csr:
|
||||
path: '{{ output_dir }}/csr_ocsp.csr'
|
||||
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||
subject_alt_name: "DNS:www.ansible.com"
|
||||
ocsp_must_staple: true
|
||||
register: csr_ocsp_idempotency
|
||||
|
||||
- import_tasks: ../tests/validate.yml
|
||||
|
||||
when: pyopenssl_version.stdout is version('0.15', '>=')
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
- name: Validate CSR_KU_XKU (assert idempotency)
|
||||
assert:
|
||||
that:
|
||||
- csr_ku_xku.changed == False
|
||||
- csr_ku_xku is not changed
|
||||
|
||||
- name: Validate old_API CSR (test - Common Name)
|
||||
shell: "openssl req -noout -subject -in {{ output_dir }}/csr_oldapi.csr -nameopt oneline,-space_eq"
|
||||
|
@ -34,3 +34,18 @@
|
|||
that:
|
||||
- csr_oldapi_cn.stdout.split('=')[-1] == 'www.ansible.com'
|
||||
- csr_oldapi_modulus.stdout == privatekey_modulus.stdout
|
||||
|
||||
- name: Validate OCSP Must Staple CSR (test - everything)
|
||||
shell: "openssl req -noout -in {{ output_dir }}/csr_ocsp.csr -text"
|
||||
register: csr_ocsp
|
||||
|
||||
- name: Validate OCSP Must Staple CSR (assert)
|
||||
assert:
|
||||
that:
|
||||
- "(csr_ocsp.stdout is search('\\s+TLS Feature:\\s*\\n\\s+status_request\\s+')) or
|
||||
(csr_ocsp.stdout is search('\\s+1.3.6.1.5.5.7.1.24:\\s*\\n\\s+0\\.\\.\\.\\.\\s+'))"
|
||||
|
||||
- name: Validate OCSP Must Staple CSR (assert idempotency)
|
||||
assert:
|
||||
that:
|
||||
- csr_ocsp_idempotency is not changed
|
||||
|
|
Loading…
Reference in a new issue