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