chiark / gitweb /
bsmtp-pull: drop -2; avoid connection sharing
[bin.git] / signkey
1 #!/usr/bin/perl
2 # signkey.pl
3 # $Id: signkey.pl 303 2004-04-23 22:59:05Z scott $
4 #
5 # Sign each UID of a key individually, mailing the exported version
6 # encrypted to the e-mail address given.
7 #
8 # Copyright (C) 2003 Scott James Remnant <scott@netsplit.com>.
9 #
10 # Permission is hereby granted, free of charge, to any person obtaining
11 # a copy of this software and associated documentation files (the
12 # "Software"), to deal in the Software without restriction, including
13 # without limitation the rights to use, copy, modify, merge, publish,
14 # distribute, sublicense, and/or sell copies of the Software, and to
15 # permit persons to whom the Software is furnished to do so, subject to
16 # the following conditions:
17
18 # The above copyright notice and this permission notice shall be
19 # included in all copies or substantial portions of the Software.
20
21 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24 # IN NO EVENT SHALL SOFTWARE IN THE PUBLIC INTEREST, INC. BE LIABLE FOR
25 # ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
26 # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
29 $name = $ENV{DEBFULLNAME};
30 $mail = $ENV{DEBEMAIL};
31 unless ($name && $mail) {
32         print STDERR "DEBFULLNAME and DEBEMAIL environment variables not set\n";
33         exit 1
34 }
35
36 if ($ARGV[0] && -f $ARGV[0]) {
37         open KEYS, $ARGV[0];
38         @keys = <KEYS>;
39         foreach (@keys) { chomp; }
40         close KEYS;
41 } else {
42         @keys = @ARGV;
43 }
44
45 unless (@keys) {
46         print STDERR "Usage: $0 < FILENAME | KEYS... >\n\n";
47         print STDERR "FILENAME  newline separated list of key information\n";
48         print STDERR "KEYS      key information\n";
49         exit 1;
50 }
51
52 @gpg = ("gpg", "--no-auto-check-trustdb", "--batch", "--yes", "--armor",
53         "--always-trust");
54 $gpg = join(" ", @gpg);
55
56 system "stty -echo";
57 print "GPG Passphrase: ";
58 $pass = <STDIN>;
59 system "stty echo";
60 print "\n";
61
62 foreach $key (@keys) {
63         print "*" x 80, "\n";
64         eval { &sign_key($key); };
65         if ($@) {
66                 print STDERR "*** Error processing $key\n";
67                 print STDERR "$@\n";
68         }
69         print "*" x 80, "\n\n\n";
70 }
71 #system("gpg", "--check-trustdb");
72
73 sub sign_key {
74         my $key = shift;
75
76         $id = undef;
77         $fpr = undef;
78         $expiry = undef;
79         @uid = ();
80
81         # suggestion by moray, not a problem if it doesn't work
82
83         #foreach $cmd ("", "recv") {
84         foreach $cmd ("recv") {
85                 if ($cmd eq "recv") {
86                         system(@gpg, "--list-keys", $key);
87                         if ($? != 0) {
88                                 system(@gpg, "--recv-keys", $key);
89                         }
90                 }
91
92                 open KEYINFO, "$gpg --fixed-list-mode --with-colons " .
93                               "--fingerprint --check-sigs $key|"
94                         or die "Couldn't retreive key information from GPG: $!";
95                 while (<KEYINFO>) {
96                         chomp;
97                         @info = split(/:/);
98                         if ($info[0] eq 'pub') {
99                                 $id = substr($info[4], -8);
100                                 $expiry = $info[6];
101                         } elsif ($info[0] eq 'fpr') {
102                                 $fpr = $info[9];
103                         } elsif ($info[0] eq 'uid') {
104                                 push @uid, $info[1] . $info[9];
105                         } elsif ($info[0] eq 'uat') {
106                                 push @uid, 'r' . $info[9];
107                         } elsif ($info[0] eq 'sig' and $info[4] eq 'F6DD330210FA4CD1') {
108                                 if (@uid) {
109                                         print "Uid $uid[$#uid] already signed; ignoring.\n";
110                                         $uid[$#uid] =~ s/^./S/;
111                                 }
112                         }
113                 }
114                 close KEYINFO;
115
116                 last if $id;
117         }
118
119         die "Key $key not found." unless $id;
120         die "No non-revoked/unsigned UIDs to sign." unless grep { /^[^rS]/ } @uid;
121         
122         open GPG, "$gpg --export $id|" or die "Couldn't export from GPG: $!";
123         @orig = <GPG>;
124         close GPG;
125
126         @fpr = ();
127         for ($i = 4; $i <= 40; $i += 4) {
128                 push @fpr, substr($fpr, $i - 4, 4);
129         }
130         @fpr[4] .= " ";
131         $fpr = join(" ", @fpr);
132
133         print "$id  $fpr\n";
134         foreach (@uid) {
135                 next unless /^(.)(.*)/;
136                 next if $1 eq 'r' or $1 eq 'S';
137                 $uidname = $2;
138                 
139                 print "          $uidname\n";
140         }
141         print "\n";
142         open GPG, '-|', @gpg, "--list-keys", $key
143                 or die "Couldn't list keys from GPG: $!";
144         while (<GPG>) {
145                 print if /revoked/;
146         }
147         close GPG;
148         print "\n";
149         print "Verified? ";
150         $answer = <STDIN>;
151         return if $answer !~ /^[yt]/i;
152
153         @sigs = ();
154
155         for ($uid = 1; $uid <= @uid; $uid++) {
156                 next unless $uid[$uid-1] =~ /^(.)(.*)/;
157                 next if $1 eq 'r' or $1 eq 'S';
158                 $uidname = $2;
159
160                 open GPG, "|$gpg --default-cert-check-level 3 " .
161                           "--command-fd 0 --passphrase-fd 0 --edit $id"
162                         or die "Couldn't sign key $uid";
163                 print GPG $pass;
164                 print GPG "uid $uid\n";
165                 print GPG "sign\n";
166                 print GPG "y\n" if $expiry;
167                 print GPG "save\n";
168                 close GPG;
169
170                 open GPG, "$gpg --export $id|"
171                         or die "Couldn't export from GPG: $!";
172                 @new = <GPG>;
173                 push @sigs, @new;
174                 close GPG;
175
176                 $keyfile = "/tmp/signkey.$$.$id.$uid";
177
178                 open UID, ">$keyfile";
179                 if (@uid > 1) {
180                         print UID
181 "Below is the ASCII-armoured copy of your key, as received from
182 the keyservers, with *ONLY* the following UID signed by ${name}'s key.
183
184         $uidname
185
186 You will receive separate e-mails for each additional UID on your key.
187 Import each into your keyring as you receive them, then upload to the
188 keyservers once all have been added.";
189                 } else {
190                         print UID
191 "Below is the ASCII-armoured copy of your key, as received from
192 the keyservers and signed by ${name}'s key.
193
194 Import this into your keyring then upload to the keyservers.";
195                 }
196
197                 print UID "\n\n(This e-mail was automatically generated.)\n\n";
198                 print UID @new;
199                 close UID;
200
201                 open GPG, "|-", @gpg, "--passphrase-fd", "0", "--encrypt",
202                           "--sign", "-r", $id, $keyfile
203                         or die "Couldn't encrypt ${uid}: $!";
204                 print GPG $pass;
205                 close GPG;
206
207                 open ASC, "$keyfile.asc" or die "Missing asc file! $uid";
208                 @asc = <ASC>;
209                 close ASC;
210
211                 open MAIL, "|-", "/usr/sbin/sendmail", "-t", "-f", $mail
212                         or die "Couldn't write to sendmail: $!";
213                 print MAIL "From: $name <$mail>\n";
214                 print MAIL "To: $uidname\n";
215                 print MAIL "Subject: Signed GPG key: $id\n\n";
216                 print MAIL @asc;
217                 close MAIL;
218
219                 system(@gpg, "--delete-key", $id);
220                 open GPG, "|$gpg --import" or die "Couldn't reimport key $uid";
221                 print GPG @orig;
222                 close GPG;
223
224                 unlink $keyfile;
225                 unlink "$keyfile.asc";
226         }
227
228 # Uncomment to have the signatures on your key when you finish
229
230 #       open GPG, "|$gpg --import" or die "Couldn't import new sigs";
231 #       print GPG @sigs;
232 #       close GPG;
233 }