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

x509_crl: allow to configure how serial numbers are provided #715

Merged
merged 1 commit into from
Feb 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions changelogs/fragments/715-x509_crl-serial.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
minor_changes:
- "x509_crl - the new option ``serial_numbers`` allow to configure in which format serial numbers can be provided
to ``revoked_certificates[].serial_number``. The default is as integers (``serial_numbers=integer``) for backwards compatibility;
setting ``serial_numbers=hex-octets`` allows to specify colon-separated hex octet strings like ``00:11:22:FF``
(https://github.com/ansible-collections/community.crypto/issues/687, https://github.com/ansible-collections/community.crypto/pull/715)."
56 changes: 49 additions & 7 deletions plugins/modules/x509_crl.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,21 @@
type: str
default: sha256

serial_numbers:
description:
- This option determines which values will be accepted for O(revoked_certificates[].serial_number).
- If set to V(integer) (default), serial numbers are assumed to be integers, for example V(66223).
(This example value is equivalent to the hex octet string V(01:02:AF).)
- If set to V(hex-octets), serial numbers are assumed to be colon-separated hex octet strings,
for example V(01:02:AF).
(This example value is equivalent to the integer V(66223).)
type: str
choices:
- integer
- hex-octets
default: integer
version_added: 2.18.0

revoked_certificates:
description:
- List of certificates to be revoked.
Expand Down Expand Up @@ -193,9 +208,13 @@
- Mutually exclusive with O(revoked_certificates[].path) and
O(revoked_certificates[].content). One of these three options must
be specified.
- This option accepts an B(integer). If you want to provide serial numbers as colon-separated hex strings,
such as C(11:22:33), you need to convert them to an integer with P(community.crypto.parse_serial#filter).
type: int
- This option accepts integers or hex octet strings, depending on the value
of O(serial_numbers).
- If O(serial_numbers=integer), integers such as V(66223) must be provided.
- If O(serial_numbers=hex-octets), strings such as V(01:02:AF) must be provided.
- You can use the filters P(community.crypto.parse_serial#filter) and
P(community.crypto.to_serial#filter) to convert these two representations.
type: raw
revocation_date:
description:
- The point in time the certificate was revoked.
Expand Down Expand Up @@ -431,7 +450,9 @@

from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.common.text.converters import to_native, to_text
from ansible.module_utils.common.validation import check_type_int, check_type_str

from ansible_collections.community.crypto.plugins.module_utils.serial import parse_serial
from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion

from ansible_collections.community.crypto.plugins.module_utils.io import (
Expand Down Expand Up @@ -520,6 +541,7 @@ def __init__(self, module):
self.ignore_timestamps = module.params['ignore_timestamps']
self.return_content = module.params['return_content']
self.name_encoding = module.params['name_encoding']
self.serial_numbers_format = module.params['serial_numbers']
self.crl_content = None

self.privatekey_path = module.params['privatekey_path']
Expand All @@ -545,6 +567,8 @@ def __init__(self, module):
if self.digest is None:
raise CRLError('The digest "{0}" is not supported'.format(module.params['digest']))

self.module = module

self.revoked_certificates = []
for i, rc in enumerate(module.params['revoked_certificates']):
result = {
Expand Down Expand Up @@ -576,7 +600,7 @@ def __init__(self, module):
)
else:
# Specify serial_number (and potentially issuer) directly
result['serial_number'] = rc['serial_number']
result['serial_number'] = self._parse_serial_number(rc['serial_number'], i)
# All other options
if rc['issuer']:
result['issuer'] = [cryptography_get_name(issuer, 'issuer') for issuer in rc['issuer']]
Expand All @@ -596,8 +620,6 @@ def __init__(self, module):
result['invalidity_date_critical'] = rc['invalidity_date_critical']
self.revoked_certificates.append(result)

self.module = module

self.backup = module.params['backup']
self.backup_file = None

Expand Down Expand Up @@ -631,6 +653,25 @@ def __init__(self, module):

self.diff_after = self.diff_before = self._get_info(data)

def _parse_serial_number(self, value, index):
if self.serial_numbers_format == 'integer':
try:
return check_type_int(value)
except TypeError as exc:
self.module.fail_json(msg='Error while parsing revoked_certificates[{idx}].serial_number as an integer: {exc}'.format(
idx=index + 1,
exc=to_native(exc),
))
if self.serial_numbers_format == 'hex-octets':
try:
return parse_serial(check_type_str(value))
except (TypeError, ValueError) as exc:
self.module.fail_json(msg='Error while parsing revoked_certificates[{idx}].serial_number as an colon-separated hex octet string: {exc}'.format(
idx=index + 1,
exc=to_native(exc),
))
raise RuntimeError('Unexpected value %s of serial_numbers' % (self.serial_numbers_format, ))

def _get_info(self, data):
if data is None:
return dict()
Expand Down Expand Up @@ -896,7 +937,7 @@ def main():
options=dict(
path=dict(type='path'),
content=dict(type='str'),
serial_number=dict(type='int'),
serial_number=dict(type='raw'),
revocation_date=dict(type='str', default='+0s'),
issuer=dict(type='list', elements='str'),
issuer_critical=dict(type='bool', default=False),
Expand All @@ -916,6 +957,7 @@ def main():
mutually_exclusive=[['path', 'content', 'serial_number']],
),
name_encoding=dict(type='str', default='ignore', choices=['ignore', 'idna', 'unicode']),
serial_numbers=dict(type='str', default='integer', choices=['integer', 'hex-octets']),
),
required_if=[
('state', 'present', ['privatekey_path', 'privatekey_content'], True),
Expand Down
14 changes: 8 additions & 6 deletions tests/integration/targets/x509_crl/tasks/impl.yml
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,15 @@
- cert-2.pem
register: slurp

- name: Create CRL 1 (idempotent with content, check mode)
- name: Create CRL 1 (idempotent with content and octet string serial, check mode)
x509_crl:
path: '{{ remote_tmp_dir }}/ca-crl1.crl'
privatekey_content: "{{ slurp.results[0].content | b64decode }}"
issuer:
CN: Ansible
last_update: 20191013000000Z
next_update: 20191113000000Z
serial_numbers: hex-octets
revoked_certificates:
- content: "{{ slurp.results[1].content | b64decode }}"
revocation_date: 20191013000000Z
Expand All @@ -135,19 +136,20 @@
reason: key_compromise
reason_critical: true
invalidity_date: 20191012000000Z
- serial_number: 1234
- serial_number: 04:D2
revocation_date: 20191001000000Z
check_mode: true
register: crl_1_idem_content_check

- name: Create CRL 1 (idempotent with content)
- name: Create CRL 1 (idempotent with content and octet string serial)
x509_crl:
path: '{{ remote_tmp_dir }}/ca-crl1.crl'
privatekey_content: "{{ slurp.results[0].content | b64decode }}"
issuer:
CN: Ansible
last_update: 20191013000000Z
next_update: 20191113000000Z
serial_numbers: hex-octets
revoked_certificates:
- content: "{{ slurp.results[1].content | b64decode }}"
revocation_date: 20191013000000Z
Expand All @@ -156,7 +158,7 @@
reason: key_compromise
reason_critical: true
invalidity_date: 20191012000000Z
- serial_number: 1234
- serial_number: 04:D2
revocation_date: 20191001000000Z
register: crl_1_idem_content

Expand Down Expand Up @@ -220,7 +222,7 @@
reason: key_compromise
reason_critical: true
invalidity_date: 20191012000000Z
- serial_number: 1234
- serial_number: "1234"
revocation_date: 20191001000000Z
check_mode: true
register: crl_1_format_idem_check
Expand All @@ -242,7 +244,7 @@
reason: key_compromise
reason_critical: true
invalidity_date: 20191012000000Z
- serial_number: 1234
- serial_number: "1234"
revocation_date: 20191001000000Z
return_content: true
register: crl_1_format_idem
Expand Down
Loading