123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- #!/bin/bash -e
- # vim: set ts=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
- #
- # Copyright (c) 2018, 2020 Red Hat, Inc.
- # Author: Radovan Sroka <rsroka@redhat.com>
- # Author: Sergio Correia <scorreia@redhat.com>
- #
- # 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 <http://www.gnu.org/licenses/>.
- #
- . clevis-luks-common-functions
- SUMMARY="Report tang keys' rotations"
- if [ "${1}" = "--summary" ]; then
- echo "${SUMMARY}"
- exit 0
- fi
- report_compare() {
- local adv_keys="${1}"
- local mdata_keys="${2}"
- [ -z "${adv_keys}" ] && return 1
- [ -z "${mdata_keys}" ] && return 1
- local thp keys
- for thp in $(printf '%s' "${mdata_keys}" | jose jwk thp --input=-); do
- if ! printf '%s' "${adv_keys}" | jose jwk thp --input=- \
- --find "${thp}" >/dev/null; then
- keys="$(printf '%s %s' "${keys}" "${thp}")"
- fi
- done
- printf '%s' "${keys}"
- }
- report_tang() {
- local content="${1}"
- [ -z "${content}" ] && return 1
- local url
- if ! url="$(jose fmt --json="${content}" --get url --unquote=-)" \
- || [ -z "${url}" ]; then
- echo "Invalid tang metadata; URL not found" >&2
- return 1
- fi
- local jws
- if ! jws="$(curl -sfg "${url}/adv")"; then
- echo "Unable to fetch advertisement (${url}/adv)" >&2
- return 1
- fi
- local adv_keys
- if ! adv_keys="$(jose fmt --json="${jws}" --object --get payload \
- --string --b64load --object --get keys \
- --array --unwind --output=-)"; then
- echo "Advertisement is malformed" >&2
- return 1
- fi
- # Check advertisement validity.
- local ver
- if ! ver="$(printf '%s' "${adv_keys}" | jose jwk use --input=- \
- --required \
- --use=verify \
- --output=-)"; then
- echo "Unable to validate advertisement" >&2
- return 1
- fi
- if ! printf '%s' "${ver}" | jose jws ver --input="${jws}" --key=- \
- --all; then
- echo "Advertisement is missing signatures" >&2
- return 1
- fi
- local mdata_keys
- if ! mdata_keys="$(jose fmt --json="${content}" --get adv --output=-)" \
- || [ -z "${mdata_keys}" ]; then
- echo "Keys from clevis metadata not found" >&2
- return 1
- fi
- report_compare "${adv_keys}" "${mdata_keys}"
- }
- report_sss() {
- local content="${1}"
- [ -z "${content}" ] && return 1
- local jwe
- for jwe in $(jose fmt --json="${content}" --get jwe --foreach=-); do
- jwe="$(printf '%s' "${jwe}" | sed -e 's/"//g')"
- report_decode "${jwe}"
- done
- }
- report_decode() {
- local data64="${1}"
- [ -z "${data64}" ] && return 1
- local data
- if ! data="$(clevis_luks_decode_jwe "${data64}")" || [ -z "${data}" ]; then
- echo "Unable to decode metadata" >&2
- exit 1
- fi
- local pin
- if ! pin="$(jose fmt --json="${data}" --get clevis --get pin --unquote=-)" \
- || [ -z "${pin}" ]; then
- echo "Pin not found in clevis metadata" >&2
- exit 1
- fi
- local content
- if ! content="$(jose fmt --json="${data}" --get clevis --get "${pin}" \
- --output=-)" || [ -z "${content}" ]; then
- echo "Invalid pin metadata; no content found" >&2
- return 1
- fi
- case "${pin}" in
- tang)
- report_tang "${content}"
- ;;
- sss)
- report_sss "${content}"
- ;;
- esac
- }
- usage_and_exit () {
- exec >&2
- echo "Usage: clevis luks report [-q] [-r] -d DEV -s SLOT"
- echo
- echo "${SUMMARY}"
- echo
- echo " -d DEV The LUKS device to check for key rotations"
- echo
- echo " -s SLT The LUKS slot to use"
- echo
- echo " -q Quiet mode; do not prompt for using 'clevis luks regen'"
- echo
- echo " -r Regenerate binding with 'clevis luks regen -q -d DEV -s SLOT'"
- echo
- exit "${1}"
- }
- while getopts "hd:s:rq" o; do
- case "${o}" in
- d) DEV="${OPTARG}";;
- h) usage_and_exit 0;;
- r) ROPT="regen";;
- s) SLT="${OPTARG}";;
- q) QOPT="quiet";;
- *) usage_and_exit 1;;
- esac
- done
- if [ -z "${DEV}" ]; then
- echo "Did not specify a device!" >&2
- exit 1
- fi
- if [ -z "${SLT}" ]; then
- echo "Did not specify a slot!" >&2
- exit 1
- fi
- if ! data64="$(clevis_luks_read_slot "${DEV}" "${SLT}")" \
- || [ -z "${data64}" ]; then
- # Error message was already displayed by clevis_luks_read_slot(),
- # at this point.
- exit 1
- fi
- if ! keys="$(report_decode "${data64}")"; then
- echo "Unable to verify whether there are rotated keys" >&2
- exit 1
- fi
- # No rotated keys.
- [ -z "${keys}" ] && exit 0
- echo "The following keys are not in the current advertisement and were probably rotated:"
- for k in ${keys}; do
- printf ' %s\n' "${k}"
- done
- if [ -z "${QOPT}" ] && [ -z "${ROPT}" ]; then
- read -r -p "Do you want to regenerate the binding with \"clevis luks regen -q -d ${DEV} -s ${SLT}\"? [ynYN] " ans
- if [ "${ans}" = "y" ] || [ "${ans}" = "Y" ]; then
- ROPT="regen"
- fi
- fi
- if [ "${ROPT}" = "regen" ]; then
- if ! EXE="$(command -v clevis-luks-regen)" || [ -z "${EXE}" ]; then
- echo "Unable to find clevis luks regen" >&2
- exit 1
- fi
- exec "${EXE}" -q -d "${DEV}" -s "${SLT}"
- fi
- exit 1
|