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