commit 8f4b0c65675135519391bc6eea127d039359639c
parent 9706ef1ab142aad95b7838c5c101ca2276410cb3
Author: Jaromil <jaromil@dyne.org>
Date: Wed, 19 Jun 2013 20:20:17 +0200
improvements to key handling
added a new 'change' command to change a Tomb's key
it replaces the same LUKS slot using luksChangeKey
Diffstat:
M | tomb | | | 213 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------- |
1 file changed, 177 insertions(+), 36 deletions(-)
diff --git a/tomb b/tomb
@@ -222,6 +222,30 @@ EOF
return 0
}
+# check if a filename is a valid tomb
+is_valid_tomb() {
+ xxx "is_valid_tomb $1"
+ # argument check
+ { test "$1" = "" } && {
+ _warning "Tomb file is missing from arguments"; return 1 }
+ # file checks
+ { test -r "$1" } || {
+ _warning "Tomb file not found: $1"; return 1 }
+ { test -f "$1" } || {
+ _warning "Tomb file is not a regular file: $1"; return 1 }
+ # check file type (if its a Luks fs)
+ file "$1" | grep -i 'luks encrypted file' >/dev/null
+ { test $? = 0 } || {
+ _warning "File is not a valid tomb: $1"; return 1 }
+ # check if its already open
+ tombfile=`basename $1`
+ tombname=${tombfile%%\.*}
+ mount -l | grep "${tombfile}.*\[$tombname\]$" > /dev/null
+ { test $? = 0 } && {
+ _warning "Tomb is currently in use: $tombname"; return 1 }
+ _message "Valid tomb file found: $1"
+ return 0
+}
# }}}
# {{{ Commandline interaction
@@ -438,16 +462,20 @@ check_bin() {
# {{{ Key operations
-
# This function retrieves a tomb key specified on commandline or one
# laying nearby the tomb if found, or from stdin if the option was
# selected. It also runs validity checks on the file. Callers should
# always use drop_key() when done with all key operations.
# On success returns 0 and prints out the full path to the key
load_key() {
- tombdir=`dirname $1`
- tombfile=`basename $1`
- tombname=${tombfile%%\.*}
+ # take the name of a tomb file as argument
+ # this is used for guessing if the key is nearby
+ { test "$1" = "" } || {
+ tombdir=`dirname $1`
+ tombfile=`basename $1`
+ tombname=${tombfile%%\.*}
+ }
+
if option_is_set -k ; then
if [[ "`option_value -k`" == "-" ]]; then
xxx "load_key reading from stdin"
@@ -594,8 +622,18 @@ drop_key() {
#$1 is the keyfile we are checking
is_valid_key() {
+ xxx "is_valid_key $1"
+ # argument check
+ { test "$1" = "" } && {
+ _warning "Key file is missing from arguments"; return 1 }
+ # file checks
+ { test -r "$1" } || {
+ _warning "Key file not found: $1"; return 1 }
+ { test -f "$1" } || {
+ _warning "Key file is not a regular file: $1"; return 1 }
# this header validity check is a virtuosism by Hellekin
- [[ `file =(awk '/^-+BEGIN/,0' $1)` =~ PGP ]] && return 0
+ [[ `file =(awk '/^-+BEGIN/,0' $1)` =~ PGP ]] && {
+ _message "Valid key file found: $1"; return 0 }
# if no BEGIN header found then we try to recover it
[[ `file $1 -bi` =~ text/plain ]] && {
_warning "Key data found with missing headers, attempting recovery"
@@ -658,7 +696,7 @@ get_lukskey() {
ret=$?
unset tombpass
- else # using status-file in gpg != 1.4.12
+ else # using status-file in gpg != 1.4.11
res=`safe_filename lukskey`
{ test $? = 0 } || { unset tombpass; die "Fatal error creating temp file." }
@@ -666,7 +704,8 @@ get_lukskey() {
print ${tombpass} | \
gpg --batch --passphrase-fd 0 --no-tty --no-options --status-fd 2 \
--no-mdc-warning --no-permission-warning --no-secmem-warning \
- -d "${keyfile}" 2>$res
+ -d "${keyfile}" 2> $res
+
unset tombpass
grep 'DECRYPTION_OKAY' $res
ret=$?; rm -f $res
@@ -681,7 +720,9 @@ get_lukskey() {
# honored options: --kdf --tomb-pwd
gen_key() {
# $1 the lukskey to encrypt
- local lukskey=$1
+# $2 is the --cipher-algo to use (string taken by GnuPG)
+ local lukskey="$1"
+ local algo="$2"
# here user is prompted for key password
local tombpass=""
local tombpasstmp=""
@@ -730,11 +771,13 @@ gen_key() {
header="_KDF_pbkdf2sha1_${pbkdf2_salt}_${pbkdf2_iter}_64\n"
}
+
print -n $header
print "${tombpass}" \
- | gpg --openpgp --batch --no-options --no-tty --passphrase-fd 0 2>/dev/null \
- -o - -c -a ${lukskey}
+ | gpg --openpgp --force-mdc --cipher-algo ${algo} \
+ --batch --no-options --no-tty --passphrase-fd 0 --status-fd 2 \
+ -o - -c -a ${lukskey}
unset tombpass
}
@@ -855,22 +898,24 @@ exhume_key() {
forge_key() {
- _message "Commanded to forge key $1"
+ xxx "forge_key()"
+ # can be specified both as simple argument or using -k
+ local destkey="$1"
+ { option_is_set -k } && { destkey="`option_value -k`" }
- { test "$1" = "" } && {
+ { test "$destkey" = "" } && {
_warning "no key name specified for creation"
return 1 }
- { test -r "$1" } && {
+ { test -r "$destkey" } && {
_warning "Forging this key would overwrite an existing file. Operation aborted."
- die "`ls -lh $1`" }
+ die "`ls -lh $destkey`" }
# if swap is on, we remind the user about possible data leaks to disk
if ! option_is_set -f && ! option_is_set --ignore-swap; then check_swap; fi
-
# create the keyfile in tmpfs so that we leave less traces in RAM
- keytmp=`safe_dir forge`
+ local keytmp=`safe_dir forge`
(( $? )) && die "error creating temp dir"
xxx "safe_dir at $keytmp"
@@ -881,7 +926,13 @@ forge_key() {
die "operation aborted."
fi
- tombkey="$1"
+ local algo
+ { option_is_set -o } && { algopt="`option_value -o`" }
+ algo=${algopt:-AES256}
+
+ _message "Commanded to forge key $destkey with cipher algorithm $algo"
+
+ local tombkey="$destkey"
_message "this operation takes time, keep using this computer on other tasks,"
_message "once done you will be asked to choose a password for your tomb."
@@ -890,7 +941,7 @@ forge_key() {
touch ${keytmp}/tomb.tmp
chmod 0600 ${keytmp}/tomb.tmp
- random_source=/dev/random
+ local random_source=/dev/random
if option_is_set --use-urandom; then
random_source=/dev/urandom
fi
@@ -913,8 +964,7 @@ forge_key() {
tombname="$tombkey"
# the gen_key() function takes care of the new key's encryption
- gen_key ${keytmp}/tomb.tmp > ${tombkey}
-
+ gen_key "${keytmp}/tomb.tmp" "$algo" > ${tombkey}
# this does a check on the file header
if ! is_valid_key ${tombkey}; then
_warning "The key does not seem to be valid"
@@ -1044,7 +1094,7 @@ lock_tomb_with_key() {
die "Aborting operations: error loading key $tombkey" }
# make sure to call drop_key later
- # the encryption cipher for a tomb can be set at creation using -o
+ # the encryption cipher for a tomb can be set when locking using -o
if option_is_set -o; then
cipher="`option_value -o`"
else
@@ -1105,6 +1155,90 @@ lock_tomb_with_key() {
}
+# This function changes the key that locks a tomb
+change_tomb_key() {
+ if ! option_is_set -f && ! option_is_set --ignore-swap; then check_swap; fi
+
+ { option_is_set -k } || { die "Specify the new key with -k" }
+ newkey="`option_value -k`"
+
+ { is_valid_key "$newkey" } || {
+ die "New key invalid. Check your usage of the --key option." }
+
+ oldkey="$1"
+ { is_valid_key "$oldkey" } || {
+ die "Old key invalid. Check your usage of the first argument." }
+
+ { is_valid_tomb "$2" } || {
+ die "Specify the name of a tomb as second argument" }
+
+ nstloop=`losetup -f`
+ { test $? = 255 } && {
+ die "Too many tombs are open. Please close any of them to proceed." }
+ losetup -f "$2"
+ cryptsetup isLuks ${nstloop}
+ # is it a LUKS encrypted nest? we check one more timesee cryptsetup(1)
+ { test $? = 0 } || {
+ losetup -d "$nstloop"
+ die "Not a valid LUKS encrypted volume: $2" }
+
+ # we have everything, prepare to mount
+ yes "Changing lock on tomb $tombname"
+ _message "old key: $oldkey"
+ _message "new key: $newkey"
+
+ # render the mapper
+ mapdate=`date +%s`
+ # save date of mount in minutes since 1970
+ mapper="tomb.${tombname}.${mapdate}.`basename $nstloop`"
+
+
+ # load the new key from the -k option
+ tombkey=`load_key`
+ { test $? = 0 } || {
+ die "Aborting operations: error loading new key $tombkey" }
+
+ newkeypass=`ask_key_password $tombkey`
+ { test $? = 0 } || {
+ die "No valid password supplied for the new key" }
+ newkeyfile="`safe_filename newkey`"
+ get_lukskey "$newkeypass" "$newkey" > $newkeyfile
+
+ # load the old key
+ oldkeypass="`ask_key_password $oldkey`"
+ { test $? = 0 } || {
+ die "No valid password supplied for the old key" }
+
+ # luksOpen the tomb (not really mounting, just on the loopback)
+ get_lukskey "$oldkeypass" "$oldkey" | \
+ cryptsetup --key-file - luksOpen ${nstloop} ${mapper}
+ { test $? = 0 } || {
+ losetup -d "$nstloop"
+ die "Unexpected error in luksOpen." }
+
+ get_lukskey "$oldkeypass" "$oldkey" | \
+ cryptsetup --key-file - luksChangeKey "$nstloop" "$newkeyfile"
+ { test $? = 0 } || {
+ losetup -d "$nstloop"
+ die "Unexpected error in luksChangeKey." }
+
+ cryptsetup luksClose "${mapper}"
+ { test $? = 0 } || {
+ losetup -d "$nstloop"
+ die "Unexpected error in luksClose." }
+
+
+ drop_key
+ unset tombpass
+ ${=WIPE} "$newkeyfile"
+ losetup -d ${nstloop}
+
+ yes "Succesfully changed key for tomb: $2"
+ _message "The new key is: $newkey"
+
+ return 0
+}
+
# backward compatibility
create_tomb() {
xxx "create_tomb(): ${=@} ${=OLDARGS}"
@@ -1922,35 +2056,36 @@ main() {
# -force and NOT -f
main_opts=(q -quiet=q D -debug=D h -help=h v -version=v U: -uid=U G: -gid=G T: -tty=T -no-color -unsecure-dev-mode)
subcommands_opts[__default]=""
- subcommands_opts[open]="f n -nohook=n k: -key=k o: -mount-options=o -ignore-swap -sudo-pwd: -tomb-pwd:"
+ subcommands_opts[open]="f -force n -nohook=n k: -key=k o: -ignore-swap -sudo-pwd: -tomb-pwd: "
subcommands_opts[mount]=${subcommands_opts[open]}
subcommands_opts[create]="" # deprecated, will issue warning
- subcommands_opts[forge]="f -force -ignore-swap k: -key=k -kdf: -tomb-pwd: -use-urandom"
- subcommands_opts[dig]="f -force -ignore-swap s: -size=s"
- subcommands_opts[lock]="f -force -ignore-swap s: -size=s k: -key=k -sudo-pwd: -tomb-pwd:"
+ subcommands_opts[forge]="f -force -ignore-swap k: -key=k -kdf: o: -tomb-pwd: -use-urandom "
+ subcommands_opts[dig]="f -force -ignore-swap s: -size=s "
+ subcommands_opts[lock]="f -force -ignore-swap k: -key=k o: -sudo-pwd: -tomb-pwd: "
+ subcommands_opts[change]="f -force -ignore-swap k: -key=k -sudo-pwd: -tomb-pwd: "
subcommands_opts[passwd]="f -ignore-swap -kdf: -tomb-old-pwd: -tomb-pwd: "
- subcommands_opts[close]="-sudo-pwd:"
+ subcommands_opts[close]="-sudo-pwd: "
subcommands_opts[help]=""
subcommands_opts[slam]=""
- subcommands_opts[list]="-get-mountpoint"
+ subcommands_opts[list]="-get-mountpoint "
subcommands_opts[index]=""
subcommands_opts[search]=""
subcommands_opts[help]=""
- subcommands_opts[bury]="f -force k: -key=k -tomb-pwd:"
- subcommands_opts[exhume]="f -force k: -key=k -tomb-pwd:"
- subcommands_opts[decompose]=""
- subcommands_opts[recompose]=""
- subcommands_opts[install]=""
+ subcommands_opts[bury]="f -force k: -key=k -tomb-pwd: "
+ subcommands_opts[exhume]="f -force k: -key=k -tomb-pwd: "
+ # subcommands_opts[decompose]=""
+ # subcommands_opts[recompose]=""
+ # subcommands_opts[install]=""
subcommands_opts[askpass]=""
subcommands_opts[mktemp]=""
subcommands_opts[source]=""
- subcommands_opts[resize]="f -force -ignore-swap s: -size=s k: -key=k -tomb-pwd:"
- subcommands_opts[check]="-ignore-swap"
+ subcommands_opts[resize]="f -force -ignore-swap s: -size=s k: -key=k -tomb-pwd: "
+ subcommands_opts[check]="-ignore-swap "
# subcommands_opts[translate]=""
### Detect subcommand
@@ -1973,7 +2108,7 @@ main() {
fi
unset discardme
if ! zparseopts -M -E -D -Adiscardme ${every_opts}; then
- error "error parsing"
+ die "error parsing"
return 127
fi
unset discardme
@@ -2055,6 +2190,12 @@ main() {
check_priv
lock_tomb_with_key ${=PARAM}
;;
+
+ change)
+ check_priv
+ change_tomb_key ${=PARAM}
+ ;;
+
# backward compat
create)
_warning "The create command is deprecated, please use dig, forge and lock instead."
@@ -2122,7 +2263,7 @@ EOF
option_is_set -v && {
cat <<EOF
-GnuPG available ciphers:
+Key forging algorithms (GnuPG symmetric ciphers):
`list_gnupg_ciphers`
EOF
return 0