diff --git a/changelogs/fragments/luks_device_passphrase_newlines.yml b/changelogs/fragments/luks_device_passphrase_newlines.yml new file mode 100644 index 00000000..281cba52 --- /dev/null +++ b/changelogs/fragments/luks_device_passphrase_newlines.yml @@ -0,0 +1,2 @@ +bugfixes: + - luks_device - allow passphrases to contain newlines (https://github.com/ansible-collections/community.crypto/pull/844). diff --git a/plugins/modules/luks_device.py b/plugins/modules/luks_device.py index 156f4b32..ebb48c64 100644 --- a/plugins/modules/luks_device.py +++ b/plugins/modules/luks_device.py @@ -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: diff --git a/tests/integration/targets/luks_device/files/keyfile3 b/tests/integration/targets/luks_device/files/keyfile3 new file mode 100644 index 00000000..3d5c5d15 Binary files /dev/null and b/tests/integration/targets/luks_device/files/keyfile3 differ diff --git a/tests/integration/targets/luks_device/files/keyfile3.license b/tests/integration/targets/luks_device/files/keyfile3.license new file mode 100644 index 00000000..edff8c76 --- /dev/null +++ b/tests/integration/targets/luks_device/files/keyfile3.license @@ -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 diff --git a/tests/integration/targets/luks_device/files/keyfile3.txt b/tests/integration/targets/luks_device/files/keyfile3.txt new file mode 100644 index 00000000..84f1372a --- /dev/null +++ b/tests/integration/targets/luks_device/files/keyfile3.txt @@ -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 diff --git a/tests/integration/targets/luks_device/tasks/tests/keyfile_binary_nocopy.yml b/tests/integration/targets/luks_device/tasks/tests/keyfile_binary_nocopy.yml new file mode 100644 index 00000000..97e83d04 --- /dev/null +++ b/tests/integration/targets/luks_device/tasks/tests/keyfile_binary_nocopy.yml @@ -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 diff --git a/tests/integration/targets/luks_device/vars/main.yml b/tests/integration/targets/luks_device/vars/main.yml new file mode 100644 index 00000000..5244f8eb --- /dev/null +++ b/tests/integration/targets/luks_device/vars/main.yml @@ -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 }}"