luks_device: allow passphrases to contain newlines (#844)

* luks_device: allow passphrases to contain newlines

This is useful when passing binary keyfiles from an ansible vault, as
it removes the restriction that the binary data cannot contain newlines.
The only exception is adding a new key to an existing container, as in
that case the two passphrases are separated by a new line.

* add integration tests and a changelog fragment

* attempt to also make luks_add_key work with passphrases containing
newlines

* use a deterministic method to generate keyfile 3, improve changelog
formatting

* add licence and copyright to keyfile3.txt to satisfy CI
pull/846/head
ilia-kats 2025-02-09 14:24:16 +01:00 committed by GitHub
parent cb6edf1a5f
commit 2433fdab98
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 134 additions and 7 deletions

View File

@ -0,0 +1,2 @@
bugfixes:
- luks_device - allow passphrases to contain newlines (https://github.com/ansible-collections/community.crypto/pull/844).

View File

@ -70,9 +70,6 @@ options:
passphrase_encoding:
description:
- Determine how passphrases are provided to parameters such as O(passphrase), O(new_passphrase), and O(remove_passphrase).
- Please note that binary passphrases cannot contain all possible binary octets. For example, a newline (0x0A)
cannot be used since it indicates that the passphrase is over. If you want to use arbitrary binary data, you must
use keyfiles.
type: str
default: text
choices:
@ -488,8 +485,6 @@ class Handler(object):
self._module.fail_json("Error while base64-decoding '{parameter_name}': {exc}".format(parameter_name=parameter_name, exc=exc))
def _run_command(self, command, data=None):
if data is not None:
data += b'\n'
return self._module.run_command(command, data=data, binary_data=True)
def get_device_by_uuid(self, uuid):
@ -635,6 +630,8 @@ class CryptHandler(Handler):
args.extend(['-q', device])
if keyfile:
args.append(keyfile)
else:
args.append('-')
result = self._run_command(args, data=passphrase)
if result[RETURN_CODE] != 0:
@ -646,6 +643,8 @@ class CryptHandler(Handler):
args = [self._cryptsetup_bin]
if keyfile:
args.extend(['--key-file', keyfile])
else:
args.extend(['--key-file', '-'])
if perf_same_cpu_crypt:
args.extend(['--perf-same_cpu_crypt'])
if perf_submit_from_crypt_cpus:
@ -706,14 +705,16 @@ class CryptHandler(Handler):
if keyfile:
args.extend(['--key-file', keyfile])
else:
args.extend(['--key-file', '-', '--keyfile-size', str(len(passphrase))])
data.append(passphrase)
if new_keyfile:
args.append(new_keyfile)
else:
data.extend([new_passphrase, new_passphrase])
args.append('-')
data.append(new_passphrase)
result = self._run_command(args, data=b'\n'.join(data) or None)
result = self._run_command(args, data=b''.join(data) or None)
if result[RETURN_CODE] != 0:
raise ValueError('Error while adding new LUKS keyslot to %s: %s'
% (device, result[STDERR]))
@ -759,6 +760,8 @@ class CryptHandler(Handler):
args = [self._cryptsetup_bin, 'luksKillSlot', device, '-q', str(keyslot)]
if keyfile:
args.extend(['--key-file', keyfile])
else:
args.extend(['--key-file', '-'])
result = self._run_command(args, data=passphrase)
if result[RETURN_CODE] != 0:
raise ValueError('Error while removing LUKS key from %s: %s'
@ -774,6 +777,7 @@ class CryptHandler(Handler):
if keyfile:
args.extend(['--key-file', keyfile])
else:
args.extend(['--key-file', '-'])
data = passphrase
if keyslot is not None:

Binary file not shown.

View File

@ -0,0 +1,3 @@
GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
SPDX-License-Identifier: GPL-3.0-or-later
SPDX-FileCopyrightText: Ansible Project

View File

@ -0,0 +1,7 @@
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
generated with:
dd if=/dev/zero of=/dev/stdout bs=1 count=4096 | openssl enc -aes-256-ctr -pass pass:1234 -nosalt

View File

@ -0,0 +1,105 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- name: Create with keyfile3
luks_device:
device: "{{ cryptfile_device }}"
state: closed
passphrase: "{{ keyfile3 }}"
passphrase_encoding: base64
type: luks2
pbkdf:
iteration_time: 0.1
algorithm: argon2i
memory: 1000
parallel: 1
sector_size: 1024
become: true
ignore_errors: true
register: create_passphrase_1
- name: Create with keyfile3 (without argon2i)
luks_device:
device: "{{ cryptfile_device }}"
state: closed
passphrase: "{{ keyfile3 }}"
passphrase_encoding: base64
pbkdf:
iteration_time: 0.1
become: true
when: create_passphrase_1 is failed
- name: Open with keyfile3
luks_device:
device: "{{ cryptfile_device }}"
state: opened
passphrase: "{{ keyfile3 }}"
passphrase_encoding: base64
become: true
ignore_errors: true
register: open_try
- assert:
that:
- open_try is not failed
- name: Close
luks_device:
device: "{{ cryptfile_device }}"
state: closed
become: true
- name: Try to open with passphrase1
luks_device:
device: "{{ cryptfile_device }}"
state: opened
passphrase: "{{ cryptfile_passphrase1 }}"
become: true
ignore_errors: true
register: open_try
- assert:
that:
- open_try is failed
- name: Give access to passphrase1
luks_device:
device: "{{ cryptfile_device }}"
state: closed
passphrase: "{{ keyfile3 }}"
passphrase_encoding: base64
new_passphrase: "{{ cryptfile_passphrase1 | b64encode }}"
pbkdf:
iteration_time: 0.1
become: true
- name: Remove access for keyfile3
luks_device:
device: "{{ cryptfile_device }}"
state: closed
remove_passphrase: "{{ keyfile3 }}"
passphrase_encoding: base64
become: true
- name: Try to open with keyfile3
luks_device:
device: "{{ cryptfile_device }}"
state: opened
passphrase: "{{ keyfile3 }}"
become: true
ignore_errors: true
register: open_try
- assert:
that:
- open_try is failed
- name: Open with passphrase1
luks_device:
device: "{{ cryptfile_device }}"
state: opened
passphrase: "{{ cryptfile_passphrase1 }}"
become: true
ignore_errors: true
register: open_try
- assert:
that:
- open_try is not failed

View File

@ -0,0 +1,6 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
keyfile3: "{{ lookup('ansible.builtin.file', 'keyfile3', lstrip=False, rstrip=False) | b64encode }}"