#!/bin/bash -e # vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: # # Copyright (c) 2016 Red Hat, Inc. # Author: Harald Hoyer # Author: Nathaniel McCallum # # 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 . # SUMMARY="Binds a LUKS device using the specified policy" UUID=cb6e8904-81ff-40da-a84a-07ab9ab5715e function usage() { echo >&2 echo "Usage: clevis luks bind [-f] [-s SLT] [-k KEY] -d DEV PIN CFG" >&2 echo >&2 echo "$SUMMARY": >&2 echo >&2 echo " -f Do not prompt for LUKSMeta initialization" >&2 echo >&2 echo " -d DEV The LUKS device on which to perform binding" >&2 echo >&2 echo " -s SLT The LUKS slot to use" >&2 echo >&2 echo " -k KEY Non-interactively read LUKS password from KEY file" >&2 echo " -k - Non-interactively read LUKS password from standard input" >&2 echo >&2 exit 1 } if [ $# -eq 1 -a "$1" == "--summary" ]; then echo "$SUMMARY" exit 0 fi while getopts ":hfd:s:k:" o; do case "$o" in f) FRC=-f;; d) export DEV=$OPTARG;; s) SLT=$OPTARG;; k) KEY=$OPTARG;; *) usage;; esac done if [ -z "$DEV" ]; then echo "Did not specify a device!" >&2 usage fi if ! cryptsetup isLuks "$DEV"; then echo "$DEV is not a LUKS device!" >&2 exit 1 fi if ! PIN=${@:$((OPTIND++)):1} || [ -z "$PIN" ]; then echo "Did not specify a pin!" >&2 usage fi if ! CFG=${@:$((OPTIND++)):1} || [ -z "$CFG" ]; then echo "Did not specify a pin config!" >&2 usage fi if [ -n "$KEY" ]; then if [ "$KEY" == "-" ]; then if cryptsetup isLuks --type luks1 "$DEV"; then if ! luksmeta test -d $DEV && [ -z "$FRC" ]; then echo "Cannot use '-k-' without '-f' unless already initialized!" >&2 usage fi fi elif ! [ -f "$KEY" ]; then echo "Key file '$KEY' not found!" >&2 exit 1 fi fi # Generate a key with the same entropy as the LUKS Master Key dump=`cryptsetup luksDump $DEV` if cryptsetup isLuks --type luks1 "$DEV"; then filt=`sed -rn 's|MK bits:[ \t]*([0-9]+)|\1|p' <<< "$dump"` else filt=`sed -rn 's|^\s+Key:\s+([0-9]+) bits\s*$|\1|p' <<< "$dump"` fi bits=`sort -n <<<"$filt" | tail -n 1` export key=`pwmake $bits` # Encrypt the new key jwe=`echo -n "$key" | clevis encrypt "$PIN" "$CFG"` # If necessary, initialize the LUKS volume if cryptsetup isLuks --type luks1 "$DEV" && ! luksmeta test -d "$DEV"; then luksmeta init -d "$DEV" $FRC fi # Get the old key case "$KEY" in "") read -s -p "Enter existing LUKS password: " old; echo;; -) old=`/bin/cat`;; *) old=`/bin/cat "$KEY"`;; esac # Add the new key if [ -n "$SLT" ]; then if ! echo -e "$old\n$key" | cryptsetup luksAddKey --key-slot $SLT $DEV; then echo "Error while adding new key to LUKS header!" >&2 exit 1 fi elif ! SLT=`echo -e "$old\n$key" \ | cryptsetup luksAddKey -v $DEV \ | sed -rn 's|^Key slot ([0-9]+) created\.$|\1|p'`; then echo "Error while adding new key to LUKS header!" >&2 exit 1 fi if cryptsetup isLuks --type luks1 "$DEV"; then if ! echo -n $jwe | luksmeta save -d "$DEV" -u "$UUID" -s $SLT 2>/dev/null; then echo "Error while saving Clevis metadata in LUKSMeta!" >&2 cryptsetup luksRemoveKey "$DEV" <<<"$key" exit 1 fi else jwe=`jose jwe fmt -i- <<<"$jwe"` # Convert to JSON Serialization tok="{\"type\":\"clevis\",\"keyslots\":[\"$SLT\"],\"jwe\":$jwe}" if ! cryptsetup token import "$DEV" <<<"$tok" ; then echo "Error while saving Clevis metadata as a LUKS token!" >&2 cryptsetup luksRemoveKey "$DEV" <<<"$key" exit 1 fi fi