Also improve reporting of recovery instances.
. "$KEYSLIB"/keyfunc.sh
defhelp <<HELP
-KEY RECOV
+[-i INST] KEY RECOV
Recover the named user KEY using a blob protected using the recovery key
RECOV; it is an error if RECOV is not currently revealed.
HELP
+inst=current
+while getopts "i:" opt; do
+ case "$opt" in
+ i) inst=$OPTARG ;;
+ *) usage_err ;;
+ esac
+done
+shift $(( $OPTIND - 1 ))
case $# in 2) ;; *) usage_err ;; esac
key=$1 recov=$2
parse_keylabel "$key"
if [ ! -d $kdir ]; then echo >&2 "$quis: unknown key \`$key'"; exit 1; fi
+checkword "recovery instance" "$inst"
checkword "recovery key label" "$recov"
case $kowner in
$USERV_USER) ;;
fi
umask 077
-recover $recov $kowner/$klabel >$knub.new
+recover $recov $inst $kowner/$klabel >$knub.new
nubbin=$(nubid <$knub.new)
case "$nubbin" in
"$nubid") ;;
}
recover () {
- recov=$1 label=$2
+ recov=$1 inst=$2 label=$3
## Recover a stashed secret, protected by RECOV and stored as LABEL, and
## write it to stdout.
checkword "recovery key label" "$recov"
+ checkword "recovery instance" "$inst"
checklabel "secret" "$label"
- rdir=$KEYS/recov/$recov/current
+ rdir=$KEYS/recov/$recov/$inst
if [ ! -f $rdir/$label.recov ]; then
- echo >&2 "$quis: no blob for \`$label' under recovery key \`$recov'"
+ echo >&2 "$quis: no blob for \`$label' under recovery key \`$recov/$inst'"
exit 1
fi
reqsafe
- nub=$SAFE/keys.reveal/$recov.current/nub
+ tag=$recov.$inst
+ nub=$SAFE/keys.reveal/$tag/nub
if [ ! -f $nub ]; then
- echo >&2 "$quis: current recovery key \`$recov' not revealed"
+ echo >&2 "$quis: current recovery key \`$recov/$inst' not revealed"
exit 1;
fi
mktmp
case $# in 0) ;; *) usage_err ;; esac
+## Collect information about available recovery keys.
if [ -d $KEYS/recov ]; then
cd $KEYS/recov
+
+ ## No keeper sets encountered yet.
kk=:
- for r in $(find . -type l -name current -print); do
- r=${r#./}; r=${r%/current}
- if ! expr >/dev/null "Q$r" : "Q$R_LABEL"; then continue; fi
- set _ $(echo $r | md5sum); rh=$2
- eval rcur_$rh=$(readlink $r/current) r_$rh=\$r
+
+ ## Iterate over recovery keys.
+ for r in *; do
+ if [ ! -d $r ]; then continue; fi
+
+ ## Now work through the instances of this recovery key.
for ri in $r/*; do
+
+ ## Get the instance number.
i=${ri##*/}
case "$i" in *[!0-9]*) continue ;; esac
+
+ ## Read the keeper sharing parameters.
for kp in $ri/*.param; do
+
+ ## Find the keeper name.
k=${kp##*/}; k=${k%.param}
+
+ ## Add this keeper to the list if we haven't already, and clear the
+ ## list of associated recovery keys.
case $kk in *:$k:*) ;; *) kk=$kk$k:; unset rr_$k ;; esac
- eval t_$k_$rh_$i='$(sharethresh $kp)'
- eval "rr_$k=\${rr_$k+\$rr_$k }$rh/$i"
+
+ ## Associate this recovery key instance with the keeper set, and
+ ## store information about the sharing.
+ eval t_$k_$r_$i='$(sharethresh $kp)'
+ eval "rr_$k=\${rr_$k+\$rr_$k }$r/$i"
done
done
done
fi
+## Now work through the keeper sets.
if [ ! -d $KEYS/keeper ]; then
echo >&2 "$quis: no keepers"
else
cd $KEYS/keeper
+
+ ## Iterate over the keeper sets.
+ firstp=t
for k in *; do
+
+ ## Make sure that this really looks like a keeper set.
checkword "keeper set label" "$k"
if [ ! -r $k/meta ]; then continue; fi
+
+ ## Read the keeper metadata, and print basic stuff about it.
read n hunoz <$k/meta
readmeta $k/0
+ case $firstp in t) firstp=nil ;; nil) echo ;; esac
echo "$k profile=$profile n=$n"
+
+ ## Print the sharing information, including the keeper nubids.
echo " share"
i=0; while [ $i -lt $n ]; do
nubid=$(cat $k/$i/nubid)
echo " $i nubid=$nubid"
i=$(( $i + 1 ))
done
+
+ ## Print the associated recovery keys.
echo " recov"
eval rr=\$rr_$k
for ri in $rr; do
- rh=${ri%/*} i=${ri##*/}
- eval r=\$r_$rh
- eval t=\$t_$k_$rh_$i
+
+ ## Pick out the hash and instance number, and extract the rest of the
+ ## data from this recovery key.
+ r=${ri%/*} i=${ri##*/}
+ eval t=\$t_$k_$r_$i
+
+ ## Start assembling an information line.
info="$r/$i t=$t"
- set $(echo $r/$i | tr / .) revealed
- eval rcur=\$rcur_$rh
- case $rcur in $i) set "$@" $(echo $r/current | tr / .) current ;; esac
+
+ ## Determine the revelation status of the recovery key. There are
+ ## maybe things to check: the revelation of the key by explicit
+ ## instance, or, if applicable, as the current instance. Build in the
+ ## positional parameters a sequence of DIR WHAT pairs to process.
+ set $r.$i revealed
+ eval rcur=\$rcur_$r
+ case $rcur in $i) set "$@" $r.current current ;; esac
while [ $# -gt 0 ]; do
rd=$SAFE/keys.reveal/$1 attr=$2; shift 2
if [ ! -d $rd ]; then
info="$info $attr=$ss"
fi
done
+
+ ## Print this information.
echo " $info"
done
done
case $# in 0) ;; *) usage_err ;; esac
+## Work through the recovery keys.
if [ ! -d $KEYS/recov ]; then
echo 2>&1 "$quis: no recovery keys"
else
cd $KEYS/recov
firstp=t
- for r in $(find . -type l -name current -print); do
- r=${r#./}; r=${r%/current}
- if ! expr >/dev/null "Q$r" : "Q$R_LABEL"; then continue; fi
- unset ri
+ for r in *; do
+ if [ ! -d $r ]; then continue; fi
+
+ ## Start printing a record for this key.
case $firstp in t) firstp=nil ;; nil) echo ;; esac
echo "$r"
+
+ ## Print information about the configured keeper set.
echo " keepers"
while read k t; do
read n hunoz <$KEYS/keeper/$k/meta
echo " $k t=$t n=$n"
done <$r/keepers
+
+ ## Print information about the various instances.
rcur=$(readlink $r/current)
for ri in $r/*; do
+
+ ## Extract and check the instance number.
i=${ri##*/}
case "$i" in *[!0-9]*) continue ;; esac
+
+ ## Start printing a subrecord.
echo " instance $i"
+
+ ## If this is the current instance, mention this.
case "$rcur" in $i) echo " current" ;; esac
+
+ ## Print basic facts about the instance.
readmeta $ri/store
nubid=$(cat $ri/store/nubid)
echo " profile $profile"
echo " nubid $nubid"
+
+ ## Print information about the keepers, including sharing stuff.
echo " keepers"
for kp in $ri/*.param; do
k=${kp##*/}; k=${k%.param}
t=$(sharethresh $kp)
echo " $k t=$t n=$n"
done
+
+ ## Print information about secrets protected by this recovery key
+ ## instance.
anyp=nil
for sf in $(cd $ri; find . -type f -name '*.recov' -print); do
s=${sf#./}
. "$KEYSLIB"/keyfunc.sh
defhelp <<HELP
-RECOV LABEL
+[-i INST] RECOV LABEL
Recover the secret LABEL using recovery key RECOV.
The recovery key must be revealed. The secret is written to stdout.
HELP
## Parse the command line.
+inst=current
+while getopts "i:" opt; do
+ case "$opt" in
+ i) inst=$OPTARG ;;
+ *) usage_err ;;
+ esac
+done
+shift $(( $OPTIND - 1 ))
case $# in 2) ;; *) usage_err ;; esac
recov=$1 label=$2
-checklabel "recovery key label" "$recov"
+checkword "recovery instance" "$inst"
+checkword "recovery key label" "$recov"
checklabel "secret" "$label"
## Do the recovery.
-recover $recov $label
+recover $recov $inst $label
###----- That's all, folks --------------------------------------------------
. "$KEYSLIB"/keyfunc.sh
defhelp <<HELP
-RECOV KEEPER
+[-i INST] RECOV KEEPER
Reveal a share of a recovery key distributed among keepers.
If enough shares have been revealed, reconstruct the recovery private key.
HELP
## Parse the command line.
+inst=current
+while getopts "i:" opt; do
+ case "$opt" in
+ i) inst=$OPTARG ;;
+ *) usage_err ;;
+ esac
+done
+shift $(( $OPTIND - 1 ))
case $# in 2) ;; *) usage_err ;; esac
recov=$1 keeper=$2; shift 2
-checklabel "recovery key" "$recov"
-case "$recov" in
- */*) ;;
- *) recov=$recov/current ;;
-esac
+checkword "recovery instance" "$inst"
+checkword "recovery key" "$recov"
checkword "keeper set label" "$keeper"
## Check that this is a sensible thing to do.
-if [ ! -f $KEYS/keeper/$keeper/meta ]; then
+kdir=$KEYS/keeper/$keeper
+if [ ! -f $kdir/meta ]; then
echo >&2 "$quis: unknown keeper set \`$keeper'"
exit 1
fi
-if [ ! -d $KEYS/recov/$recov ]; then
+if [ ! -l $KEYS/recov/$recov/current ]; then
echo >&2 "$quis: unknown recovery key \`$recov'"
exit 1
fi
-if [ ! -f $KEYS/recov/$recov/$keeper.param ]; then
+rdir=$KEYS/recov/$recov/$inst
+if [ ! -f $rdir/$keeper.param ]; then
echo >&2 "$quis: recovery key \`$recov' not kept by keeper set \`$keeper'"
exit 1
fi
cat >$tmp/secret
## Read the threshold from the recovery metadata.
-t=$(sharethresh $KEYS/recov/$recov/$keeper.param)
+t=$(sharethresh $rdir/$keeper.param)
## Find out which keeper index it corresponds to.
-read n hunoz <$KEYS/keeper/$keeper/meta
+read n hunoz <$kdir/meta
i=0
foundp=nil
while [ $i -lt $n ]; do
- c_sysprepare $KEYS/keeper/$keeper/$i
+ c_sysprepare $kdir/$i
nubbin=$(nubid <$tmp/secret)
- nubid=$(cat $KEYS/keeper/$keeper/$i/nubid)
+ nubid=$(cat $kdir/$i/nubid)
case "$nubbin" in "$nubid") foundp=t; break ;; esac
i=$(( $i + 1 ))
done
## Establish the recovery staging area. See whether we've done enough
## already.
reqsafe
-tag=$(echo $recov | tr / .)
+tag=$recov.$inst
mkdir -p -m700 $SAFE/keys.reveal
reveal=$SAFE/keys.reveal/$tag
if [ ! -d $reveal ]; then mkdir -m700 $reveal; fi
cd $reveal
if [ -f nub ]; then
- echo >&2 "$quis: recovery key \`$recov' already revealed"
+ echo >&2 "$quis: recovery key \`$recov/$inst' already revealed"
exit 1
fi
if [ -f $keeper.$i.share ]; then
echo >&2 "$quis: share $i already revealed"
else
- c_sysdecrypt $KEYS/keeper/$keeper/$i $tmp/secret \
- <$KEYS/recov/$recov/$keeper.$i.share \
+ c_sysdecrypt $kdir/$i $tmp/secret \
+ <$rdir/$keeper.$i.share \
>$keeper.$i.new
mv $keeper.$i.new $keeper.$i.share
fi
if [ $n -lt $t ]; then
echo >&2 "$quis: share $i revealed; $(( $t - $n )) more required"
else
- cat $KEYS/recov/$recov/$keeper.param $keeper.*.share >$keeper.shares
+ cat $rdir/$keeper.param $keeper.*.share >$keeper.shares
$bindir/shamir recover <$keeper.shares >nub.new
- c_sysprepare $KEYS/recov/$recov/store
+ c_sysprepare $rdir/store
nubbin=$(nubid <nub.new)
- nubid=$(cat $KEYS/recov/$recov/store/nubid)
+ nubid=$(cat $rdir/store/nubid)
case "$nubbin" in
"$nubid") ;;
*)
esac
mv nub.new nub
rm -f $keeper.*
- echo >&2 "$quis: recovery key \`$recov' revealed"
+ echo >&2 "$quis: recovery key \`$recov/$inst' revealed"
fi
###----- That's all, folks --------------------------------------------------