* export.c (do_export_stream) [ENABLE_SELINUX_HACKS]: Don't allow
[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 designated revocation certificate for this key? (y/N) ")))
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? (y/N) ")) )
477       {
478         rc = 0;
479         goto leave;
480       }
481
482     if(sk->version>=4 || opt.force_v4_certs) {
483       /* get the reason for the revocation */
484       reason = ask_revocation_reason( 1, 0, 1 );
485       if( !reason ) { /* user decided to cancel */
486         rc = 0;
487         goto leave;
488       }
489     }
490
491     switch( is_secret_key_protected( sk ) ) {
492       case -1:
493         log_error(_("unknown protection algorithm\n"));
494         rc = G10ERR_PUBKEY_ALGO;
495         break;
496       case 0:
497         tty_printf(_("NOTE: This key is not protected!\n"));
498         break;
499       default:
500         rc = check_secret_key( sk, 0 );
501         break;
502     }
503     if( rc )
504         goto leave;
505
506
507     if( !opt.armor )
508         tty_printf(_("ASCII armored output forced.\n"));
509
510     if( (rc = open_outfile( NULL, 0, &out )) )
511         goto leave;
512
513     afx.what = 1;
514     afx.hdrlines = "Comment: A revocation certificate should follow\n";
515     iobuf_push_filter( out, armor_filter, &afx );
516
517     /* create it */
518     rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x20, 0,
519                              opt.force_v4_certs?4:0, 0, 0,
520                              revocation_reason_build_cb, reason );
521     if( rc ) {
522         log_error(_("make_keysig_packet failed: %s\n"), g10_errstr(rc));
523         goto leave;
524     }
525
526     if(PGP2 || PGP6 || PGP7 || PGP8)
527       {
528         /* Use a minimal pk for PGPx mode, since PGP can't import bare
529            revocation certificates. */
530         rc=export_minimal_pk(out,pub_keyblock,sig,NULL);
531         if(rc)
532           goto leave;
533       }
534     else
535       {
536         init_packet( &pkt );
537         pkt.pkttype = PKT_SIGNATURE;
538         pkt.pkt.signature = sig;
539
540         rc = build_packet( out, &pkt );
541         if( rc ) {
542           log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
543           goto leave;
544         }
545       }
546
547     /* and issue a usage notice */
548     tty_printf(_("Revocation certificate created.\n\n"
549 "Please move it to a medium which you can hide away; if Mallory gets\n"
550 "access to this certificate he can use it to make your key unusable.\n"
551 "It is smart to print this certificate and store it away, just in case\n"
552 "your media become unreadable.  But have some caution:  The print system of\n"
553 "your machine might store the data and make it available to others!\n"));
554
555   leave:
556     if( sig )
557         free_seckey_enc( sig );
558     release_kbnode( keyblock );
559     release_kbnode( pub_keyblock );
560     keydb_release (kdbhd);
561     if( rc )
562         iobuf_cancel(out);
563     else
564         iobuf_close(out);
565     release_revocation_reason_info( reason );
566     return rc;
567 }
568
569
570
571 struct revocation_reason_info *
572 ask_revocation_reason( int key_rev, int cert_rev, int hint )
573 {
574     int code=-1;
575     char *description = NULL;
576     struct revocation_reason_info *reason;
577     const char *text_0 = _("No reason specified");
578     const char *text_1 = _("Key has been compromised");
579     const char *text_2 = _("Key is superseded");
580     const char *text_3 = _("Key is no longer used");
581     const char *text_4 = _("User ID is no longer valid");
582     const char *code_text = NULL;
583
584     do {
585         code=-1;
586         m_free(description);
587         description = NULL;
588
589         tty_printf(_("Please select the reason for the revocation:\n"));
590         tty_printf(    "  0 = %s\n", text_0 );
591         if( key_rev )
592             tty_printf("  1 = %s\n", text_1 );
593         if( key_rev )
594             tty_printf("  2 = %s\n", text_2 );
595         if( key_rev )
596             tty_printf("  3 = %s\n", text_3 );
597         if( cert_rev )
598             tty_printf("  4 = %s\n", text_4 );
599         tty_printf(    "  Q = %s\n", _("Cancel") );
600         if( hint )
601             tty_printf(_("(Probably you want to select %d here)\n"), hint );
602
603         while(code==-1) {
604             int n;
605             char *answer = cpr_get("ask_revocation_reason.code",
606                                                 _("Your decision? "));
607             trim_spaces( answer );
608             cpr_kill_prompt();
609             if( *answer == 'q' || *answer == 'Q')
610               return NULL; /* cancel */
611             if( hint && !*answer )
612                 n = hint;
613             else if(!digitp( answer ) )
614                 n = -1;
615             else
616                 n = atoi(answer);
617             m_free(answer);
618             if( n == 0 ) {
619                 code = 0x00; /* no particular reason */
620                 code_text = text_0;
621             }
622             else if( key_rev && n == 1 ) {
623                 code = 0x02; /* key has been compromised */
624                 code_text = text_1;
625             }
626             else if( key_rev && n == 2 ) {
627                 code = 0x01; /* key is superseded */
628                 code_text = text_2;
629             }
630             else if( key_rev && n == 3 ) {
631                 code = 0x03; /* key is no longer used */
632                 code_text = text_3;
633             }
634             else if( cert_rev && n == 4 ) {
635                 code = 0x20; /* uid is no longer valid */
636                 code_text = text_4;
637             }
638             else
639                 tty_printf(_("Invalid selection.\n"));
640         }
641
642         tty_printf(_("Enter an optional description; "
643                      "end it with an empty line:\n") );
644         for(;;) {
645             char *answer = cpr_get("ask_revocation_reason.text", "> " );
646             trim_trailing_ws( answer, strlen(answer) );
647             cpr_kill_prompt();
648             if( !*answer ) {
649                 m_free(answer);
650                 break;
651             }
652
653             {
654                 char *p = make_printable_string( answer, strlen(answer), 0 );
655                 m_free(answer);
656                 answer = p;
657             }
658
659             if( !description )
660                 description = m_strdup(answer);
661             else {
662                 char *p = m_alloc( strlen(description) + strlen(answer) + 2 );
663                 strcpy(stpcpy(stpcpy( p, description),"\n"),answer);
664                 m_free(description);
665                 description = p;
666             }
667             m_free(answer);
668         }
669
670         tty_printf(_("Reason for revocation: %s\n"), code_text );
671         if( !description )
672             tty_printf(_("(No description given)\n") );
673         else
674             tty_printf("%s\n", description );
675
676     } while( !cpr_get_answer_is_yes("ask_revocation_reason.okay",
677                                             _("Is this okay? (y/N) "))  );
678
679     reason = m_alloc( sizeof *reason );
680     reason->code = code;
681     reason->desc = description;
682     return reason;
683 }
684
685 void
686 release_revocation_reason_info( struct revocation_reason_info *reason )
687 {
688     if( reason ) {
689         m_free( reason->desc );
690         m_free( reason );
691     }
692 }