chiark / gitweb /
8f8e347634a752fe80dc063b29584b76a36690fd
[distorted-keys] / reveal
1 #! /bin/sh
2 ###
3 ### Reveal shares of a secret distributed among keepers
4 ###
5 ### (c) 2011 Mark Wooding
6 ###
7
8 ###----- Licensing notice ---------------------------------------------------
9 ###
10 ### This file is part of the distorted.org.uk key management suite.
11 ###
12 ### distorted-keys is free software; you can redistribute it and/or modify
13 ### it under the terms of the GNU General Public License as published by
14 ### the Free Software Foundation; either version 2 of the License, or
15 ### (at your option) any later version.
16 ###
17 ### distorted-keys is distributed in the hope that it will be useful,
18 ### but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ### GNU General Public License for more details.
21 ###
22 ### You should have received a copy of the GNU General Public License
23 ### along with distorted-keys; if not, write to the Free Software Foundation,
24 ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
26 set -e
27 case "${KEYSLIB+t}" in t) ;; *) echo >&2 "$0: KEYSLIB unset"; exit 1 ;; esac
28 . "$KEYSLIB"/keyfunc.sh
29
30 defhelp <<HELP
31 RECOV KEEPER [KEY]
32 Reveal a share of a recovery key distributed among keepers.
33
34 If enough shares have been revealed, reconstruct the recovery private key.
35 The key is read from KEY, or stdin if KEY is omitted or \`-'.
36 HELP
37 dohelp
38
39 ## Parse the command line.
40 case $# in
41   2) if [ -t 0 ]; then echo >&2 "$quis: stdin is a terminal"; exit 1; fi ;;
42   3) ;;
43   *) echo >&2 "$usage"; exit 1 ;;
44 esac
45 recov=$1 keeper=$2; shift 2
46 checklabel "recovery key" "$recov"
47 case "$recov" in
48   */*) ;;
49   *) recov=$recov/current ;;
50 esac
51 checkword "keeper set label" "$keeper"
52
53 ## Grab the key, because we'll need to read it several times.
54 tmp=$(mktmp); cleanup rmtmp
55 secret=$(cat -- "$@")
56 pub=$(ec_public /dev/stdin <<EOF
57 $secret
58 EOF
59 )
60
61 ## Read the threshold from the recovery metadata.
62 read param <$KEYS/recov/$recov/$keeper.param
63 case "$param" in
64   shamir-params:*) ;;
65   *)
66     echo >&2 "$quis: secret sharing parameter file damaged (wrong header)"
67     exit 1
68     ;;
69 esac
70 t=";${param#*:}"
71 case "$t" in
72   *";t="*) ;;
73   *)
74     echo >&2 "$quis: secret sharing parameter file damaged (missing t)"
75     exit 1
76     ;;
77 esac
78 t=${t#*;t=}
79 t=${t%%;*}
80
81 ## Find out which keeper index it corresponds to.
82 read n hunoz <$KEYS/keeper/$keeper/meta
83 i=0
84 foundp=nil
85 : "$pub"
86 while [ $i -lt $n ]; do
87   read cand <$KEYS/keeper/$keeper/$i.pub
88   : "$cand"
89   case "$pub" in "$cand") foundp=t; break ;; esac
90   i=$(( i + 1 ))
91 done
92 case $foundp in
93   nil) echo >&2 "$quis: key doesn't match keeper \`$keeper'"; exit 1 ;;
94 esac
95
96 ## Establish the recovery staging area.  See whether we've done enough
97 ## already.
98 mem=$(userv root claim-mem-dir </dev/null)
99 tag=$(echo $recov | tr / .)
100 mkdir -p -m700 $mem/keys.reveal
101 reveal=$mem/keys.reveal/$tag
102 if [ ! -d $reveal ]; then mkdir -m700 $reveal; fi
103 cd $reveal
104 if [ -f secret ]; then
105   echo >&2 "$quis: secret $recov already revealed"
106   exit 1
107 fi
108 if [ -f $keeper.$i ]; then
109   echo >&2 "$quis: share $i already revealed"
110   exit 1
111 fi
112
113 ## Decrypt the share.
114 umask 077
115 ec_decrypt /dev/stdin \
116   -i$KEYS/recov/$recov/$keeper.$i.share \
117   -o$keeper.$i.new <<EOF
118 $secret
119 EOF
120 mv $keeper.$i.new $keeper.$i
121
122 ## See if there's enough for a recovery.
123 n=0
124 for j in $keeper.*; do if [ -f "$j" ]; then n=$(( n + 1 )); fi; done
125 if [ $n -lt $t ]; then
126   echo >&2 "$quis: share $i revealed; $(( t - n )) more required"
127 else
128   cat $KEYS/recov/$recov/$keeper.param $keeper.* >$keeper.shares
129   shamir recover <$keeper.shares >secret.new
130   pubx=$(ec_public secret.new)
131   puby=$(cat $KEYS/recov/$recov/pub)
132   case "$pubx" in
133     "$puby") ;;
134     *)
135       echo >&2 "quis: recovered secret key doesn't match public key"
136       exit 1
137       ;;
138   esac
139   mv secret.new secret
140   echo >&2 "$quis: secret $recov revealed"
141 fi
142
143 ###----- That's all, folks --------------------------------------------------