added fast-import to import-options
[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 = m_alloc( buflen );
63     *buffer = reason->code;
64     if( ud ) {
65         memcpy(buffer+1, ud, strlen(ud) );
66         m_free( ud );
67     }
68
69     build_sig_subpkt( sig, SIGSUBPKT_REVOC_REASON, buffer, buflen );
70     m_free( 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 %08lX incomplete\n"),(ulong)keyid[1]);
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 )
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
213     if( opt.batch ) {
214         log_error(_("sorry, can't do this in batch mode\n"));
215         return G10ERR_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) : G10ERR_INV_USER_ID;
223     if (rc) {
224         log_error (_("key `%s' not found: %s\n"),uname, g10_errstr (rc));
225         goto leave;
226     }
227
228     rc = keydb_get_keyblock (kdbhd, &keyblock );
229     if( rc ) {
230         log_error (_("error reading keyblock: %s\n"), g10_errstr(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=m_alloc_clear(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             size_t n;
264             char *p;
265             u32 sk_keyid[2];
266             PKT_signature *revkey=NULL;
267
268             any=1;
269             keyid_from_sk(sk,sk_keyid);
270
271             tty_printf("\npub  %4u%c/%08lX %s   ",
272                        nbits_from_pk( pk ),
273                        pubkey_letter( pk->pubkey_algo ),
274                        (ulong)keyid[1], datestr_from_pk(pk) );
275
276             p = get_user_id( keyid, &n );
277             tty_print_utf8_string( p, n );
278             m_free(p);
279             tty_printf("\n\n");
280
281             tty_printf(_("To be revoked by:\n"));
282
283             tty_printf("\nsec  %4u%c/%08lX %s   ",
284                        nbits_from_sk( sk ),
285                        pubkey_letter( sk->pubkey_algo ),
286                        (ulong)sk_keyid[1], datestr_from_sk(sk) );
287
288             p = get_user_id( sk_keyid, &n );
289             tty_print_utf8_string( p, n );
290             m_free(p);
291             tty_printf("\n");
292             if(pk->revkey[i].class&0x40)
293               tty_printf(_("(This is a sensitive revocation key)\n"));
294             tty_printf("\n");
295
296             if( !cpr_get_answer_is_yes("gen_desig_revoke.okay",
297                        _("Create a revocation certificate for this key? ")) )
298               continue;
299
300             /* get the reason for the revocation (this is always v4) */
301             reason = ask_revocation_reason( 1, 0, 1 );
302             if( !reason )
303               continue;
304
305             rc = check_secret_key( sk, 0 );
306             if( rc )
307               continue;
308
309             if( !opt.armor )
310               tty_printf(_("ASCII armored output forced.\n"));
311
312             if( (rc = open_outfile( NULL, 0, &out )) )
313               goto leave;
314
315             afx.what = 1;
316             afx.hdrlines = "Comment: A revocation certificate should follow\n";
317             iobuf_push_filter( out, armor_filter, &afx );
318
319             /* create it */
320             rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x20, 0,
321                                      0, 0, 0,
322                                      revocation_reason_build_cb, reason );
323             if( rc ) {
324               log_error(_("make_keysig_packet failed: %s\n"), g10_errstr(rc));
325               goto leave;
326             }
327
328             /* Spit out a minimal pk as well, since otherwise there is
329                no way to know which key to attach this revocation to.
330                Also include the direct key signature that contains
331                this revocation key.  We're allowed to include
332                sensitive revocation keys along with a revocation, as
333                this may be the only time the recipient has seen it.
334                Note that this means that if we have multiple different
335                sensitive revocation keys in a given direct key
336                signature, we're going to include them all here.  This
337                is annoying, but the good outweighs the bad, since
338                without including this a sensitive revoker can't really
339                do their job.  People should not include multiple
340                sensitive revocation keys in one signature: 2440 says
341                "Note that it may be appropriate to isolate this
342                subpacket within a separate signature so that it is not
343                combined with other subpackets that need to be
344                exported." -dms */
345
346             while(!revkey)
347               {
348                 KBNODE signode;
349
350                 signode=find_next_kbnode(node,PKT_SIGNATURE);
351                 if(!signode)
352                   break;
353
354                 node=signode;
355
356                 if(keyid[0]==signode->pkt->pkt.signature->keyid[0] &&
357                    keyid[1]==signode->pkt->pkt.signature->keyid[1] &&
358                    IS_KEY_SIG(signode->pkt->pkt.signature))
359                   {
360                     int j;
361
362                     for(j=0;j<signode->pkt->pkt.signature->numrevkeys;j++)
363                       {
364                         if(pk->revkey[i].class==
365                            signode->pkt->pkt.signature->revkey[j]->class &&
366                            pk->revkey[i].algid==
367                            signode->pkt->pkt.signature->revkey[j]->algid &&
368                            memcmp(pk->revkey[i].fpr,
369                                   signode->pkt->pkt.signature->revkey[j]->fpr,
370                                   MAX_FINGERPRINT_LEN)==0)
371                           {
372                             revkey=signode->pkt->pkt.signature;
373                             break;
374                           }
375                       }
376                   }
377               }
378
379             if(!revkey)
380               BUG();
381
382             rc=export_minimal_pk(out,keyblock,sig,revkey);
383             if(rc)
384               goto leave;
385
386             /* and issue a usage notice */
387             tty_printf(_("Revocation certificate created.\n"));
388             break;
389           }
390       }
391
392     if(!any)
393       log_error(_("no revocation keys found for `%s'\n"),uname);
394
395   leave:
396     if( pk )
397         free_public_key( pk );
398     if( sk )
399         free_secret_key( sk );
400     if( sig )
401         free_seckey_enc( sig );
402
403     if( rc )
404         iobuf_cancel(out);
405     else
406         iobuf_close(out);
407     release_revocation_reason_info( reason );
408     return rc;
409 }
410
411
412 /****************
413  * Generate a revocation certificate for UNAME
414  */
415 int
416 gen_revoke( const char *uname )
417 {
418     int rc = 0;
419     armor_filter_context_t afx;
420     PACKET pkt;
421     PKT_secret_key *sk; /* used as pointer into a kbnode */
422     PKT_public_key *pk = NULL;
423     PKT_signature *sig = NULL;
424     u32 sk_keyid[2];
425     IOBUF out = NULL;
426     KBNODE keyblock = NULL, pub_keyblock = NULL;
427     KBNODE node;
428     KEYDB_HANDLE kdbhd;
429     struct revocation_reason_info *reason = NULL;
430     KEYDB_SEARCH_DESC desc;
431
432     if( opt.batch ) {
433         log_error(_("sorry, can't do this in batch mode\n"));
434         return G10ERR_GENERAL;
435     }
436
437     memset( &afx, 0, sizeof afx);
438     init_packet( &pkt );
439
440     /* search the userid: 
441      * We don't want the whole getkey stuff here but the entire keyblock
442      */
443     kdbhd = keydb_new (1);
444     classify_user_id (uname, &desc);
445     rc = desc.mode? keydb_search (kdbhd, &desc, 1) : G10ERR_INV_USER_ID;
446     if (rc) {
447         log_error (_("secret key `%s' not found: %s\n"),
448                    uname, g10_errstr (rc));
449         goto leave;
450     }
451
452     rc = keydb_get_keyblock (kdbhd, &keyblock );
453     if( rc ) {
454         log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
455         goto leave;
456     }
457
458     /* get the keyid from the keyblock */
459     node = find_kbnode( keyblock, PKT_SECRET_KEY );
460     if( !node ) 
461         BUG ();
462
463     /* fixme: should make a function out of this stuff,
464      * it's used all over the source */
465     sk = node->pkt->pkt.secret_key;
466     keyid_from_sk( sk, sk_keyid );
467     tty_printf("\nsec  %4u%c/%08lX %s   ",
468               nbits_from_sk( sk ),
469               pubkey_letter( sk->pubkey_algo ),
470               (ulong)sk_keyid[1], datestr_from_sk(sk) );
471     {
472         size_t n;
473         char *p = get_user_id( sk_keyid, &n );
474         tty_print_utf8_string( p, n );
475         m_free(p);
476         tty_printf("\n");
477     }
478     pk = m_alloc_clear( sizeof *pk );
479
480     /* FIXME: We should get the public key direct from the secret one */
481
482     pub_keyblock=get_pubkeyblock(sk_keyid);
483     if(!pub_keyblock)
484       {
485         log_error(_("no corresponding public key: %s\n"), g10_errstr(rc) );
486         goto leave;
487       }
488
489     node=find_kbnode(pub_keyblock,PKT_PUBLIC_KEY);
490     if(!node)
491       BUG();
492
493     pk=node->pkt->pkt.public_key;
494
495     if( cmp_public_secret_key( pk, sk ) ) {
496         log_error(_("public key does not match secret key!\n") );
497         rc = G10ERR_GENERAL;
498         goto leave;
499     }
500
501     tty_printf("\n");
502     if( !cpr_get_answer_is_yes("gen_revoke.okay",
503                         _("Create a revocation certificate for this key? ")) ){
504         rc = 0;
505         goto leave;
506     }
507
508     if(sk->version>=4 || opt.force_v4_certs) {
509       /* get the reason for the revocation */
510       reason = ask_revocation_reason( 1, 0, 1 );
511       if( !reason ) { /* user decided to cancel */
512         rc = 0;
513         goto leave;
514       }
515     }
516
517     switch( is_secret_key_protected( sk ) ) {
518       case -1:
519         log_error(_("unknown protection algorithm\n"));
520         rc = G10ERR_PUBKEY_ALGO;
521         break;
522       case 0:
523         tty_printf(_("NOTE: This key is not protected!\n"));
524         break;
525       default:
526         rc = check_secret_key( sk, 0 );
527         break;
528     }
529     if( rc )
530         goto leave;
531
532
533     if( !opt.armor )
534         tty_printf(_("ASCII armored output forced.\n"));
535
536     if( (rc = open_outfile( NULL, 0, &out )) )
537         goto leave;
538
539     afx.what = 1;
540     afx.hdrlines = "Comment: A revocation certificate should follow\n";
541     iobuf_push_filter( out, armor_filter, &afx );
542
543     /* create it */
544     rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x20, 0,
545                              opt.force_v4_certs?4:0, 0, 0,
546                              revocation_reason_build_cb, reason );
547     if( rc ) {
548         log_error(_("make_keysig_packet failed: %s\n"), g10_errstr(rc));
549         goto leave;
550     }
551
552     if(opt.pgp2 || opt.pgp6 || opt.pgp7)
553       {
554         rc=export_minimal_pk(out,NULL /*pub_keyblock*/,sig,NULL);
555         if(rc)
556           goto leave;
557       }
558     else
559       {
560         init_packet( &pkt );
561         pkt.pkttype = PKT_SIGNATURE;
562         pkt.pkt.signature = sig;
563
564         rc = build_packet( out, &pkt );
565         if( rc ) {
566           log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
567           goto leave;
568         }
569       }
570
571     /* and issue a usage notice */
572     tty_printf(_("Revocation certificate created.\n\n"
573 "Please move it to a medium which you can hide away; if Mallory gets\n"
574 "access to this certificate he can use it to make your key unusable.\n"
575 "It is smart to print this certificate and store it away, just in case\n"
576 "your media become unreadable.  But have some caution:  The print system of\n"
577 "your machine might store the data and make it available to others!\n"));
578
579   leave:
580     if( sig )
581         free_seckey_enc( sig );
582     release_kbnode( keyblock );
583     release_kbnode( pub_keyblock );
584     keydb_release (kdbhd);
585     if( rc )
586         iobuf_cancel(out);
587     else
588         iobuf_close(out);
589     release_revocation_reason_info( reason );
590     return rc;
591 }
592
593
594
595 struct revocation_reason_info *
596 ask_revocation_reason( int key_rev, int cert_rev, int hint )
597 {
598     int code=-1;
599     char *description = NULL;
600     struct revocation_reason_info *reason;
601     const char *text_0 = _("No reason specified");
602     const char *text_1 = _("Key has been compromised");
603     const char *text_2 = _("Key is superseded");
604     const char *text_3 = _("Key is no longer used");
605     const char *text_4 = _("User ID is no longer valid");
606     const char *code_text = NULL;
607
608     do {
609         m_free(description);
610         description = NULL;
611
612         tty_printf(_("Please select the reason for the revocation:\n"));
613         tty_printf(    "  0 = %s\n", text_0 );
614         if( key_rev )
615             tty_printf("  1 = %s\n", text_1 );
616         if( key_rev )
617             tty_printf("  2 = %s\n", text_2 );
618         if( key_rev )
619             tty_printf("  3 = %s\n", text_3 );
620         if( cert_rev )
621             tty_printf("  4 = %s\n", text_4 );
622         tty_printf(    "  Q = %s\n", _("Cancel") );
623         if( hint )
624             tty_printf(_("(Probably you want to select %d here)\n"), hint );
625
626         while(code==-1) {
627             int n;
628             char *answer = cpr_get("ask_revocation_reason.code",
629                                                 _("Your decision? "));
630             trim_spaces( answer );
631             cpr_kill_prompt();
632             if( *answer == 'q' || *answer == 'Q')
633               return NULL; /* cancel */
634             if( hint && !*answer )
635                 n = hint;
636             else if(!isdigit( *answer ) )
637                 n = -1;
638             else
639                 n = atoi(answer);
640             m_free(answer);
641             if( n == 0 ) {
642                 code = 0x00; /* no particular reason */
643                 code_text = text_0;
644             }
645             else if( key_rev && n == 1 ) {
646                 code = 0x02; /* key has been compromised */
647                 code_text = text_1;
648             }
649             else if( key_rev && n == 2 ) {
650                 code = 0x01; /* key is superseded */
651                 code_text = text_2;
652             }
653             else if( key_rev && n == 3 ) {
654                 code = 0x03; /* key is no longer used */
655                 code_text = text_3;
656             }
657             else if( cert_rev && n == 4 ) {
658                 code = 0x20; /* uid is no longer valid */
659                 code_text = text_4;
660             }
661             else
662                 tty_printf(_("Invalid selection.\n"));
663         }
664
665         tty_printf(_("Enter an optional description; "
666                      "end it with an empty line:\n") );
667         for(;;) {
668             char *answer = cpr_get("ask_revocation_reason.text", "> " );
669             trim_trailing_ws( answer, strlen(answer) );
670             cpr_kill_prompt();
671             if( !*answer ) {
672                 m_free(answer);
673                 break;
674             }
675
676             {
677                 char *p = make_printable_string( answer, strlen(answer), 0 );
678                 m_free(answer);
679                 answer = p;
680             }
681
682             if( !description )
683                 description = m_strdup(answer);
684             else {
685                 char *p = m_alloc( strlen(description) + strlen(answer) + 2 );
686                 strcpy(stpcpy(stpcpy( p, description),"\n"),answer);
687                 m_free(description);
688                 description = p;
689             }
690             m_free(answer);
691         }
692
693         tty_printf(_("Reason for revocation: %s\n"), code_text );
694         if( !description )
695             tty_printf(_("(No description given)\n") );
696         else
697             tty_printf("%s\n", description );
698
699     } while( !cpr_get_answer_is_yes("ask_revocation_reason.okay",
700                                             _("Is this okay? "))  );
701
702     reason = m_alloc( sizeof *reason );
703     reason->code = code;
704     reason->desc = description;
705     return reason;
706 }
707
708 void
709 release_revocation_reason_info( struct revocation_reason_info *reason )
710 {
711     if( reason ) {
712         m_free( reason->desc );
713         m_free( reason );
714     }
715 }