From a66f0ae40b44b6599acac5df86b0853e912b913d Mon Sep 17 00:00:00 2001 From: Sergio Correia Date: Mon, 25 May 2020 17:52:02 -0300 Subject: [PATCH] luks: get rid of bashisms in clevis-luks-common-functions As suggested in #202, let's try to define some sort of style guide to try to improve portability and consistency across the scripts. The suggestions include: - getting rid of bashisms, at least for scripts running in early userland - running with "set -e" and "set -u" - using $() instead of backticks - using long form of `jose' commands, for better readability This commit converts clevis-luks-common-function and its user clevis-luks-list. As of now, shellcheck complains of the following: "SC2039: In POSIX sh, 'local' is undefined." This can be muted with `shellcheck -eSC2039' --- src/luks/clevis-luks-common-functions | 129 ++++++++++++++++---------- src/luks/clevis-luks-list | 11 ++- 2 files changed, 85 insertions(+), 55 deletions(-) diff --git a/src/luks/clevis-luks-common-functions b/src/luks/clevis-luks-common-functions index e27c444d..afb0cdc0 100644 --- a/src/luks/clevis-luks-common-functions +++ b/src/luks/clevis-luks-common-functions @@ -1,4 +1,5 @@ -#!/bin/bash -e +#!/bin/sh +set -eu # vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: # # Copyright (c) 2019 Red Hat, Inc. @@ -21,8 +22,12 @@ # valid_slot() will check whether a given slot is possibly valid, i.e., if it # is a numeric value within the specified range. valid_slot() { - local SLT="${1}" - local MAX_SLOTS="${2}" + local SLT="${1:-}" + local MAX_SLOTS="${2:-}" + + [ -z "${SLT}" ] && return 1 + [ -z "${MAX_SLOTS}" ] && return 1 + case "${SLT}" in ''|*[!0-9]*) return 1 @@ -41,15 +46,15 @@ valid_slot() { # should be either LUKS1 or LUKS2. Returns 1 in case of failure; 0 in case of # success. clevis_luks_read_slot() { - local DEV="${1}" - local SLT="${2}" + local DEV="${1:-}" + local SLT="${2:-}" if [ -z "${DEV}" ] || [ -z "${SLT}" ]; then echo "Need both a device and a slot as arguments." >&2 return 1 fi - local DATA_CODED='' + local jwe local MAX_LUKS1_SLOTS=8 local MAX_LUKS2_SLOTS=32 if cryptsetup isLuks --type luks1 "${DEV}"; then @@ -65,15 +70,16 @@ clevis_luks_read_slot() { local CLEVIS_UUID="cb6e8904-81ff-40da-a84a-07ab9ab5715e" local uuid - # Pattern from luksmeta: active slot uuid. - read -r _ _ uuid <<< "$(luksmeta show -d "${DEV}" | grep "^${SLT} *")" + # Pattern from luksmeta: slot active uuid. + uuid="$(luksmeta show -d "${DEV}" | sed -rn \ + "s|^${SLT}\s+active\s+(\S+)|\1|p")" - if [ "${uuid}" != ${CLEVIS_UUID}"" ]; then + if [ "${uuid}" != "${CLEVIS_UUID}" ]; then echo "Not a clevis slot!" >&2 return 1 fi - if ! DATA_CODED="$(luksmeta load -d "${DEV}" -s "${SLT}")"; then + if ! jwe="$(luksmeta load -d "${DEV}" -s "${SLT}")"; then echo "Cannot load data from ${DEV} slot:${SLT}!" >&2 return 1 fi @@ -94,10 +100,10 @@ clevis_luks_read_slot() { local token token=$(cryptsetup token export --token-id "${token_id}" "${DEV}") - DATA_CODED=$(jose fmt -j- -Og jwe -o- <<< "${token}" \ - | jose jwe fmt -i- -c) + jwe=$(jose fmt --json="${token}" --object --get jwe -o- \ + | jose jwe fmt -i- -c) - if [ -z "${DATA_CODED}" ]; then + if [ -z "${jwe}" ]; then echo "Cannot load data from ${DEV} slot:${SLT}!" >&2 return 1 fi @@ -105,51 +111,63 @@ clevis_luks_read_slot() { echo "${DEV} is not a supported LUKS device!" >&2 return 1 fi - echo "${DATA_CODED}" + echo "${jwe}" } # clevis_luks_used_slots() will return the list of used slots for a given LUKS # device. clevis_luks_used_slots() { - local DEV="${1}" + local DEV="${1:-}" + [ -z "${DEV}" ] && return 1 - local slots + local used_slots if cryptsetup isLuks --type luks1 "${DEV}"; then - readarray -t slots < <(cryptsetup luksDump "${DEV}" \ - | sed -rn 's|^Key Slot ([0-7]): ENABLED$|\1|p') + if ! used_slots=$(cryptsetup luksDump "${DEV}" 2>/dev/null \ + | sed -rn 's|^Key Slot ([0-7]): ENABLED$|\1|p'); then + return 1 + fi elif cryptsetup isLuks --type luks2 "${DEV}"; then - readarray -t slots < <(cryptsetup luksDump "${DEV}" \ - | sed -rn 's|^\s+([0-9]+): luks2$|\1|p') + if ! used_slots=$(cryptsetup luksDump "${DEV}" 2>/dev/null \ + | sed -rn 's|^\s+([0-9]+): luks2$|\1|p'); then + return 1 + fi else echo "${DEV} is not a supported LUKS device!" >&2 return 1 fi - echo "${slots[@]}" + echo "${used_slots}" } # clevis_luks_decode_jwe() will decode a given JWE. clevis_luks_decode_jwe() { - local jwe="${1}" + local jwe="${1:-}" + [ -z "${jwe}" ] && return 1 local coded - if ! coded=$(jose jwe fmt -i- <<< "${jwe}"); then + if ! coded=$(jose jwe fmt --input="${jwe}" 2>/dev/null); then return 1 fi - coded=$(jose fmt -j- -g protected -u- <<< "${coded}" | tr -d '"') - jose b64 dec -i- <<< "${coded}" + if ! coded="$(jose fmt --json="${coded}" --get protected --unquote=- \ + 2>/dev/null | tr -d '"')"; then + return 1 + fi + printf '%s' "${coded}" | jose b64 dec -i- 2>/dev/null } # clevis_luks_print_pin_config() will print the config of a given pin; i.e. # for tang it will display the associated url address, and for tpm2, the # properties in place, like the hash, for instance. clevis_luks_print_pin_config() { - local P="${1}" - local decoded="${2}" + local P="${1:-}" + local decoded="${2:-}" + + [ -z "${P}" ] && return 1 + [ -z "${decoded}" ] && return 1 local content - if ! content="$(jose fmt -j- -g clevis -g "${P}" -o- <<< "${decoded}")" \ - || [ -z "${content}" ]; then + if ! content="$(jose fmt --json="${decoded}" --get clevis --get "${P}" \ + --output=- 2>/dev/null)" || [ -z "${content}" ]; then return 1 fi @@ -157,7 +175,7 @@ clevis_luks_print_pin_config() { case "${P}" in tang) local url - url="$(jose fmt -j- -g url -u- <<< "${content}")" + url="$(jose fmt --json="${content}" --get url --unquote=- 2>/dev/null)" pin=$(printf '{"url":"%s"}' "${url}") printf "tang '%s'" "${pin}" ;; @@ -167,17 +185,19 @@ clevis_luks_print_pin_config() { local key local value for key in 'hash' 'key' 'pcr_bank' 'pcr_ids' 'pcr_digest'; do - if value=$(jose fmt -j- -g "${key}" -u- <<< "${content}"); then + if value="$(jose fmt --json="${content}" --get "${key}" \ + --unquote=- 2>/dev/null)"; then pin=$(printf '%s,"%s":"%s"' "${pin}" "${key}" "${value}") fi done # Remove possible leading comma. - pin=${pin/#,/} + pin=$(echo "${pin}" | sed -e 's/^,//') printf "tpm2 '{%s}'" "${pin}" ;; sss) local threshold - threshold=$(jose fmt -j- -Og t -o- <<< "${content}") + threshold="$(jose fmt --json="${content}" --object --get t --output=- \ + 2>/dev/null)" clevis_luks_process_sss_pin "${content}" "${threshold}" ;; *) @@ -189,7 +209,8 @@ clevis_luks_print_pin_config() { # clevis_luks_decode_pin_config() will receive a JWE and extract a pin config # from it. clevis_luks_decode_pin_config() { - local jwe="${1}" + local jwe="${1:-}" + [ -z "${jwe}" ] && return 1 local decoded if ! decoded=$(clevis_luks_decode_jwe "${jwe}"); then @@ -197,7 +218,8 @@ clevis_luks_decode_pin_config() { fi local P - if ! P=$(jose fmt -j- -Og clevis -g pin -u- <<< "${decoded}"); then + if ! P="$(jose fmt --json="${decoded}" --object --get clevis --get pin \ + --unquote=- 2>/dev/null)"; then return 1 fi @@ -207,8 +229,11 @@ clevis_luks_decode_pin_config() { # clevis_luks_join_sss_cfg() will receive a list of configurations for a given # pin and returns it as list, in the format PIN [cfg1, cfg2, ..., cfgN]. clevis_luks_join_sss_cfg() { - local pin="${1}" - local cfg="${2}" + local pin="${1:-}" + local cfg="${2:-}" + [ -z "${pin}" ] && return 1 + [ -z "${cfg}" ] && return 1 + cfg=$(echo "${cfg}" | tr -d "'" | sed -e 's/^,//') printf '"%s":[%s]' "${pin}" "${cfg}" } @@ -216,22 +241,22 @@ clevis_luks_join_sss_cfg() { # clevis_luks_process_sss_pin() will receive a JWE with information on the sss # pin config, and also its associated threshold, and will extract the info. clevis_luks_process_sss_pin() { - local jwe="${1}" - local threshold="${2}" - - local sss_tang - local sss_tpm2 - local sss - local pin_cfg - local pin - local cfg + local jwe="${1:-}" + local threshold="${2:-}" + [ -z "${jwe}" ] && return 1 + [ -z "${threshold}" ] && return 1 + + local sss_tang sss_tpm2 sss pin_cfg pin cfg + sss_tang='' sss_tpm2='' sss='' local coded - for coded in $(jose fmt -j- -Og jwe -Af- <<< "${jwe}"| tr -d '"'); do + for coded in $(jose fmt --json="${jwe}" --object --get jwe --Array \ + --foreach=- 2>/dev/null | tr -d '"'); do if ! pin_cfg="$(clevis_luks_decode_pin_config "${coded}")"; then continue fi - read -r pin cfg <<< "${pin_cfg}" + pin="$(echo "${pin_cfg}" | sed -rn 's|^(\S+)\s+(\S+)$|\1|p')" + cfg="$(echo "${pin_cfg}" | sed -rn 's|^(\S+)\s+(\S+)$|\2|p')" case "${pin}" in tang) sss_tang="${sss_tang},${cfg}" @@ -259,7 +284,7 @@ clevis_luks_process_sss_pin() { fi # Remove possible leading comma. - cfg=${cfg/#,/} + cfg=$(echo "${cfg}" | sed -e 's/^,//') pin=$(printf '{"t":%d,"pins":{%s}}' "${threshold}" "${cfg}") printf "sss '%s'" "${pin}" } @@ -267,8 +292,10 @@ clevis_luks_process_sss_pin() { # clevis_luks_read_pins_from_slot() will receive a given device and slot and # will then output its associated policy configuration. clevis_luks_read_pins_from_slot() { - local DEV="${1}" - local SLOT="${2}" + local DEV="${1:-}" + local SLOT="${2:-}" + [ -z "${DEV}" ] && return 1 + [ -z "${SLT}" ] && return 1 local jwe if ! jwe=$(clevis_luks_read_slot "${DEV}" "${SLOT}" 2>/dev/null); then diff --git a/src/luks/clevis-luks-list b/src/luks/clevis-luks-list index 40b68b84..88d65161 100755 --- a/src/luks/clevis-luks-list +++ b/src/luks/clevis-luks-list @@ -1,4 +1,5 @@ -#!/bin/bash -e +#!/bin/sh +set -eu # vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: # # Copyright (c) 2017-2019 Red Hat, Inc. @@ -23,7 +24,7 @@ SUMMARY="Lists pins bound to a LUKSv1 or LUKSv2 device" -function usage() { +usage() { echo >&2 echo "Usage: clevis luks list -d DEV [-s SLT]" >&2 echo >&2 @@ -36,11 +37,13 @@ function usage() { exit 1 } -if [ ${#} -eq 1 ] && [ "${1}" = "--summary" ]; then +if [ "${1:-}" = '--summary' ]; then echo "${SUMMARY}" exit 0 fi +DEV= +SLT= while getopts ":d:s:" o; do case "$o" in d) DEV=${OPTARG};; @@ -64,7 +67,7 @@ fi if [ -n "${SLT}" ]; then clevis_luks_read_pins_from_slot "${DEV}" "${SLT}" else - if ! used_slots=$(clevis_luks_used_slots "${DEV}"); then + if ! used_slots="$(clevis_luks_used_slots "${DEV}")"; then echo "No used slots detected for device ${DEV}!" >&2 exit 1 fi