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