See ChangeLog: Mon Jul 26 09:34:46 CEST 1999 Werner Koch
[gnupg.git] / g10 / revoke.c
1 /* revoke.c
2  *      Copyright (C) 1998 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <assert.h>
27
28 #include "options.h"
29 #include "packet.h"
30 #include "errors.h"
31 #include "keydb.h"
32 #include "memory.h"
33 #include "util.h"
34 #include "main.h"
35 #include "ttyio.h"
36 #include "status.h"
37 #include "i18n.h"
38
39
40 /****************
41  * Generate a revocation certificate for UNAME
42  */
43 int
44 gen_revoke( const char *uname )
45 {
46     int rc = 0;
47     armor_filter_context_t afx;
48     compress_filter_context_t zfx;
49     PACKET pkt;
50     PKT_secret_key *sk; /* used as pointer into a kbnode */
51     PKT_public_key *pk = NULL;
52     PKT_signature *sig = NULL;
53     u32 sk_keyid[2];
54     IOBUF out = NULL;
55     KBNODE keyblock = NULL;
56     KBNODE node;
57     KBPOS kbpos;
58
59     if( opt.batch ) {
60         log_error(_("sorry, can't do this in batch mode\n"));
61         return G10ERR_GENERAL;
62     }
63
64
65     /* FIXME: ask for the reason of revocation
66        0x00 - No reason specified (key revocations or cert revocations)
67     Does not make sense!
68
69        0x01 - Key is superceded (key revocations)
70        0x02 - Key material has been compromised (key revocations)
71        0x03 - Key is no longer used (key revocations)
72        0x20 - User id information is no longer valid (cert revocations)
73
74        Following the revocation code is a string of octets which gives
75       information about the reason for revocation in human-readable form
76      */
77
78     memset( &afx, 0, sizeof afx);
79     memset( &zfx, 0, sizeof zfx);
80     init_packet( &pkt );
81
82
83     /* search the userid */
84     rc = find_secret_keyblock_byname( &kbpos, uname );
85     if( rc ) {
86         log_error(_("secret key for user `%s' not found\n"), uname );
87         goto leave;
88     }
89
90     /* read the keyblock */
91     rc = read_keyblock( &kbpos, &keyblock );
92     if( rc ) {
93         log_error(_("error reading the certificate: %s\n"), g10_errstr(rc) );
94         goto leave;
95     }
96
97     /* get the keyid from the keyblock */
98     node = find_kbnode( keyblock, PKT_SECRET_KEY );
99     if( !node ) { /* maybe better to use log_bug ? */
100         log_error(_("Oops; secret key not found anymore!\n"));
101         rc = G10ERR_GENERAL;
102         goto leave;
103     }
104
105     /* fixme: should make a function out of this stuff,
106      * it's used all over the source */
107     sk = node->pkt->pkt.secret_key;
108     keyid_from_sk( sk, sk_keyid );
109     tty_printf("\nsec  %4u%c/%08lX %s   ",
110               nbits_from_sk( sk ),
111               pubkey_letter( sk->pubkey_algo ),
112               sk_keyid[1], datestr_from_sk(sk) );
113     {
114         size_t n;
115         char *p = get_user_id( sk_keyid, &n );
116         tty_print_string( p, n );
117         m_free(p);
118         tty_printf("\n");
119     }
120     pk = m_alloc_clear( sizeof *pk );
121     rc = get_pubkey( pk, sk_keyid );
122     if( rc ) {
123         log_error(_("no corresponding public key: %s\n"), g10_errstr(rc) );
124         goto leave;
125     }
126     if( cmp_public_secret_key( pk, sk ) ) {
127         log_error(_("public key does not match secret key!\n") );
128         rc = G10ERR_GENERAL;
129         goto leave;
130     }
131
132     tty_printf("\n");
133     if( !cpr_get_answer_is_yes("gen_revoke.okay",
134                         _("Create a revocation certificate for this key? ")) ){
135         rc = 0;
136         goto leave;
137     }
138
139     switch( is_secret_key_protected( sk ) ) {
140       case -1:
141         log_error(_("unknown protection algorithm\n"));
142         rc = G10ERR_PUBKEY_ALGO;
143         break;
144       case 0:
145         tty_printf(_("NOTE: This key is not protected!\n"));
146         break;
147       default:
148         rc = check_secret_key( sk, 0 );
149         break;
150     }
151     if( rc )
152         goto leave;
153
154
155     if( !opt.armor )
156         tty_printf(_("ASCII armored output forced.\n"));
157
158     if( (rc = open_outfile( NULL, 0, &out )) )
159         goto leave;
160
161     afx.what = 1;
162     afx.hdrlines = "Comment: A revocation certificate should follow\n";
163     iobuf_push_filter( out, armor_filter, &afx );
164
165     /* create it */
166     rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x20, 0, NULL, NULL);
167     if( rc ) {
168         log_error(_("make_keysig_packet failed: %s\n"), g10_errstr(rc));
169         goto leave;
170     }
171     init_packet( &pkt );
172     pkt.pkttype = PKT_SIGNATURE;
173     pkt.pkt.signature = sig;
174
175     rc = build_packet( out, &pkt );
176     if( rc ) {
177         log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
178         goto leave;
179     }
180
181     /* and issue a usage notice */
182     tty_printf(_("Revocation certificate created.\n\n"
183 "Please move it to a medium which you can hide away; if Mallory gets\n"
184 "access to this certificate he can use it to make your key unusable.\n"
185 "It is smart to print this certificate and store it away, just in case\n"
186 "your media become unreadable.  But have some caution:  The print system of\n"
187 "your machine might store the data and make it available to others!\n"));
188
189
190
191   leave:
192     if( pk )
193         free_public_key( pk );
194     if( sig )
195         free_seckey_enc( sig );
196     release_kbnode( keyblock );
197     if( rc )
198         iobuf_cancel(out);
199     else
200         iobuf_close(out);
201     return rc;
202 }
203
204 #if 0 /* The code is not complete but anyway, now we use */
205       /* the edit menu to revoke signature */
206 /****************
207  * Return true if there is already a revocation signature for KEYID
208  * in KEYBLOCK at point node.
209  */
210 static int
211 already_revoked( const KBNODE keyblock, const KBNODE node, u32 *keyid )                                                          ) {
212 {
213     const KBNODE n = find_prev_kbnode( keyblock, node, PKT_USER_ID );
214
215     for( ; n; n = n->next ) {
216         PKT_signature *sig;
217         if( n->pkt->pkttype == PKT_SIGNATURE
218             && (sig = node->pkt->pkt.signature)->sig_class == 0x30
219             && sig->keyid[0] == keyid[0]
220             && sig->keyid[1] == keyid[1] )
221             return 1;
222         }
223         else if( n->pkt->pkttype == PKT_USER_ID
224             break;
225         else if( n->pkt->pkttype == PKT_PUBLIC_SUBKEY
226             break;
227     }
228     return 0;
229 }
230
231 /****************
232  * Ask whether the signature should be revoked.  If the user commits this,
233  * flag bit 0 is set.
234  */
235 static void
236 ask_revoke_sig( KBNODE keyblock, KBNODE node, PKT_signature *sig )                                                          ) {
237 {
238     KBNODE unode = find_prev_kbnode( keyblock, node, PKT_USER_ID );
239
240     if( !unode ) {
241         log_error("Oops: no user ID for signature\n");
242         return;
243     }
244
245     tty_printf(_("user ID: \""));
246     tty_print_string( unode->pkt->pkt.user_id->name,
247                       unode->pkt->pkt.user_id->len, 0 );
248     tty_printf(_("\"\nsigned with your key %08lX at %s\n"),
249                 sig->keyid[1], datestr_from_sig(sig) );
250
251     if( cpr_get_answer_is_yes("ask_revoke_sig.one",
252          _("Create a revocation certificate for this signature? (y/N)")) ) {
253         node->flag |= 1;
254     }
255 }
256
257 /****************
258  * Generate a signature revocation certificate for UNAME
259  */
260 int
261 gen_sig_revoke( const char *uname )
262 {
263     int rc = 0;
264     armor_filter_context_t afx;
265     compress_filter_context_t zfx;
266     PACKET pkt;
267     IOBUF out = NULL;
268     KBNODE keyblock = NULL;
269     KBNODE node;
270     KBPOS kbpos;
271     int uidchg;
272
273     if( opt.batch ) {
274         log_error(_("sorry, can't do this in batch mode\n"));
275         return G10ERR_GENERAL;
276     }
277
278
279     memset( &afx, 0, sizeof afx);
280     memset( &zfx, 0, sizeof zfx);
281     init_packet( &pkt );
282
283
284     /* get the keyblock */
285     rc = find_keyblock_byname( &kbpos, uname );
286     if( rc ) {
287         log_error(_("public key for user `%s' not found\n"), uname );
288         goto leave;
289     }
290
291     /* read the keyblock */
292     rc = read_keyblock( &kbpos, &keyblock );
293     if( rc ) {
294         log_error(_("error reading the certificate: %s\n"), g10_errstr(rc) );
295         goto leave;
296     }
297
298     /* get the keyid from the keyblock */
299     node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
300     if( !node ) {
301         log_error(_("Oops; public key lost!\n"));
302         rc = G10ERR_GENERAL;
303         goto leave;
304     }
305
306     if( (rc = open_outfile( NULL, 0, &out )) )
307         goto leave;
308
309     if( opt.armor ) {
310        afx.what = 1;
311        iobuf_push_filter( out, armor_filter, &afx );
312     }
313
314     /* Now walk over all signatures which we did with one of
315      * our secret keys.  Hmmm: Should we check for duplicate signatures */
316     clear_kbnode_flags( flags );
317     for( node = keyblock; node; node = node->next ) {
318         PKT_signature *sig;
319         if( node->pkt->pkttype == PKT_SIGNATURE
320             && ((sig = node->pkt->pkt.signature)->sig_class&~3) == 0x10
321             && seckey_available( sig->keyid )
322             && !already_revoked( keyblock, node, sig->keyid ) ) {                                                            ) {
323             ask_revoke_sig( keyblock, node, sig )
324         }
325         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
326             break;
327     }
328
329
330     for( node = keyblock; node; node = node->next ) { {
331         if( (node->flag & 1) )
332             break;
333     }
334     if( !node ) {
335         log_info(_("nothing to revoke\n"));
336         iobuf_cancel(out);
337         out = NULL;
338         goto leave;
339     }
340
341     init_packet( &pkt );
342     pkt.pkttype = PKT_PUBLIC_KEY;
343     pkt.pkt.public_key = keyblock->pkt->pkt.public_key;
344     rc = build_packet( out, &pkt );
345     if( rc ) {
346         log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
347         goto leave;
348     }
349     uidchg = 1;
350     for( node = keyblock; node; node = node->next ) {
351         if( node->pkt->pkttype == PKT_USER_ID )
352             uidchg = 1;
353         if( !(node->flag & 1) )
354             continue;
355
356         if( uidchg ) {
357             /* create a user ID packet */
358             .......
359             uidchg = 0;
360         }
361
362         /* create it */
363         rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x30, 0, NULL, NULL);
364         if( rc ) {
365             log_error(_("make_keysig_packet failed: %s\n"), g10_errstr(rc));
366             goto leave;
367         }
368         init_packet( &pkt );
369         pkt.pkttype = PKT_SIGNATURE;
370         pkt.pkt.signature = sig;
371
372         rc = build_packet( out, &pkt );
373         if( rc ) {
374             log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
375             goto leave;
376         }
377     }
378
379   leave:
380     release_kbnode( keyblock );
381     if( !out )
382         ;
383     else if( rc )
384         iobuf_cancel(out);
385     else
386         iobuf_close(out);
387     return rc;
388 }
389 #endif /* unused code */
390