Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable TLS/SSL CTX Options for the get_certificate Module #779

Merged
merged 11 commits into from
Jul 7, 2024
4 changes: 4 additions & 0 deletions changelogs/fragments/779-add-ssl_ctx_options-option.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
minor_changes:
- get_certificate - adds `ssl_ctx_options` option for specifying SSL CTX options (https://github.com/ansible-collections/community.crypto/pull/779).
dlehrman marked this conversation as resolved.
Show resolved Hide resolved
...
46 changes: 46 additions & 0 deletions plugins/modules/get_certificate.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,14 @@
- The default value V(false) is B(deprecated) and will change to V(true) in community.crypto 3.0.0.
type: bool
version_added: 2.12.0
ssl_ctx_options:
dlehrman marked this conversation as resolved.
Show resolved Hide resolved
description:
- SSL CTX options (SSL OP flags) to use for the request.
- See the L(List of SSL OP Flags,https://wiki.openssl.org/index.php/List_of_SSL_OP_Flags) for more details.
- The available SSL CTX options is dependent on the Python and OpenSSL/LibreSSL versions.
type: list
elements: [ str, int ]
dlehrman marked this conversation as resolved.
Show resolved Hide resolved
version_added: tbd
dlehrman marked this conversation as resolved.
Show resolved Hide resolved

notes:
- When using ca_cert on OS X it has been reported that in some conditions the validate will always succeed.
Expand Down Expand Up @@ -205,11 +213,29 @@
msg: "cert expires in: {{ expire_days }} days."
vars:
expire_days: "{{ (( cert.not_after | to_datetime('%Y%m%d%H%M%SZ')) - (ansible_date_time.iso8601 | to_datetime('%Y-%m-%dT%H:%M:%SZ')) ).days }}"

- name: Allow legacy insecure renegotiation to get a cert from a legacy device
community.crypto.get_certificate:
host: "legacy-device.domain.com"
port: 443
ciphers:
- HIGH
ssl_ctx_options:
- OP_ALL
- OP_NO_SSLv3
- OP_CIPHER_SERVER_PREFERENCE
- OP_ENABLE_MIDDLEBOX_COMPAT
- OP_NO_COMPRESSION
- 4 # OP_LEGACY_SERVER_CONNECT
delegate_to: localhost
run_once: true
register: legacy_cert
'''

import atexit
import base64
import traceback
import ssl

from os.path import isfile
from socket import create_connection, setdefaulttimeout, socket
Expand Down Expand Up @@ -285,6 +311,7 @@ def main():
starttls=dict(type='str', choices=['mysql']),
ciphers=dict(type='list', elements='str'),
asn1_base64=dict(type='bool'),
ssl_ctx_options=dict(type='list', default=None),
dlehrman marked this conversation as resolved.
Show resolved Hide resolved
),
)

Expand All @@ -298,6 +325,7 @@ def main():
start_tls_server_type = module.params.get('starttls')
ciphers = module.params.get('ciphers')
asn1_base64 = module.params['asn1_base64']
ssl_ctx_options = module.params.get('ssl_ctx_options')
if asn1_base64 is None:
module.deprecate(
'The default value `false` for asn1_base64 is deprecated and will change to `true` in '
Expand Down Expand Up @@ -346,6 +374,9 @@ def main():
if ciphers is not None:
module.fail_json(msg='To use ciphers, you must run the get_certificate module with Python 2.7 or newer.',
exception=CREATE_DEFAULT_CONTEXT_IMP_ERR)
if ssl_ctx_options is not None:
module.fail_json(msg='To use ssl_ctx_options, you must run the get_certificate module with Python 2.7 or newer.',
exception=CREATE_DEFAULT_CONTEXT_IMP_ERR)
try:
# Note: get_server_certificate does not support SNI!
cert = get_server_certificate((host, port), ca_certs=ca_cert)
Expand Down Expand Up @@ -381,6 +412,21 @@ def main():
ciphers_joined = ":".join(ciphers)
ctx.set_ciphers(ciphers_joined)

if ssl_ctx_options is not None:
# Clear default options
ctx.options = 0

# For each item in the ssl_ctx_options list
for ssl_ctx_option in ssl_ctx_options:
# If the item is a string
if isinstance(ssl_ctx_option, str):
dlehrman marked this conversation as resolved.
Show resolved Hide resolved
# Get the int value for the option and add it to ctx options
ctx.options |= getattr(ssl, ssl_ctx_option)
dlehrman marked this conversation as resolved.
Show resolved Hide resolved
# If the item is an integer
elif isinstance(ssl_ctx_option, int):
# Add the int value of the option to ctx options
ctx.options |= ssl_ctx_option
dlehrman marked this conversation as resolved.
Show resolved Hide resolved

cert = ctx.wrap_socket(sock, server_hostname=server_name or host).getpeercert(True)
cert = DER_cert_to_PEM_cert(cert)
except Exception as e:
Expand Down
Loading