mirror of
https://github.com/ansible-collections/community.crypto.git
synced 2026-05-08 22:33:53 +00:00
openssh_cert - adding signature_algorithm option (#277)
* Initial Commit * Update supported OpenSSH versions for RSA SHA-2 signed certs * Updating 'regenerate' documentation
This commit is contained in:
@@ -160,7 +160,8 @@ class KeygenCommand(object):
|
|||||||
self._run_command = module.run_command
|
self._run_command = module.run_command
|
||||||
|
|
||||||
def generate_certificate(self, certificate_path, identifier, options, pkcs11_provider, principals,
|
def generate_certificate(self, certificate_path, identifier, options, pkcs11_provider, principals,
|
||||||
serial_number, signing_key_path, type, time_parameters, use_agent, **kwargs):
|
serial_number, signature_algorithm, signing_key_path, type,
|
||||||
|
time_parameters, use_agent, **kwargs):
|
||||||
args = [self._bin_path, '-s', signing_key_path, '-P', '', '-I', identifier]
|
args = [self._bin_path, '-s', signing_key_path, '-P', '', '-I', identifier]
|
||||||
|
|
||||||
if options:
|
if options:
|
||||||
@@ -178,6 +179,8 @@ class KeygenCommand(object):
|
|||||||
args.extend(['-U'])
|
args.extend(['-U'])
|
||||||
if time_parameters.validity_string:
|
if time_parameters.validity_string:
|
||||||
args.extend(['-V', time_parameters.validity_string])
|
args.extend(['-V', time_parameters.validity_string])
|
||||||
|
if signature_algorithm:
|
||||||
|
args.extend(['-t', signature_algorithm])
|
||||||
args.append(certificate_path)
|
args.append(certificate_path)
|
||||||
|
|
||||||
return self._run_command(args, **kwargs)
|
return self._run_command(args, **kwargs)
|
||||||
|
|||||||
@@ -555,6 +555,11 @@ class OpensshCertificate(object):
|
|||||||
def signing_key(self):
|
def signing_key(self):
|
||||||
return to_text(self._cert_info.signing_key_fingerprint())
|
return to_text(self._cert_info.signing_key_fingerprint())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def signature_type(self):
|
||||||
|
signature_data = OpensshParser.signature_data(self.signature)
|
||||||
|
return to_text(signature_data['signature_type'])
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _parse_cert_info(pub_key_type, parser):
|
def _parse_cert_info(pub_key_type, parser):
|
||||||
cert_info = get_cert_info_object(pub_key_type)
|
cert_info = get_cert_info_object(pub_key_type)
|
||||||
|
|||||||
@@ -201,8 +201,9 @@ class OpensshParser(object):
|
|||||||
signature_blob = parser.string()
|
signature_blob = parser.string()
|
||||||
|
|
||||||
blob_parser = cls(signature_blob)
|
blob_parser = cls(signature_blob)
|
||||||
if signature_type == b'ssh-rsa':
|
if signature_type in (b'ssh-rsa', b'rsa-sha2-256', b'rsa-sha2-512'):
|
||||||
# https://datatracker.ietf.org/doc/html/rfc4253#section-6.6
|
# https://datatracker.ietf.org/doc/html/rfc4253#section-6.6
|
||||||
|
# https://datatracker.ietf.org/doc/html/rfc8332#section-3
|
||||||
signature_data['s'] = cls._big_int(signature_blob, "big")
|
signature_data['s'] = cls._big_int(signature_blob, "big")
|
||||||
elif signature_type == b'ssh-dss':
|
elif signature_type == b'ssh-dss':
|
||||||
# https://datatracker.ietf.org/doc/html/rfc4253#section-6.6
|
# https://datatracker.ietf.org/doc/html/rfc4253#section-6.6
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ options:
|
|||||||
- When C(fail) the task will fail if a certificate already exists at I(path) and does not
|
- When C(fail) the task will fail if a certificate already exists at I(path) and does not
|
||||||
match the module's options.
|
match the module's options.
|
||||||
- When C(partial_idempotence) an existing certificate will be regenerated based on
|
- When C(partial_idempotence) an existing certificate will be regenerated based on
|
||||||
I(serial), I(type), I(valid_from), I(valid_to), I(valid_at), and I(principals).
|
I(serial), I(signature_algorithm), I(type), I(valid_from), I(valid_to), I(valid_at), and I(principals).
|
||||||
- When C(full_idempotence) I(identifier), I(options), I(public_key), and I(signing_key)
|
- When C(full_idempotence) I(identifier), I(options), I(public_key), and I(signing_key)
|
||||||
are also considered when compared against an existing certificate.
|
are also considered when compared against an existing certificate.
|
||||||
- C(always) is equivalent to I(force=true).
|
- C(always) is equivalent to I(force=true).
|
||||||
@@ -62,6 +62,26 @@ options:
|
|||||||
- always
|
- always
|
||||||
default: partial_idempotence
|
default: partial_idempotence
|
||||||
version_added: 1.8.0
|
version_added: 1.8.0
|
||||||
|
signature_algorithm:
|
||||||
|
description:
|
||||||
|
- As of OpenSSH 8.2 the SHA-1 signature algorithm for RSA keys has been disabled and C(ssh) will refuse
|
||||||
|
host certificates signed with the SHA-1 algorithm. OpenSSH 8.1 made C(rsa-sha2-512) the default algorithm
|
||||||
|
when acting as a CA and signing certificates with a RSA key. However, for OpenSSH versions less than 8.1
|
||||||
|
the SHA-2 signature algorithms, C(rsa-sha2-256) or C(rsa-sha2-512), must be specified using this option
|
||||||
|
if compatibility with newer C(ssh) clients is required. Conversely if hosts using OpenSSH version 8.2
|
||||||
|
or greater must remain compatible with C(ssh) clients using OpenSSH less than 7.2, then C(ssh-rsa)
|
||||||
|
can be used when generating host certificates (a corresponding change to the sshd_config to add C(ssh-rsa)
|
||||||
|
to the C(CASignatureAlgorithms) keyword is also required).
|
||||||
|
- Using any value for this option with a non-RSA I(signing_key) will cause this module to fail.
|
||||||
|
- "Note: OpenSSH versions prior to 7.2 do not support SHA-2 signature algorithms for RSA keys and OpenSSH
|
||||||
|
versions prior to 7.3 do not support SHA-2 signature algorithms for certificates."
|
||||||
|
- See U(https://www.openssh.com/txt/release-8.2) for more information.
|
||||||
|
type: str
|
||||||
|
choices:
|
||||||
|
- ssh-rsa
|
||||||
|
- rsa-sha2-256
|
||||||
|
- rsa-sha2-512
|
||||||
|
version_added: 1.10.0
|
||||||
signing_key:
|
signing_key:
|
||||||
description:
|
description:
|
||||||
- The path to the private openssh key that is used for signing the public key in order to generate the certificate.
|
- The path to the private openssh key that is used for signing the public key in order to generate the certificate.
|
||||||
@@ -269,6 +289,7 @@ class Certificate(OpensshModule):
|
|||||||
self.public_key = self.module.params['public_key']
|
self.public_key = self.module.params['public_key']
|
||||||
self.regenerate = self.module.params['regenerate'] if not self.module.params['force'] else 'always'
|
self.regenerate = self.module.params['regenerate'] if not self.module.params['force'] else 'always'
|
||||||
self.serial_number = self.module.params['serial_number']
|
self.serial_number = self.module.params['serial_number']
|
||||||
|
self.signature_algorithm = self.module.params['signature_algorithm']
|
||||||
self.signing_key = self.module.params['signing_key']
|
self.signing_key = self.module.params['signing_key']
|
||||||
self.state = self.module.params['state']
|
self.state = self.module.params['state']
|
||||||
self.type = self.module.params['type']
|
self.type = self.module.params['type']
|
||||||
@@ -366,6 +387,7 @@ class Certificate(OpensshModule):
|
|||||||
def _is_partially_valid(self):
|
def _is_partially_valid(self):
|
||||||
return all([
|
return all([
|
||||||
set(self.original_data.principals) == set(self.principals),
|
set(self.original_data.principals) == set(self.principals),
|
||||||
|
self.original_data.signature_type == self.signature_algorithm if self.signature_algorithm else True,
|
||||||
self.original_data.serial == self.serial_number if self.serial_number is not None else True,
|
self.original_data.serial == self.serial_number if self.serial_number is not None else True,
|
||||||
self.original_data.type == self.type,
|
self.original_data.type == self.type,
|
||||||
self._compare_time_parameters(),
|
self._compare_time_parameters(),
|
||||||
@@ -425,7 +447,7 @@ class Certificate(OpensshModule):
|
|||||||
|
|
||||||
self.ssh_keygen.generate_certificate(
|
self.ssh_keygen.generate_certificate(
|
||||||
key_copy, self.identifier, self.options, self.pkcs11_provider, self.principals, self.serial_number,
|
key_copy, self.identifier, self.options, self.pkcs11_provider, self.principals, self.serial_number,
|
||||||
self.signing_key, self.type, self.time_parameters, self.use_agent,
|
self.signature_algorithm, self.signing_key, self.type, self.time_parameters, self.use_agent,
|
||||||
environ_update=dict(TZ="UTC"), check_rc=True
|
environ_update=dict(TZ="UTC"), check_rc=True
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -485,6 +507,8 @@ def get_cert_dict(data):
|
|||||||
|
|
||||||
result = data.to_dict()
|
result = data.to_dict()
|
||||||
result.pop('nonce')
|
result.pop('nonce')
|
||||||
|
result['signature_algorithm'] = data.signature_type
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@@ -503,6 +527,7 @@ def main():
|
|||||||
default='partial_idempotence',
|
default='partial_idempotence',
|
||||||
choices=['never', 'fail', 'partial_idempotence', 'full_idempotence', 'always']
|
choices=['never', 'fail', 'partial_idempotence', 'full_idempotence', 'always']
|
||||||
),
|
),
|
||||||
|
signature_algorithm=dict(type='str', choices=['ssh-rsa', 'rsa-sha2-256', 'rsa-sha2-512']),
|
||||||
signing_key=dict(type='path'),
|
signing_key=dict(type='path'),
|
||||||
serial_number=dict(type='int'),
|
serial_number=dict(type='int'),
|
||||||
state=dict(type='str', default='present', choices=['absent', 'present']),
|
state=dict(type='str', default='present', choices=['absent', 'present']),
|
||||||
|
|||||||
@@ -20,6 +20,81 @@
|
|||||||
valid_from: always
|
valid_from: always
|
||||||
valid_to: forever
|
valid_to: forever
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: Generate cert with updated signature algorithm
|
||||||
|
openssh_cert:
|
||||||
|
type: user
|
||||||
|
path: "{{ certificate_path }}"
|
||||||
|
public_key: "{{ public_key }}"
|
||||||
|
signing_key: "{{ signing_key }}"
|
||||||
|
signature_algorithm: rsa-sha2-256
|
||||||
|
valid_from: always
|
||||||
|
valid_to: forever
|
||||||
|
register: updated_signature_algorithm
|
||||||
|
|
||||||
|
- name: Assert signature algorithm update causes change
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- updated_signature_algorithm is changed
|
||||||
|
|
||||||
|
- name: Generate cert with updated signature algorithm (idempotent)
|
||||||
|
openssh_cert:
|
||||||
|
type: user
|
||||||
|
path: "{{ certificate_path }}"
|
||||||
|
public_key: "{{ public_key }}"
|
||||||
|
signing_key: "{{ signing_key }}"
|
||||||
|
signature_algorithm: rsa-sha2-256
|
||||||
|
valid_from: always
|
||||||
|
valid_to: forever
|
||||||
|
register: updated_signature_algorithm_idempotent
|
||||||
|
|
||||||
|
- name: Assert signature algorithm update is idempotent
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- updated_signature_algorithm_idempotent is not changed
|
||||||
|
|
||||||
|
- name: Generate cert with original signature algorithm
|
||||||
|
openssh_cert:
|
||||||
|
type: user
|
||||||
|
path: "{{ certificate_path }}"
|
||||||
|
public_key: "{{ public_key }}"
|
||||||
|
signing_key: "{{ signing_key }}"
|
||||||
|
signature_algorithm: ssh-rsa
|
||||||
|
valid_from: always
|
||||||
|
valid_to: forever
|
||||||
|
register: second_signature_algorithm
|
||||||
|
|
||||||
|
- name: Assert second signature algorithm update causes change
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- second_signature_algorithm is changed
|
||||||
|
|
||||||
|
- name: Omit signature algorithm
|
||||||
|
openssh_cert:
|
||||||
|
type: user
|
||||||
|
path: "{{ certificate_path }}"
|
||||||
|
public_key: "{{ public_key }}"
|
||||||
|
signing_key: "{{ signing_key }}"
|
||||||
|
valid_from: always
|
||||||
|
valid_to: forever
|
||||||
|
register: omitted_signature_algorithm
|
||||||
|
|
||||||
|
- name: Assert omitted_signature_algorithm does not cause change
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- omitted_signature_algorithm is not changed
|
||||||
|
|
||||||
|
- name: Revert to original certificate
|
||||||
|
openssh_cert:
|
||||||
|
type: user
|
||||||
|
path: "{{ certificate_path }}"
|
||||||
|
public_key: "{{ public_key }}"
|
||||||
|
signing_key: "{{ signing_key }}"
|
||||||
|
valid_from: always
|
||||||
|
valid_to: forever
|
||||||
|
regenerate: always
|
||||||
|
when: openssh_version is version("7.3", ">=")
|
||||||
|
|
||||||
- name: Generate cert with new signing key
|
- name: Generate cert with new signing key
|
||||||
openssh_cert:
|
openssh_cert:
|
||||||
type: user
|
type: user
|
||||||
|
|||||||
Reference in New Issue
Block a user