* export.c (parse_export_options): New option sexp-format.
[gnupg.git] / g10 / revoke.c
1 /* revoke.c
2  * Copyright (C) 1998, 1999, 2000, 2001, 2002 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 #include <ctype.h>
28
29 #include "options.h"
30 #include "packet.h"
31 #include "errors.h"
32 #include "keydb.h"
33 #include "memory.h"
34 #include "util.h"
35 #include "main.h"
36 #include "ttyio.h"
37 #include "status.h"
38 #include "i18n.h"
39
40
41 struct revocation_reason_info {
42     int code;
43     char *desc;
44 };
45
46
47 int
48 revocation_reason_build_cb( PKT_signature *sig, void *opaque )
49 {
50     struct revocation_reason_info *reason = opaque;
51     char *ud = NULL;
52     byte *buffer;
53     size_t buflen = 1;
54
55     if(!reason)
56       return 0;
57
58     if( reason->desc ) {
59         ud = native_to_utf8( reason->desc );
60         buflen += strlen(ud);
61     }
62     buffer = xmalloc ( buflen );
63     *buffer = reason->code;
64     if( ud ) {
65         memcpy(buffer+1, ud, strlen(ud) );
66         xfree ( ud );
67     }
68
69     build_sig_subpkt( sig, SIGSUBPKT_REVOC_REASON, buffer, buflen );
70     xfree ( buffer );
71     return 0;
72 }
73
74 /* Outputs a minimal pk (as defined by 2440) from a keyblock.  A
75    minimal pk consists of the public key packet and a user ID.  We try
76    and pick a user ID that has a uid signature, and include it if
77    possible. */
78 static int
79 export_minimal_pk(iobuf_t out,KBNODE keyblock,
80                   PKT_signature *revsig,PKT_signature *revkey)
81 {
82   KBNODE node;
83   PACKET pkt;
84   PKT_user_id *uid=NULL;
85   PKT_signature *selfsig=NULL;
86   u32 keyid[2];
87   int rc;
88
89   node=find_kbnode(keyblock,PKT_PUBLIC_KEY);
90   if(!node)
91     {
92       log_error(_("key incomplete\n"));
93       return GPG_ERR_GENERAL;
94     }
95
96   keyid_from_pk(node->pkt->pkt.public_key,keyid);
97
98   pkt=*node->pkt;
99   rc=build_packet(out,&pkt);
100   if(rc)
101     {
102       log_error(_("build_packet failed: %s\n"), gpg_strerror (rc) );
103       return rc;
104     }
105
106   init_packet(&pkt);
107   pkt.pkttype=PKT_SIGNATURE;
108
109   /* the revocation itself, if any.  2440 likes this to come first. */
110   if(revsig)
111     {
112       pkt.pkt.signature=revsig;
113       rc=build_packet(out,&pkt);
114       if(rc)
115         {
116           log_error(_("build_packet failed: %s\n"), gpg_strerror (rc) );
117           return rc;
118         }
119     }
120
121   /* If a revkey in a 1F sig is present, include it too */
122   if(revkey)
123     {
124       pkt.pkt.signature=revkey;
125       rc=build_packet(out,&pkt);
126       if(rc)
127         {
128           log_error(_("build_packet failed: %s\n"), gpg_strerror (rc) );
129           return rc;
130         }
131     }
132
133   while(!selfsig)
134     {
135       KBNODE signode;
136
137       node=find_next_kbnode(node,PKT_USER_ID);
138       if(!node)
139         {
140           /* We're out of user IDs - none were self-signed. */
141           if(uid)
142             break;
143           else
144             {
145               log_error(_("key %08lX incomplete\n"),(ulong)keyid[1]);
146               return GPG_ERR_GENERAL;
147             }
148         }
149
150       if(node->pkt->pkt.user_id->attrib_data)
151         continue;
152
153       uid=node->pkt->pkt.user_id;
154       signode=node;
155
156       while((signode=find_next_kbnode(signode,PKT_SIGNATURE)))
157         {
158           if(keyid[0]==signode->pkt->pkt.signature->keyid[0] &&
159              keyid[1]==signode->pkt->pkt.signature->keyid[1] &&
160              IS_UID_SIG(signode->pkt->pkt.signature))
161             {
162               selfsig=signode->pkt->pkt.signature;
163               break;
164             }
165         }
166     }
167
168   pkt.pkttype=PKT_USER_ID;
169   pkt.pkt.user_id=uid;
170
171   rc=build_packet(out,&pkt);
172   if(rc)
173     {
174       log_error(_("build_packet failed: %s\n"), gpg_strerror (rc) );
175       return rc;
176     }
177
178   if(selfsig)
179     {
180       pkt.pkttype=PKT_SIGNATURE;
181       pkt.pkt.signature=selfsig;
182
183       rc=build_packet(out,&pkt);
184       if(rc)
185         {
186           log_error(_("build_packet failed: %s\n"), gpg_strerror (rc) );
187           return rc;
188         }
189     }
190
191   return 0;
192 }
193
194 /****************
195  * Generate a revocation certificate for UNAME via a designated revoker
196  */
197 int
198 gen_desig_revoke( const char *uname )
199 {
200     int rc = 0;
201     armor_filter_context_t afx;
202     PKT_public_key *pk = NULL;
203     PKT_secret_key *sk = NULL;
204     PKT_signature *sig = NULL;
205     iobuf_t out = NULL;
206     struct revocation_reason_info *reason = NULL;
207     KEYDB_HANDLE kdbhd;
208     KEYDB_SEARCH_DESC desc;
209     KBNODE keyblock=NULL,node;
210     u32 keyid[2];
211     int i,any=0;
212
213     if( opt.batch ) {
214         log_error(_("sorry, can't do this in batch mode\n"));
215         return GPG_ERR_GENERAL;
216     }
217
218     memset( &afx, 0, sizeof afx);
219
220     kdbhd = keydb_new (0);
221     classify_user_id (uname, &desc);
222     rc = desc.mode? keydb_search (kdbhd, &desc, 1) : GPG_ERR_INV_USER_ID;
223     if (rc) {
224         log_error (_("key `%s' not found: %s\n"),uname, gpg_strerror (rc));
225         goto leave;
226     }
227
228     rc = keydb_get_keyblock (kdbhd, &keyblock );
229     if( rc ) {
230         log_error (_("error reading keyblock: %s\n"), gpg_strerror (rc) );
231         goto leave;
232     }
233
234     /* To parse the revkeys */
235     merge_keys_and_selfsig(keyblock);
236
237     /* get the key from the keyblock */
238     node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
239     if( !node ) 
240       BUG ();
241
242     pk=node->pkt->pkt.public_key;
243
244     keyid_from_pk(pk,keyid);
245
246     /* Are we a designated revoker for this key? */
247
248     if(!pk->revkey && pk->numrevkeys)
249       BUG();
250
251     for(i=0;i<pk->numrevkeys;i++)
252       {
253         if(sk)
254           free_secret_key(sk);
255
256         sk=xcalloc (1,sizeof(*sk));
257
258         rc=get_seckey_byfprint(sk,pk->revkey[i].fpr,MAX_FINGERPRINT_LEN);
259
260         /* We have the revocation key */
261         if(!rc)
262           {
263             PKT_signature *revkey = NULL;
264
265             any = 1;
266
267             print_pubkey_info (pk);
268             tty_printf ("\n");
269
270             tty_printf (_("To be revoked by:\n"));
271             print_seckey_info (sk);
272
273             if(pk->revkey[i].class&0x40)
274               tty_printf(_("(This is a sensitive revocation key)\n"));
275             tty_printf("\n");
276
277             if( !cpr_get_answer_is_yes("gen_desig_revoke.okay",
278                        _("Create a revocation certificate for this key? ")) )
279               continue;
280
281             /* get the reason for the revocation (this is always v4) */
282             reason = ask_revocation_reason( 1, 0, 1 );
283             if( !reason )
284               continue;
285
286             rc = check_secret_key( sk, 0 );
287             if( rc )
288               continue;
289
290             if( !opt.armor )
291               tty_printf(_("ASCII armored output forced.\n"));
292
293             if( (rc = open_outfile( NULL, 0, &out )) )
294               goto leave;
295
296             afx.what = 1;
297             afx.hdrlines = "Comment: A revocation certificate should follow\n";
298             iobuf_push_filter( out, armor_filter, &afx );
299
300             /* create it */
301             rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x20, 0,
302                                      0, 0, 0,
303                                      revocation_reason_build_cb, reason );
304             if( rc ) {
305               log_error(_("make_keysig_packet failed: %s\n"), gpg_strerror (rc));
306               goto leave;
307             }
308
309             /* Spit out a minimal pk as well, since otherwise there is
310                no way to know which key to attach this revocation to.
311                Also include the direct key signature that contains
312                this revocation key.  We're allowed to include
313                sensitive revocation keys along with a revocation, as
314                this may be the only time the recipient has seen it.
315                Note that this means that if we have multiple different
316                sensitive revocation keys in a given direct key
317                signature, we're going to include them all here.  This
318                is annoying, but the good outweighs the bad, since
319                without including this a sensitive revoker can't really
320                do their job.  People should not include multiple
321                sensitive revocation keys in one signature: 2440 says
322                "Note that it may be appropriate to isolate this
323                subpacket within a separate signature so that it is not
324                combined with other subpackets that need to be
325                exported." -dms */
326
327             while(!revkey)
328               {
329                 KBNODE signode;
330
331                 signode=find_next_kbnode(node,PKT_SIGNATURE);
332                 if(!signode)
333                   break;
334
335                 node=signode;
336
337                 if(keyid[0]==signode->pkt->pkt.signature->keyid[0] &&
338                    keyid[1]==signode->pkt->pkt.signature->keyid[1] &&
339                    IS_KEY_SIG(signode->pkt->pkt.signature))
340                   {
341                     int j;
342
343                     for(j=0;j<signode->pkt->pkt.signature->numrevkeys;j++)
344                       {
345                         if(pk->revkey[i].class==
346                            signode->pkt->pkt.signature->revkey[j]->class &&
347                            pk->revkey[i].algid==
348                            signode->pkt->pkt.signature->revkey[j]->algid &&
349                            memcmp(pk->revkey[i].fpr,
350                                   signode->pkt->pkt.signature->revkey[j]->fpr,
351                                   MAX_FINGERPRINT_LEN)==0)
352                           {
353                             revkey=signode->pkt->pkt.signature;
354                             break;
355                           }
356                       }
357                   }
358               }
359
360             if(!revkey)
361               BUG();
362
363             rc=export_minimal_pk(out,keyblock,sig,revkey);
364             if(rc)
365               goto leave;
366
367             /* and issue a usage notice */
368             tty_printf(_("Revocation certificate created.\n"));
369             break;
370           }
371       }
372
373     if(!any)
374       log_error(_("no revocation keys found for `%s'\n"),uname);
375
376   leave:
377     if( pk )
378         free_public_key( pk );
379     if( sk )
380         free_secret_key( sk );
381     if( sig )
382         free_seckey_enc( sig );
383
384     if( rc )
385         iobuf_cancel(out);
386     else
387         iobuf_close(out);
388     release_revocation_reason_info( reason );
389     return rc;
390 }
391
392
393 /****************
394  * Generate a revocation certificate for UNAME
395  */
396 int
397 gen_revoke( const char *uname )
398 {
399     int rc = 0;
400     armor_filter_context_t afx;
401     PACKET pkt;
402     PKT_secret_key *sk; /* used as pointer into a kbnode */
403     PKT_public_key *pk = NULL;
404     PKT_signature *sig = NULL;
405     u32 sk_keyid[2];
406     iobuf_t out = NULL;
407     KBNODE keyblock = NULL, pub_keyblock = NULL;
408     KBNODE node;
409     KEYDB_HANDLE kdbhd;
410     struct revocation_reason_info *reason = NULL;
411     KEYDB_SEARCH_DESC desc;
412
413     if( opt.batch ) {
414         log_error(_("sorry, can't do this in batch mode\n"));
415         return GPG_ERR_GENERAL;
416     }
417
418     memset( &afx, 0, sizeof afx);
419     init_packet( &pkt );
420
421     /* search the userid: 
422      * We don't want the whole getkey stuff here but the entire keyblock
423      */
424     kdbhd = keydb_new (1);
425     classify_user_id (uname, &desc);
426     rc = desc.mode? keydb_search (kdbhd, &desc, 1) : GPG_ERR_INV_USER_ID;
427     if (rc) {
428         log_error (_("secret key `%s' not found: %s\n"),
429                    uname, gpg_strerror (rc));
430         goto leave;
431     }
432
433     rc = keydb_get_keyblock (kdbhd, &keyblock );
434     if( rc ) {
435         log_error (_("error reading keyblock: %s\n"), gpg_strerror (rc) );
436         goto leave;
437     }
438
439     /* get the keyid from the keyblock */
440     node = find_kbnode( keyblock, PKT_SECRET_KEY );
441     if( !node ) 
442         BUG ();
443
444     /* fixme: should make a function out of this stuff,
445      * it's used all over the source */
446     sk = node->pkt->pkt.secret_key;
447     keyid_from_sk( sk, sk_keyid );
448     print_seckey_info (sk);
449
450     pk = xcalloc (1, sizeof *pk );
451
452     /* FIXME: We should get the public key direct from the secret one */
453
454     pub_keyblock=get_pubkeyblock(sk_keyid);
455     if(!pub_keyblock)
456       {
457         log_error(_("no corresponding public key: %s\n"), gpg_strerror (rc) );
458         goto leave;
459       }
460
461     node=find_kbnode(pub_keyblock,PKT_PUBLIC_KEY);
462     if(!node)
463       BUG();
464
465     pk=node->pkt->pkt.public_key;
466
467     if( cmp_public_secret_key( pk, sk ) ) {
468         log_error(_("public key does not match secret key!\n") );
469         rc = GPG_ERR_GENERAL;
470         goto leave;
471     }
472
473     tty_printf("\n");
474     if( !cpr_get_answer_is_yes("gen_revoke.okay",
475                         _("Create a revocation certificate for this key? ")) ){
476         rc = 0;
477         goto leave;
478     }
479
480     if(sk->version>=4 || opt.force_v4_certs) {
481       /* get the reason for the revocation */
482       reason = ask_revocation_reason( 1, 0, 1 );
483       if( !reason ) { /* user decided to cancel */
484         rc = 0;
485         goto leave;
486       }
487     }
488
489     switch( is_secret_key_protected( sk ) ) {
490       case -1:
491         log_error(_("unknown protection algorithm\n"));
492         rc = GPG_ERR_PUBKEY_ALGO;
493         break;
494       case 0:
495         tty_printf(_("NOTE: This key is not protected!\n"));
496         break;
497       default:
498         rc = check_secret_key( sk, 0 );
499         break;
500     }
501     if( rc )
502         goto leave;
503
504
505     if( !opt.armor )
506         tty_printf(_("ASCII armored output forced.\n"));
507
508     if( (rc = open_outfile( NULL, 0, &out )) )
509         goto leave;
510
511     afx.what = 1;
512     afx.hdrlines = "Comment: A revocation certificate should follow\n";
513     iobuf_push_filter( out, armor_filter, &afx );
514
515     /* create it */
516     rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x20, 0,
517                              opt.force_v4_certs?4:0, 0, 0,
518                              revocation_reason_build_cb, reason );
519     if( rc ) {
520         log_error(_("make_keysig_packet failed: %s\n"), gpg_strerror (rc));
521         goto leave;
522     }
523
524     if(PGP2 || PGP6 || PGP7 || PGP8)
525       {
526         /* Use a minimal pk for PGPx mode, since PGP can't import bare
527            revocation certificates. */
528         rc=export_minimal_pk(out,pub_keyblock,sig,NULL);
529         if(rc)
530           goto leave;
531       }
532     else
533       {
534         init_packet( &pkt );
535         pkt.pkttype = PKT_SIGNATURE;
536         pkt.pkt.signature = sig;
537
538         rc = build_packet( out, &pkt );
539         if( rc ) {
540           log_error(_("build_packet failed: %s\n"), gpg_strerror (rc) );
541           goto leave;
542         }
543       }
544
545     /* and issue a usage notice */
546     tty_printf(_("Revocation certificate created.\n\n"
547 "Please move it to a medium which you can hide away; if Mallory gets\n"
548 "access to this certificate he can use it to make your key unusable.\n"
549 "It is smart to print this certificate and store it away, just in case\n"
550 "your media become unreadable.  But have some caution:  The print system of\n"
551 "your machine might store the data and make it available to others!\n"));
552
553   leave:
554     if( sig )
555         free_seckey_enc( sig );
556     release_kbnode( keyblock );
557     release_kbnode( pub_keyblock );
558     keydb_release (kdbhd);
559     if( rc )
560         iobuf_cancel(out);
561     else
562         iobuf_close(out);
563     release_revocation_reason_info( reason );
564     return rc;
565 }
566
567
568
569 struct revocation_reason_info *
570 ask_revocation_reason( int key_rev, int cert_rev, int hint )
571 {
572     int code=-1;
573     char *description = NULL;
574     struct revocation_reason_info *reason;
575     const char *text_0 = _("No reason specified");
576     const char *text_1 = _("Key has been compromised");
577     const char *text_2 = _("Key is superseded");
578     const char *text_3 = _("Key is no longer used");
579     const char *text_4 = _("User ID is no longer valid");
580     const char *code_text = NULL;
581
582     do {
583         code=-1;
584         xfree (description);
585         description = NULL;
586
587         tty_printf(_("Please select the reason for the revocation:\n"));
588         tty_printf(    "  0 = %s\n", text_0 );
589         if( key_rev )
590             tty_printf("  1 = %s\n", text_1 );
591         if( key_rev )
592             tty_printf("  2 = %s\n", text_2 );
593         if( key_rev )
594             tty_printf("  3 = %s\n", text_3 );
595         if( cert_rev )
596             tty_printf("  4 = %s\n", text_4 );
597         tty_printf(    "  Q = %s\n", _("Cancel") );
598         if( hint )
599             tty_printf(_("(Probably you want to select %d here)\n"), hint );
600
601         while(code==-1) {
602             int n;
603             char *answer = cpr_get("ask_revocation_reason.code",
604                                                 _("Your decision? "));
605             trim_spaces( answer );
606             cpr_kill_prompt();
607             if( *answer == 'q' || *answer == 'Q')
608               return NULL; /* cancel */
609             if( hint && !*answer )
610                 n = hint;
611             else if(!isdigit( *answer ) )
612                 n = -1;
613             else
614                 n = atoi(answer);
615             xfree (answer);
616             if( n == 0 ) {
617                 code = 0x00; /* no particular reason */
618                 code_text = text_0;
619             }
620             else if( key_rev && n == 1 ) {
621                 code = 0x02; /* key has been compromised */
622                 code_text = text_1;
623             }
624             else if( key_rev && n == 2 ) {
625                 code = 0x01; /* key is superseded */
626                 code_text = text_2;
627             }
628             else if( key_rev && n == 3 ) {
629                 code = 0x03; /* key is no longer used */
630                 code_text = text_3;
631             }
632             else if( cert_rev && n == 4 ) {
633                 code = 0x20; /* uid is no longer valid */
634                 code_text = text_4;
635             }
636             else
637                 tty_printf(_("Invalid selection.\n"));
638         }
639
640         tty_printf(_("Enter an optional description; "
641                      "end it with an empty line:\n") );
642         for(;;) {
643             char *answer = cpr_get("ask_revocation_reason.text", "> " );
644             trim_trailing_ws( answer, strlen(answer) );
645             cpr_kill_prompt();
646             if( !*answer ) {
647                 xfree (answer);
648                 break;
649             }
650
651             {
652                 char *p = make_printable_string( answer, strlen(answer), 0 );
653                 xfree (answer);
654                 answer = p;
655             }
656
657             if( !description )
658                 description = xstrdup (answer);
659             else {
660                 char *p = xmalloc ( strlen(description) + strlen(answer) + 2 );
661                 strcpy(stpcpy(stpcpy( p, description),"\n"),answer);
662                 xfree (description);
663                 description = p;
664             }
665             xfree (answer);
666         }
667
668         tty_printf(_("Reason for revocation: %s\n"), code_text );
669         if( !description )
670             tty_printf(_("(No description given)\n") );
671         else
672             tty_printf("%s\n", description );
673
674     } while( !cpr_get_answer_is_yes("ask_revocation_reason.okay",
675                                             _("Is this okay? "))  );
676
677     reason = xmalloc ( sizeof *reason );
678     reason->code = code;
679     reason->desc = description;
680     return reason;
681 }
682
683 void
684 release_revocation_reason_info( struct revocation_reason_info *reason )
685 {
686     if( reason ) {
687         xfree ( reason->desc );
688         xfree ( reason );
689     }
690 }