--- clevis-18.ori/src/luks/clevis-luks-bind 2021-04-15 13:00:19.965065700 +0200 +++ clevis-18/src/luks/clevis-luks-bind 2022-11-24 12:53:59.613676320 +0100 @@ -25,7 +25,7 @@ usage() { exec >&2 echo - echo "Usage: clevis luks bind [-y] [-f] [-s SLT] [-k KEY] [-t TOKEN_ID] -d DEV PIN CFG" + echo "Usage: clevis luks bind [-y] [-f] [-s SLT] [-k KEY] [-t TOKEN_ID] [-e EXISTING_TOKEN_ID] -d DEV PIN CFG" echo echo "$SUMMARY": echo @@ -42,6 +42,8 @@ echo " -k KEY Non-interactively read LUKS password from KEY file" echo " -k - Non-interactively read LUKS password from standard input" echo + echo " -e E_TKN_ID Existing LUKS token ID for existing passphrase; only available for LUKS2" + echo exit 2 } @@ -52,13 +54,14 @@ FRC= YES= -while getopts ":hfyd:s:k:t:" o; do +while getopts ":hfyd:s:k:t:e:" o; do case "$o" in f) FRC='-f';; d) DEV="$OPTARG";; s) SLT="$OPTARG";; k) KEY="$OPTARG";; t) TOKEN_ID="$OPTARG";; + e) EXISTING_TOKEN_ID="$OPTARG";; y) FRC='-f' YES='-y';; *) usage;; @@ -99,11 +102,20 @@ exit 1 fi +if [ -n "${EXISTING_TOKEN_ID}" ] && ! clevis_luks_luks2_existing_token_id_supported; then + echo "Existing token ID not supported in this cryptsetup version" >&2 + exit 1 +fi + # Get the existing passphrase/keyfile. existing_key= keyfile= case "${KEY}" in -"") IFS= read -r -s -p "Enter existing LUKS password: " existing_key; echo >&2;; + "") + if [ -z "${EXISTING_TOKEN_ID}" ] ; then + IFS= read -r -s -p "Enter existing LUKS password: " existing_key; echo >&2 + fi + ;; -) IFS= read -r -s -p "" existing_key ||: if [ "${luks_type}" = "luks1" ] && ! luksmeta test -d "${DEV}" \ && [ -z "${FRC}" ]; then @@ -119,6 +131,13 @@ ;; esac +# Check if existing token id for keyring read is provided +# If so, keyfile is not allowed +if [ -n "${EXISTING_TOKEN_ID}" ] && [ -n "${keyfile}" ] ; then + echo "Cannot specify kernel keyring description together with key file" >&2 + exit 1 +fi + # If necessary, initialize the LUKS volume. if [ "${luks_type}" = "luks1" ] && ! luksmeta test -d "${DEV}"; then luksmeta init -d "${DEV}" ${FRC} @@ -127,7 +146,7 @@ if ! clevis_luks_do_bind "${DEV}" "${SLT}" "${TOKEN_ID}" \ "${PIN}" "${CFG}" \ "${YES}" "" \ - "${existing_key}" "${keyfile}"; then + "${existing_key}" "${keyfile}" "${EXISTING_TOKEN_ID}"; then echo "Error adding new binding to ${DEV}" >&2 exit 1 fi --- clevis-18.ori/src/luks/clevis-luks-bind.1.adoc 2021-04-15 13:00:19.965065700 +0200 +++ clevis-18/src/luks/clevis-luks-bind.1.adoc 2022-11-24 12:54:48.476829197 +0100 @@ -9,7 +9,7 @@ == SYNOPSIS -*clevis luks bind* [-f] [-y] -d DEV [-t TKN_ID] [-s SLT] [-k KEY] PIN CFG +*clevis luks bind* [-f] [-y] -d DEV [-t TKN_ID] [-s SLT] [-k KEY] [-e EXISTING_TOKEN_ID] PIN CFG == OVERVIEW @@ -54,6 +54,12 @@ * *-k* - : Non-interactively read LUKS password from standard input +* *-e* _E_TKN_ID_ : + LUKS token ID for existing passphrase; only available for LUKS2. + This parameter allows providing a configured token ID in LUKS2 + containing the existing passphrase for this device, so that + existing passphrase is not prompted by clevis + == CAVEATS This command does not change the LUKS master key. This implies that if you --- clevis-18.ori/src/luks/clevis-luks-common-functions.in 2022-11-24 12:46:09.130204312 +0100 +++ clevis-18/src/luks/clevis-luks-common-functions.in 2022-11-24 13:01:57.087170193 +0100 @@ -307,9 +307,10 @@ local KEY="${2:-}" local KEYFILE="${3:-}" local SLT="${4:-}" + local EXISTING_TOKEN_ID="${5:-}" [ -z "${DEV}" ] && return 1 - [ -z "${KEYFILE}" ] && [ -z "${KEY}" ] && return 1 + [ -z "${EXISTING_TOKEN_ID}" ] && [ -z "${KEYFILE}" ] && [ -z "${KEY}" ] && return 1 local extra_args extra_args="$([ -n "${SLT}" ] && printf -- '--key-slot %s' "${SLT}")" @@ -318,6 +319,11 @@ ${extra_args} return fi + if [ -n "${EXISTING_TOKEN_ID}" ]; then + cryptsetup open --test-passphrase "${DEV}" --token-id "${EXISTING_TOKEN_ID}" \ + ${extra_args} + return + fi printf '%s' "${KEY}" | cryptsetup open --test-passphrase "${DEV}" \ ${extra_args} @@ -753,10 +759,11 @@ local NEWKEY="${3}" local KEY="${4}" local KEYFILE="${5:-}" + local EXISTING_TOKEN_ID="${6:-}" [ -z "${DEV}" ] && return 1 [ -z "${NEWKEY}" ] && return 1 - [ -z "${KEY}" ] && [ -z "${KEYFILE}" ] && return 1 + [ -z "${EXISTING_TOKEN_ID}" ] && [ -z "${KEY}" ] && [ -z "${KEYFILE}" ] && return 1 local extra_args='' input input="$(printf '%s\n%s' "${KEY}" "${NEWKEY}")" @@ -764,6 +771,10 @@ extra_args="$(printf -- '--key-file %s' "${KEYFILE}")" input="$(printf '%s' "${NEWKEY}")" fi + if [ -n "${EXISTING_TOKEN_ID}" ]; then + extra_args="$(printf -- '--token-id %s' "${EXISTING_TOKEN_ID}")" + input="$(printf '%s' "${NEWKEY}")" + fi local pbkdf_args="--pbkdf pbkdf2 --pbkdf-force-iterations 1000" printf '%s' "${input}" | cryptsetup luksAddKey --batch-mode \ @@ -780,6 +791,7 @@ local NEWKEY="${3}" local KEY="${4}" local KEYFILE="${5:-}" + local EXISTING_TOKEN_ID="${6:-}" [ -z "${DEV}" ] && return 1 [ -z "${NEWKEY}" ] && return 1 @@ -789,7 +801,7 @@ local in_place clevis_luks_check_valid_key_or_keyfile "${DEV}" \ "${KEY}" "${KEYFILE}" \ - "${SLT}" 2>/dev/null \ + "${SLT}" "${EXISTING_TOKEN_ID}" 2>/dev/null \ && in_place=true local input extra_args= @@ -798,6 +810,10 @@ extra_args="$(printf -- '--key-file %s' "${KEYFILE}")" input="$(printf '%s' "${NEWKEY}")" fi + if [ -n "${EXISTING_TOKEN_ID}" ]; then + extra_args="$(printf -- '--token-id %s' "${EXISTING_TOKEN_ID}")" + input="$(printf '%s' "${NEWKEY}")" + fi local pbkdf_args="--pbkdf pbkdf2 --pbkdf-force-iterations 1000" if [ -n "${in_place}" ]; then @@ -844,13 +860,13 @@ [ -n "${OVERWRITE}" ] || return 1 clevis_luks_update_key "${DEV}" "${SLT}" \ - "${NEWKEY}" "${KEY}" "${KEYFILE}" + "${NEWKEY}" "${KEY}" "${KEYFILE}" "${EXISTING_TOKEN_ID}" return fi # Add a new key. clevis_luks_add_key "${DEV}" "${SLT}" \ - "${NEWKEY}" "${KEY}" "${KEYFILE}" + "${NEWKEY}" "${KEY}" "${KEYFILE}" "${EXISTING_TOKEN_ID}" } # clevis_luks_generate_key() generates a new key for use with clevis. @@ -942,6 +958,7 @@ local OVERWRITE="${7:-}" local KEY="${8:-}" local KEYFILE="${9:-}" + local EXISTING_TOKEN_ID="${10:-}" [ -z "${DEV}" ] && return 1 [ -z "${PIN}" ] && return 1 @@ -951,6 +968,8 @@ if ! clevis_luks_check_valid_key_or_keyfile "${DEV}" \ "${KEY}" \ "${KEYFILE}" \ + "" \ + "${EXISTING_TOKEN_ID}" \ && ! KEY="$(clevis_luks_get_existing_key "${DEV}" \ "Enter existing LUKS password: " \ "recover")"; then @@ -995,7 +1014,7 @@ if ! clevis_luks_save_key_to_slot "${DEV}" "${SLT}" \ "${newkey}" "${KEY}" "${KEYFILE}" \ - "${OVERWRITE}"; then + "${OVERWRITE}" "${EXISTING_TOKEN_ID}"; then echo "Unable to save/update key slot; operation cancelled" >&2 clevis_luks_restore_dev "${CLEVIS_TMP_DIR}" || : rm -rf "${CLEVIS_TMP_DIR}" @@ -1016,12 +1035,19 @@ } # clevis_luks_luks2_supported() indicates whether we support LUKS2 devices. -# Suppor is determined at build time. +# Support is determined at build time. function clevis_luks_luks2_supported() { # We require cryptsetup >= 2.0.4 to fully support LUKSv2. return @OLD_CRYPTSETUP@ } +# clevis_luks_luks2_existing_token_id_supported() indicates whether +# cryptsetup allows token id for passphrase providing +function clevis_luks_luks2_existing_token_id_supported() { + # We require cryptsetup >= 2.6.0 to fully support LUKSv2 addkey/open by token ID + return @OLD_CRYPTSETUP_EXISTING_TOKEN_ID@ +} + # clevis_luks_type() returns the LUKS type of a device, e.g. "luks1". clevis_luks_type() { local DEV="${1}" --- clevis-18.ori/src/luks/meson.build 2021-04-15 13:00:19.965065700 +0200 +++ clevis-18/src/luks/meson.build 2022-11-24 13:02:39.118301695 +0100 @@ -14,6 +14,15 @@ endif endif +libcryptsetup_ext_token_id = dependency('libcryptsetup', version: '>=2.6.0', required: false) +if libcryptsetup_ext_token_id.found() + luksmeta_data.set('OLD_CRYPTSETUP_EXISTING_TOKEN_ID', '0') + message('cryptsetup version supports existing token id') +else + luksmeta_data.set('OLD_CRYPTSETUP_EXISTING_TOKEN_ID', '1') + warning('cryptsetup version does not support existing token id') +endif + clevis_luks_common_functions = configure_file( input: 'clevis-luks-common-functions.in', output: 'clevis-luks-common-functions', --- clevis-18.ori/src/luks/tests/bind-luks2-ext-token 1970-01-01 01:00:00.000000000 +0100 +++ clevis-18/src/luks/tests/bind-luks2-ext-token 2022-11-24 13:04:30.742650939 +0100 @@ -0,0 +1,74 @@ +#!/bin/bash -ex +# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: +# +# Copyright (c) 2022 Red Hat, Inc. +# Author: Sergio Arroutbi +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +TEST=$(basename "${0}") +. tests-common-functions + +on_exit() { + [ -d "${TMP}" ] && rm -rf "${TMP}" +} + +create_existing_token_id_from_keyring() { + local DEV="${1}" + local KEYDESC="${2}" + local TOKEN_ID="${3}" + local PASS="${4}" + if [[ -z "${DEV}" ]] || [[ -z "${KEYDESC}" ]] || [[ -z "${TOKEN_ID}" ]]; then + return 1 + fi + KEYRING_ID=$(keyctl add user "${KEYDESC}" "${PASS}" @s) + keyctl print "${KEYRING_ID}" 2>/dev/null 1>/dev/null + cryptsetup token add --token-id "${TOKEN_ID}" --key-description "${KEYDESC}" "${DEV}" +} + +if ! luks2_supported; then + skip_test "${TEST}: LUKS2 is not supported." +fi + +if ! luks2_existing_token_id_supported; then + skip_test "${TEST}: Existing token ID not supported" +fi + +trap 'on_exit' EXIT +trap 'exit' ERR + +TMP="$(mktemp -d)" + +ADV="${TMP}/adv.jws" +tang_create_adv "${TMP}" "${ADV}" +CFG="$(printf '{"url":"foobar","adv":"%s"}' "$ADV")" + +EXISTING_TOKEN_ID=5 +KEYDESC="testkey" +PASS="123exttokenid_" +DEV="${TMP}/luks2-device-ext-token" +new_device "luks2" "${DEV}" "${PASS}" + +create_existing_token_id_from_keyring "${DEV}" "${KEYDESC}" "${EXISTING_TOKEN_ID}" "${PASS}" + +if ! clevis luks bind -y -d "${DEV}" -e "${EXISTING_TOKEN_ID}" tang "${CFG}"; then + error "${TEST}: Binding expected to succeed with existing token id:${EXISTING_TOKEN_ID}" >&2 +fi + +KEYFILE="${TMP}/keyfile.txt" +touch "${KEYFILE}" +if clevis luks bind -y -d "${DEV}" -e "${EXISTING_TOKEN_ID}" -k "${KEYFILE}" tang "${CFG}"; then + error "${TEST}: Using existing token id and keyfile should dump an error" >&2 +fi --- clevis-18.ori/src/luks/tests/meson.build 2021-04-15 13:00:19.967066500 +0200 +++ clevis-18/src/luks/tests/meson.build 2022-11-24 13:06:36.096043131 +0100 @@ -5,6 +5,15 @@ # given token slot. cryptsetup = find_program('cryptsetup', required: true) +# Use keyctl to check an existing token id can be created from +# kernel keyring password +keyutils = find_program('keyctl', required: false) +if keyutils.found() + message('keyutils installed') +else + warning('keyutils not installed, unable to test existing token id binding') +endif + common_functions = configure_file(input: 'tests-common-functions.in', output: 'tests-common-functions', configuration: luksmeta_data, @@ -69,6 +78,10 @@ test('unbind-unbound-slot-luks2', find_program('unbind-unbound-slot-luks2'), env: env) test('unbind-luks2', find_program('unbind-luks2'), env: env, timeout: 60) + if keyutils.found() and luksmeta_data.get('OLD_CRYPTSETUP_EXISTING_TOKEN_ID') == '0' + test('bind-luks2-ext-token', find_program('bind-luks2-ext-token'), env: env, timeout: 60) + endif + if jq.found() test('list-recursive-luks2', find_program('list-recursive-luks2'), env: env, timeout: 60) test('list-tang-luks2', find_program('list-tang-luks2'), env: env, timeout: 60) --- clevis-18.ori/src/luks/tests/tests-common-functions.in 2021-04-15 13:00:19.967066500 +0200 +++ clevis-18/src/luks/tests/tests-common-functions.in 2022-11-24 13:06:24.376006462 +0100 @@ -36,6 +36,12 @@ return @OLD_CRYPTSETUP@ } +# We require cryptsetup >= 2.6.0 to fully support LUKSv2 addkey/open by token ID +# Support is determined at build time. +luks2_existing_token_id_supported() { + return @OLD_CRYPTSETUP_EXISTING_TOKEN_ID@ +} + # Creates a new LUKS1 or LUKS2 device to be used. new_device() { local LUKS="${1}"