cc66dfced62de1a9d53013f2e214cd72930a9f86
[gnupg.git] / g10 / revoke.c
1 /* revoke.c
2  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
3  *               2004 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
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 "gpg.h"
30 #include "options.h"
31 #include "packet.h"
32 #include "status.h"
33 #include "keydb.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 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 G10ERR_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"), g10_errstr(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"), g10_errstr(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"), g10_errstr(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 %s has no user IDs\n"),keystr(keyid));
146               return G10ERR_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"), g10_errstr(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"), g10_errstr(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, strlist_t locusr )
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 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     SK_LIST sk_list=NULL;
213
214     if( opt.batch )
215       {
216         log_error(_("can't do this in batch mode\n"));
217         return G10ERR_GENERAL;
218       }
219
220     afx = new_armor_context ();
221
222     kdbhd = keydb_new (0);
223     classify_user_id (uname, &desc);
224     rc = desc.mode? keydb_search (kdbhd, &desc, 1) : G10ERR_INV_USER_ID;
225     if (rc) {
226         log_error (_("key \"%s\" not found: %s\n"),uname, g10_errstr (rc));
227         goto leave;
228     }
229
230     rc = keydb_get_keyblock (kdbhd, &keyblock );
231     if( rc ) {
232         log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
233         goto leave;
234     }
235
236     /* To parse the revkeys */
237     merge_keys_and_selfsig(keyblock);
238
239     /* get the key from the keyblock */
240     node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
241     if( !node ) 
242       BUG ();
243
244     pk=node->pkt->pkt.public_key;
245
246     keyid_from_pk(pk,keyid);
247
248     if(locusr)
249       {
250         rc=build_sk_list(locusr,&sk_list,0,PUBKEY_USAGE_CERT);
251         if(rc)
252           goto leave;
253       }
254
255     /* Are we a designated revoker for this key? */
256
257     if(!pk->revkey && pk->numrevkeys)
258       BUG();
259
260     for(i=0;i<pk->numrevkeys;i++)
261       {
262         SK_LIST list;
263
264         if(sk)
265           free_secret_key(sk);
266
267         if(sk_list)
268           {
269             for(list=sk_list;list;list=list->next)
270               {
271                 byte fpr[MAX_FINGERPRINT_LEN];
272                 size_t fprlen;
273
274                 fingerprint_from_sk(list->sk,fpr,&fprlen);
275
276                 /* Don't get involved with keys that don't have 160
277                    bit fingerprints */
278                 if(fprlen!=20)
279                   continue;
280
281                 if(memcmp(fpr,pk->revkey[i].fpr,20)==0)
282                   break;
283               }
284
285             if(list)
286               sk=copy_secret_key(NULL,list->sk);
287             else
288               continue;
289           }
290         else
291           {
292             sk=xmalloc_secure_clear(sizeof(*sk));
293             rc=get_seckey_byfprint(sk,pk->revkey[i].fpr,MAX_FINGERPRINT_LEN);
294           }
295
296         /* We have the revocation key */
297         if(!rc)
298           {
299             PKT_signature *revkey = NULL;
300
301             any = 1;
302
303             print_pubkey_info (NULL, pk);
304             tty_printf ("\n");
305
306             tty_printf (_("To be revoked by:\n"));
307             print_seckey_info (sk);
308
309             if(pk->revkey[i].class&0x40)
310               tty_printf(_("(This is a sensitive revocation key)\n"));
311             tty_printf("\n");
312
313             if( !cpr_get_answer_is_yes("gen_desig_revoke.okay",
314          _("Create a designated revocation certificate for this key? (y/N) ")))
315               continue;
316
317             /* get the reason for the revocation (this is always v4) */
318             reason = ask_revocation_reason( 1, 0, 1 );
319             if( !reason )
320               continue;
321
322             rc = check_secret_key( sk, 0 );
323             if( rc )
324               continue;
325
326             if( !opt.armor )
327               tty_printf(_("ASCII armored output forced.\n"));
328
329             if( (rc = open_outfile( NULL, 0, &out )) )
330               goto leave;
331
332             afx->what = 1;
333             afx->hdrlines = "Comment: A designated revocation certificate"
334               " should follow\n";
335             push_armor_filter (afx, out);
336
337             /* create it */
338             rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x20, 0,
339                                      0, 0, 0,
340                                      revocation_reason_build_cb, reason );
341             if( rc ) {
342               log_error(_("make_keysig_packet failed: %s\n"), g10_errstr(rc));
343               goto leave;
344             }
345
346             /* Spit out a minimal pk as well, since otherwise there is
347                no way to know which key to attach this revocation to.
348                Also include the direct key signature that contains
349                this revocation key.  We're allowed to include
350                sensitive revocation keys along with a revocation, as
351                this may be the only time the recipient has seen it.
352                Note that this means that if we have multiple different
353                sensitive revocation keys in a given direct key
354                signature, we're going to include them all here.  This
355                is annoying, but the good outweighs the bad, since
356                without including this a sensitive revoker can't really
357                do their job.  People should not include multiple
358                sensitive revocation keys in one signature: 2440 says
359                "Note that it may be appropriate to isolate this
360                subpacket within a separate signature so that it is not
361                combined with other subpackets that need to be
362                exported." -dms */
363
364             while(!revkey)
365               {
366                 KBNODE signode;
367
368                 signode=find_next_kbnode(node,PKT_SIGNATURE);
369                 if(!signode)
370                   break;
371
372                 node=signode;
373
374                 if(keyid[0]==signode->pkt->pkt.signature->keyid[0] &&
375                    keyid[1]==signode->pkt->pkt.signature->keyid[1] &&
376                    IS_KEY_SIG(signode->pkt->pkt.signature))
377                   {
378                     int j;
379
380                     for(j=0;j<signode->pkt->pkt.signature->numrevkeys;j++)
381                       {
382                         if(pk->revkey[i].class==
383                            signode->pkt->pkt.signature->revkey[j]->class &&
384                            pk->revkey[i].algid==
385                            signode->pkt->pkt.signature->revkey[j]->algid &&
386                            memcmp(pk->revkey[i].fpr,
387                                   signode->pkt->pkt.signature->revkey[j]->fpr,
388                                   MAX_FINGERPRINT_LEN)==0)
389                           {
390                             revkey=signode->pkt->pkt.signature;
391                             break;
392                           }
393                       }
394                   }
395               }
396
397             if(!revkey)
398               BUG();
399
400             rc=export_minimal_pk(out,keyblock,sig,revkey);
401             if(rc)
402               goto leave;
403
404             /* and issue a usage notice */
405             tty_printf(_("Revocation certificate created.\n"));
406             break;
407           }
408       }
409
410     if(!any)
411       log_error(_("no revocation keys found for \"%s\"\n"),uname);
412
413   leave:
414     if( pk )
415         free_public_key( pk );
416     if( sk )
417         free_secret_key( sk );
418     if( sig )
419         free_seckey_enc( sig );
420
421     release_sk_list(sk_list);
422
423     if( rc )
424         iobuf_cancel(out);
425     else
426         iobuf_close(out);
427     release_revocation_reason_info( reason );
428     release_armor_context (afx);
429     return rc;
430 }
431
432
433 /****************
434  * Generate a revocation certificate for UNAME
435  */
436 int
437 gen_revoke( const char *uname )
438 {
439     int rc = 0;
440     armor_filter_context_t *afx;
441     PACKET pkt;
442     PKT_secret_key *sk; /* used as pointer into a kbnode */
443     PKT_public_key *pk = NULL;
444     PKT_signature *sig = NULL;
445     u32 sk_keyid[2];
446     IOBUF out = NULL;
447     KBNODE keyblock = NULL, pub_keyblock = NULL;
448     KBNODE node;
449     KEYDB_HANDLE kdbhd;
450     struct revocation_reason_info *reason = NULL;
451     KEYDB_SEARCH_DESC desc;
452
453     if( opt.batch )
454       {
455         log_error(_("can't do this in batch mode\n"));
456         return G10ERR_GENERAL;
457       }
458
459     afx = new_armor_context ();
460     init_packet( &pkt );
461
462     /* search the userid: 
463      * We don't want the whole getkey stuff here but the entire keyblock
464      */
465     kdbhd = keydb_new (1);
466     classify_user_id (uname, &desc);
467     rc = desc.mode? keydb_search (kdbhd, &desc, 1) : G10ERR_INV_USER_ID;
468     if (rc)
469       {
470         log_error (_("secret key \"%s\" not found: %s\n"),
471                    uname, g10_errstr (rc));
472         goto leave;
473       }
474
475     rc = keydb_get_keyblock (kdbhd, &keyblock );
476     if( rc ) {
477         log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
478         goto leave;
479     }
480
481     /* get the keyid from the keyblock */
482     node = find_kbnode( keyblock, PKT_SECRET_KEY );
483     if( !node ) 
484         BUG ();
485
486     /* fixme: should make a function out of this stuff,
487      * it's used all over the source */
488     sk = node->pkt->pkt.secret_key;
489     keyid_from_sk( sk, sk_keyid );
490     print_seckey_info (sk);
491
492     pk = xmalloc_clear( sizeof *pk );
493
494     /* FIXME: We should get the public key direct from the secret one */
495
496     pub_keyblock=get_pubkeyblock(sk_keyid);
497     if(!pub_keyblock)
498       {
499         log_error(_("no corresponding public key: %s\n"), g10_errstr(rc) );
500         goto leave;
501       }
502
503     node=find_kbnode(pub_keyblock,PKT_PUBLIC_KEY);
504     if(!node)
505       BUG();
506
507     pk=node->pkt->pkt.public_key;
508
509     if( cmp_public_secret_key( pk, sk ) ) {
510         log_error(_("public key does not match secret key!\n") );
511         rc = G10ERR_GENERAL;
512         goto leave;
513     }
514
515     tty_printf("\n");
516     if( !cpr_get_answer_is_yes("gen_revoke.okay",
517                   _("Create a revocation certificate for this key? (y/N) ")) )
518       {
519         rc = 0;
520         goto leave;
521       }
522
523     if(sk->version>=4 || opt.force_v4_certs) {
524       /* get the reason for the revocation */
525       reason = ask_revocation_reason( 1, 0, 1 );
526       if( !reason ) { /* user decided to cancel */
527         rc = 0;
528         goto leave;
529       }
530     }
531
532     switch( is_secret_key_protected( sk ) ) {
533       case -1:
534         log_error(_("unknown protection algorithm\n"));
535         rc = G10ERR_PUBKEY_ALGO;
536         break;
537       case -3:
538         tty_printf (_("Secret parts of primary key are not available.\n"));
539         rc = G10ERR_NO_SECKEY;
540         break;
541       case 0:
542         tty_printf(_("NOTE: This key is not protected!\n"));
543         break;
544       default:
545         rc = check_secret_key( sk, 0 );
546         break;
547     }
548     if( rc )
549         goto leave;
550
551
552     if( !opt.armor )
553         tty_printf(_("ASCII armored output forced.\n"));
554
555     if( (rc = open_outfile( NULL, 0, &out )) )
556         goto leave;
557
558     afx->what = 1;
559     afx->hdrlines = "Comment: A revocation certificate should follow\n";
560     push_armor_filter (afx, out);
561
562     /* create it */
563     rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x20, 0,
564                              opt.force_v4_certs?4:0, 0, 0,
565                              revocation_reason_build_cb, reason );
566     if( rc ) {
567         log_error(_("make_keysig_packet failed: %s\n"), g10_errstr(rc));
568         goto leave;
569     }
570
571     if(PGP2 || PGP6 || PGP7 || PGP8)
572       {
573         /* Use a minimal pk for PGPx mode, since PGP can't import bare
574            revocation certificates. */
575         rc=export_minimal_pk(out,pub_keyblock,sig,NULL);
576         if(rc)
577           goto leave;
578       }
579     else
580       {
581         init_packet( &pkt );
582         pkt.pkttype = PKT_SIGNATURE;
583         pkt.pkt.signature = sig;
584
585         rc = build_packet( out, &pkt );
586         if( rc ) {
587           log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
588           goto leave;
589         }
590       }
591
592     /* and issue a usage notice */
593     tty_printf(_("Revocation certificate created.\n\n"
594 "Please move it to a medium which you can hide away; if Mallory gets\n"
595 "access to this certificate he can use it to make your key unusable.\n"
596 "It is smart to print this certificate and store it away, just in case\n"
597 "your media become unreadable.  But have some caution:  The print system of\n"
598 "your machine might store the data and make it available to others!\n"));
599
600   leave:
601     if( sig )
602         free_seckey_enc( sig );
603     release_kbnode( keyblock );
604     release_kbnode( pub_keyblock );
605     keydb_release (kdbhd);
606     if( rc )
607         iobuf_cancel(out);
608     else
609         iobuf_close(out);
610     release_revocation_reason_info( reason );
611     release_armor_context (afx);
612     return rc;
613 }
614
615
616
617 struct revocation_reason_info *
618 ask_revocation_reason( int key_rev, int cert_rev, int hint )
619 {
620     int code=-1;
621     char *description = NULL;
622     struct revocation_reason_info *reason;
623     const char *text_0 = _("No reason specified");
624     const char *text_1 = _("Key has been compromised");
625     const char *text_2 = _("Key is superseded");
626     const char *text_3 = _("Key is no longer used");
627     const char *text_4 = _("User ID is no longer valid");
628     const char *code_text = NULL;
629
630     do {
631         code=-1;
632         xfree(description);
633         description = NULL;
634
635         tty_printf(_("Please select the reason for the revocation:\n"));
636         tty_printf(    "  0 = %s\n", text_0 );
637         if( key_rev )
638             tty_printf("  1 = %s\n", text_1 );
639         if( key_rev )
640             tty_printf("  2 = %s\n", text_2 );
641         if( key_rev )
642             tty_printf("  3 = %s\n", text_3 );
643         if( cert_rev )
644             tty_printf("  4 = %s\n", text_4 );
645         tty_printf(    "  Q = %s\n", _("Cancel") );
646         if( hint )
647             tty_printf(_("(Probably you want to select %d here)\n"), hint );
648
649         while(code==-1) {
650             int n;
651             char *answer = cpr_get("ask_revocation_reason.code",
652                                                 _("Your decision? "));
653             trim_spaces( answer );
654             cpr_kill_prompt();
655             if( *answer == 'q' || *answer == 'Q')
656               return NULL; /* cancel */
657             if( hint && !*answer )
658                 n = hint;
659             else if(!digitp( answer ) )
660                 n = -1;
661             else
662                 n = atoi(answer);
663             xfree(answer);
664             if( n == 0 ) {
665                 code = 0x00; /* no particular reason */
666                 code_text = text_0;
667             }
668             else if( key_rev && n == 1 ) {
669                 code = 0x02; /* key has been compromised */
670                 code_text = text_1;
671             }
672             else if( key_rev && n == 2 ) {
673                 code = 0x01; /* key is superseded */
674                 code_text = text_2;
675             }
676             else if( key_rev && n == 3 ) {
677                 code = 0x03; /* key is no longer used */
678                 code_text = text_3;
679             }
680             else if( cert_rev && n == 4 ) {
681                 code = 0x20; /* uid is no longer valid */
682                 code_text = text_4;
683             }
684             else
685                 tty_printf(_("Invalid selection.\n"));
686         }
687
688         tty_printf(_("Enter an optional description; "
689                      "end it with an empty line:\n") );
690         for(;;) {
691             char *answer = cpr_get("ask_revocation_reason.text", "> " );
692             trim_trailing_ws( answer, strlen(answer) );
693             cpr_kill_prompt();
694             if( !*answer ) {
695                 xfree(answer);
696                 break;
697             }
698
699             {
700                 char *p = make_printable_string( answer, strlen(answer), 0 );
701                 xfree(answer);
702                 answer = p;
703             }
704
705             if( !description )
706                 description = xstrdup(answer);
707             else {
708                 char *p = xmalloc( strlen(description) + strlen(answer) + 2 );
709                 strcpy(stpcpy(stpcpy( p, description),"\n"),answer);
710                 xfree(description);
711                 description = p;
712             }
713             xfree(answer);
714         }
715
716         tty_printf(_("Reason for revocation: %s\n"), code_text );
717         if( !description )
718             tty_printf(_("(No description given)\n") );
719         else
720             tty_printf("%s\n", description );
721
722     } while( !cpr_get_answer_is_yes("ask_revocation_reason.okay",
723                                             _("Is this okay? (y/N) "))  );
724
725     reason = xmalloc( sizeof *reason );
726     reason->code = code;
727     reason->desc = description;
728     return reason;
729 }
730
731 void
732 release_revocation_reason_info( struct revocation_reason_info *reason )
733 {
734     if( reason ) {
735         xfree( reason->desc );
736         xfree( reason );
737     }
738 }