* import.c (import_secret_one): Check for an illegal (>110) protection
[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         /* Use a minimal pk for PGPx mode, since PGP can't import bare
555            revocation certificates. */
556         rc=export_minimal_pk(out,pub_keyblock,sig,NULL);
557         if(rc)
558           goto leave;
559       }
560     else
561       {
562         init_packet( &pkt );
563         pkt.pkttype = PKT_SIGNATURE;
564         pkt.pkt.signature = sig;
565
566         rc = build_packet( out, &pkt );
567         if( rc ) {
568           log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
569           goto leave;
570         }
571       }
572
573     /* and issue a usage notice */
574     tty_printf(_("Revocation certificate created.\n\n"
575 "Please move it to a medium which you can hide away; if Mallory gets\n"
576 "access to this certificate he can use it to make your key unusable.\n"
577 "It is smart to print this certificate and store it away, just in case\n"
578 "your media become unreadable.  But have some caution:  The print system of\n"
579 "your machine might store the data and make it available to others!\n"));
580
581   leave:
582     if( sig )
583         free_seckey_enc( sig );
584     release_kbnode( keyblock );
585     release_kbnode( pub_keyblock );
586     keydb_release (kdbhd);
587     if( rc )
588         iobuf_cancel(out);
589     else
590         iobuf_close(out);
591     release_revocation_reason_info( reason );
592     return rc;
593 }
594
595
596
597 struct revocation_reason_info *
598 ask_revocation_reason( int key_rev, int cert_rev, int hint )
599 {
600     int code=-1;
601     char *description = NULL;
602     struct revocation_reason_info *reason;
603     const char *text_0 = _("No reason specified");
604     const char *text_1 = _("Key has been compromised");
605     const char *text_2 = _("Key is superseded");
606     const char *text_3 = _("Key is no longer used");
607     const char *text_4 = _("User ID is no longer valid");
608     const char *code_text = NULL;
609
610     do {
611         m_free(description);
612         description = NULL;
613
614         tty_printf(_("Please select the reason for the revocation:\n"));
615         tty_printf(    "  0 = %s\n", text_0 );
616         if( key_rev )
617             tty_printf("  1 = %s\n", text_1 );
618         if( key_rev )
619             tty_printf("  2 = %s\n", text_2 );
620         if( key_rev )
621             tty_printf("  3 = %s\n", text_3 );
622         if( cert_rev )
623             tty_printf("  4 = %s\n", text_4 );
624         tty_printf(    "  Q = %s\n", _("Cancel") );
625         if( hint )
626             tty_printf(_("(Probably you want to select %d here)\n"), hint );
627
628         while(code==-1) {
629             int n;
630             char *answer = cpr_get("ask_revocation_reason.code",
631                                                 _("Your decision? "));
632             trim_spaces( answer );
633             cpr_kill_prompt();
634             if( *answer == 'q' || *answer == 'Q')
635               return NULL; /* cancel */
636             if( hint && !*answer )
637                 n = hint;
638             else if(!isdigit( *answer ) )
639                 n = -1;
640             else
641                 n = atoi(answer);
642             m_free(answer);
643             if( n == 0 ) {
644                 code = 0x00; /* no particular reason */
645                 code_text = text_0;
646             }
647             else if( key_rev && n == 1 ) {
648                 code = 0x02; /* key has been compromised */
649                 code_text = text_1;
650             }
651             else if( key_rev && n == 2 ) {
652                 code = 0x01; /* key is superseded */
653                 code_text = text_2;
654             }
655             else if( key_rev && n == 3 ) {
656                 code = 0x03; /* key is no longer used */
657                 code_text = text_3;
658             }
659             else if( cert_rev && n == 4 ) {
660                 code = 0x20; /* uid is no longer valid */
661                 code_text = text_4;
662             }
663             else
664                 tty_printf(_("Invalid selection.\n"));
665         }
666
667         tty_printf(_("Enter an optional description; "
668                      "end it with an empty line:\n") );
669         for(;;) {
670             char *answer = cpr_get("ask_revocation_reason.text", "> " );
671             trim_trailing_ws( answer, strlen(answer) );
672             cpr_kill_prompt();
673             if( !*answer ) {
674                 m_free(answer);
675                 break;
676             }
677
678             {
679                 char *p = make_printable_string( answer, strlen(answer), 0 );
680                 m_free(answer);
681                 answer = p;
682             }
683
684             if( !description )
685                 description = m_strdup(answer);
686             else {
687                 char *p = m_alloc( strlen(description) + strlen(answer) + 2 );
688                 strcpy(stpcpy(stpcpy( p, description),"\n"),answer);
689                 m_free(description);
690                 description = p;
691             }
692             m_free(answer);
693         }
694
695         tty_printf(_("Reason for revocation: %s\n"), code_text );
696         if( !description )
697             tty_printf(_("(No description given)\n") );
698         else
699             tty_printf("%s\n", description );
700
701     } while( !cpr_get_answer_is_yes("ask_revocation_reason.okay",
702                                             _("Is this okay? "))  );
703
704     reason = m_alloc( sizeof *reason );
705     reason->code = code;
706     reason->desc = description;
707     return reason;
708 }
709
710 void
711 release_revocation_reason_info( struct revocation_reason_info *reason )
712 {
713     if( reason ) {
714         m_free( reason->desc );
715         m_free( reason );
716     }
717 }