Skip to content

Commit

Permalink
luks: get rid of bashisms in clevis-luks-common-functions
Browse files Browse the repository at this point in the history
As suggested in latchset#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'
  • Loading branch information
sergio-correia committed May 26, 2020
1 parent 0bea5c4 commit a66f0ae
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 55 deletions.
129 changes: 78 additions & 51 deletions src/luks/clevis-luks-common-functions
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -94,70 +100,82 @@ 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
else
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

local pin=
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}"
;;
Expand All @@ -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}"
;;
*)
Expand All @@ -189,15 +209,17 @@ 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
return 1
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

Expand All @@ -207,31 +229,34 @@ 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}"
}

# 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}"
Expand Down Expand Up @@ -259,16 +284,18 @@ 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}"
}

# 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
Expand Down
11 changes: 7 additions & 4 deletions src/luks/clevis-luks-list
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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
Expand All @@ -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};;
Expand All @@ -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
Expand Down

0 comments on commit a66f0ae

Please sign in to comment.