chiark / gitweb /
claim-dir, debian/distorted-keys.postinst: Let `keys' run `claim-dir'.
[distorted-keys] / 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 [-p PROFILE] RECOV [KEEPER:K ...] [-- OPTION=VALUE ...]
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
47 ## Parse the command line.
48 profile=${recov_profile-recovery}
49 while getopts "p:" opt; do
50   case "$opt" in
51     p) profile=$OPTARG ;;
52     *) usage_err ;;
53   esac
54 done
55 shift $(( $OPTIND - 1 ))
56 case $# in 0) usage_err ;; esac
57 recov=$1; shift
58 checkword "recovery key label" "$recov"
59 checkword "profile label" "$profile"
60 nkeep=0
61 for k in "$@"; do
62   case "$k" in
63     --) break ;;
64     *:*) ;;
65     *) echo >&2 "$quis: bad keeper spec \`$k'"; exit 1 ;;
66   esac
67   keeper=${k%:*} t=${k#*:} nkeep=$(( $nkeep + 1 ))
68   checkword "keeper set label" "$keeper"
69   checknumber "keeper quorum" "$t"
70 done
71
72 ## Establish the keeper parameters.
73 rdir=$KEYS/recov/$recov
74 if [ ! -d $rdir ]; then mkdir -m755 -p $rdir; fi
75 case $nkeep in
76   0)
77     kparam=$rdir/keepers
78     ;;
79   *)
80     for k in "$@"; do
81       case "$k" in --) break ;; esac
82       keeper=${k%:*} t=${k#*:}
83       echo $keeper $t
84     done >$rdir/keepers.new
85     kparam=$rdir/keepers.new
86     ;;
87 esac
88 if [ ! -f $kparam ]; then echo >&2 "$quis: no keepers specified"; exit 1; fi
89
90 ## Make the new key and issue the shares.
91 mktmp
92 rm -rf $rdir/new
93 mkdir -m755 $rdir/new
94 cd $tmp
95 while :; do case "$#,$1" in
96     0,) break ;;
97     *,*,*) ;;
98     *,--) break ;;
99   esac
100   shift
101 done
102 c_gensyskey $profile $rdir/new/store secret recov="$recov"
103 while read keeper k; do
104   read n hunoz <$KEYS/keeper/$keeper/meta
105   $bindir/shamir issue $k/$n secret | {
106     read param
107     echo "$param" >$rdir/new/$keeper.param
108     i=0
109     while read share; do
110       c_sysencrypt $KEYS/keeper/$keeper/$i >$rdir/new/$keeper.$i.share <<EOF
111 $share
112 EOF
113       i=$(( $i + 1 ))
114     done
115   }
116 done <$kparam
117 rm -f secret
118
119 ## If there's an existing instance of this key, transfer the recovery blobs.
120 if [ ! -d $rdir/current ]; then
121   seq=0
122 else
123   seq=$(readlink $rdir/current)
124   reqsafe
125   reveal=$SAFE/keys.reveal/$recov.current/secret
126   if [ ! -f $reveal ]; then
127     echo >&2 "$quis: current $recov key not revealed"
128     exit 1
129   fi
130
131   find $rdir/current/ -type f -name '*.recov' -print | while read name; do
132     name=${name#$rdir/current/}
133     case "$name" in */*) mkdir -p -m755 $rdir/new/${name%/*} ;; esac
134     c_sysdecrypt $rdir/current/store $reveal <$rdir/current/$name >tmp
135     c_sysencrypt $rdir/new/store <tmp >$rdir/new/$name
136     rm tmp
137   done
138   rm -r $SAFE/keys.reveal/$recov.current
139 fi
140
141 ## Tidy up and commit.  Repointing the symlink is grim because, according to
142 ## POSIX rules, `mv foo bar' should rename `foo' to `bar/foo' is `bar' is a
143 ## symlink to a directory -- and there's no way of turning this behaviour
144 ## off.  The subterfuge here is due to Colin Watson.
145 cd $rdir
146 while [ -d $seq ]; do seq=$(( $seq + 1 )); done
147 case $kparam in *.new) mv keepers.new keepers ;; esac
148 rm -f next
149 ln -s $seq next
150 mv new $seq
151 mkdir hack; mv next hack/current; mv hack/current .; rmdir hack
152
153 ###----- That's all, folks --------------------------------------------------