chiark / gitweb /
d221764bd3e21775ab33f6a4949697ac322d122c
[distorted-keys] / new-recov
1 #! /bin/sh
2 ###
3 ### Generate a new recovery key and split it 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:K ...]
32 Generate a new recovery secret, and split it among the available keepers.
33
34 The new secret will be called RECOV.  For each KEEPER set, the private key
35 wil be split into shares, and encrypted with the KEEPER's public keys; any K
36 of these shares can be used to reveal the original key.
37
38 If there is already a recovery key called RECOV then it will be rolled over.
39 The previous key must already be revealed.  If KEEPERs are listed, these
40 replace the existing keeper sets; otherwise the same keepers as before are
41 used.
42
43 If there is not a recovery key called RECOV then at least one keeper set must
44 be specified.
45 HELP
46 dohelp
47
48 ## Parse the command line.
49 case $# in 0) echo >&2 "$usage"; exit 1 ;; esac
50 recov=$1; shift
51 checkword "recovery key label" "$recov"
52 for k in "$@"; do
53   case "$k" in
54     *:*) ;;
55     *) echo >&2 "$quis: bad keeper spec \`$k'"; exit 1 ;;
56   esac
57   keeper=${k%:*} t=${k#*:}
58   checkword "keeper set label" "$keeper"
59   checknumber "keeper quorum" "$t"
60 done
61
62 ## Establish the keeper parameters.
63 rdir=$KEYS/recov/$recov
64 if [ ! -d $rdir ]; then mkdir -m755 -p $rdir; fi
65 case $# in
66   0)
67     kparam=$rdir/keepers
68     ;;
69   *)
70     for k in "$@"; do
71       keeper=${k%:*} t=${k#*:}
72       echo $keeper $t
73     done >$rdir/keepers.new
74     kparam=$rdir/keepers.new
75     ;;
76 esac
77 if [ ! -f $kparam ]; then echo >&2 "$quis: no keepers specified"; exit 1; fi
78
79 ## Make the new key and issue the shares.
80 tmp=$(mktmp); cleanup rmtmp
81 rm -rf $rdir/new
82 mkdir -m755 $rdir/new
83 cd $tmp
84 ec_keygen secret $rdir/new/pub
85 while read keeper k; do
86   read n hunoz <$KEYS/keeper/$keeper/meta
87   shamir issue $k/$n secret | {
88     read param
89     echo "$param" >$rdir/new/$keeper.param
90     i=0
91     while read share; do
92       echo $share |
93         ec_encrypt $KEYS/keeper/$keeper/$i.pub -o$rdir/new/$keeper.$i.share
94       i=$(( i + 1 ))
95     done
96   }
97 done <$kparam
98 rm -f secret
99
100 ## If there's an existing instance of this key, transfer the recovery blobs.
101 if [ ! -d $rdir/current ]; then
102   seq=0
103 else
104   seq=$(readlink $rdir/current)
105   mem=$(userv root claim-mem-dir </dev/null)
106   reveal=$mem/keys.reveal/$recov.current/secret
107   if [ ! -f $reveal ]; then
108     echo >&2 "$quis: current $recov key not revealed"
109     exit 1
110   fi
111
112   find $rdir/current/ -type f -name '*.recov' -print | while read name; do
113     name=${name#$rdir/current/}
114     case "$name" in */*) mkdir -p -m755 $rdir/new/${name%/*} ;; esac
115     ec_decrypt $reveal -i$rdir/current/$name |
116       ec_encrypt $rdir/new/pub -o$rdir/new/$name
117   done
118   rm -r $mem/keys.reveal/$recov.current
119 fi
120
121 ## Tidy up and commit.  Repointing the symlink is grim because, according to
122 ## POSIX rules, `mv foo bar' should rename `foo' to `bar/foo' is `bar' is a
123 ## symlink to a directory -- and there's no way of turning this behaviour
124 ## off.  The subterfuge here is due to Colin Watson.
125 cd $rdir
126 while [ -d $seq ]; do seq=$(( seq + 1 )); done
127 case $kparam in *.new) mv keepers.new keepers ;; esac
128 rm -f next
129 ln -s $seq next
130 mv new $seq
131 mkdir hack; mv next hack/current; mv hack/current .; rmdir hack
132
133 ###----- That's all, folks --------------------------------------------------