2006-06-09 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / g10 / revoke.c
blob34f9f5c852c16cb95b4cb7e401a23f9c4995e80d
1 /* revoke.c
2 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
3 * 2004 Free Software Foundation, Inc.
5 * This file is part of GnuPG.
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
20 * USA.
23 #include <config.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <assert.h>
29 #include <ctype.h>
31 #include "gpg.h"
32 #include "options.h"
33 #include "packet.h"
34 #include "errors.h"
35 #include "keydb.h"
36 #include "util.h"
37 #include "main.h"
38 #include "ttyio.h"
39 #include "status.h"
40 #include "i18n.h"
43 struct revocation_reason_info {
44 int code;
45 char *desc;
49 int
50 revocation_reason_build_cb( PKT_signature *sig, void *opaque )
52 struct revocation_reason_info *reason = opaque;
53 char *ud = NULL;
54 byte *buffer;
55 size_t buflen = 1;
57 if(!reason)
58 return 0;
60 if( reason->desc ) {
61 ud = native_to_utf8( reason->desc );
62 buflen += strlen(ud);
64 buffer = xmalloc( buflen );
65 *buffer = reason->code;
66 if( ud ) {
67 memcpy(buffer+1, ud, strlen(ud) );
68 xfree( ud );
71 build_sig_subpkt( sig, SIGSUBPKT_REVOC_REASON, buffer, buflen );
72 xfree( buffer );
73 return 0;
76 /* Outputs a minimal pk (as defined by 2440) from a keyblock. A
77 minimal pk consists of the public key packet and a user ID. We try
78 and pick a user ID that has a uid signature, and include it if
79 possible. */
80 static int
81 export_minimal_pk(IOBUF out,KBNODE keyblock,
82 PKT_signature *revsig,PKT_signature *revkey)
84 KBNODE node;
85 PACKET pkt;
86 PKT_user_id *uid=NULL;
87 PKT_signature *selfsig=NULL;
88 u32 keyid[2];
89 int rc;
91 node=find_kbnode(keyblock,PKT_PUBLIC_KEY);
92 if(!node)
94 log_error("key incomplete\n");
95 return G10ERR_GENERAL;
98 keyid_from_pk(node->pkt->pkt.public_key,keyid);
100 pkt=*node->pkt;
101 rc=build_packet(out,&pkt);
102 if(rc)
104 log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
105 return rc;
108 init_packet(&pkt);
109 pkt.pkttype=PKT_SIGNATURE;
111 /* the revocation itself, if any. 2440 likes this to come first. */
112 if(revsig)
114 pkt.pkt.signature=revsig;
115 rc=build_packet(out,&pkt);
116 if(rc)
118 log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
119 return rc;
123 /* If a revkey in a 1F sig is present, include it too */
124 if(revkey)
126 pkt.pkt.signature=revkey;
127 rc=build_packet(out,&pkt);
128 if(rc)
130 log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
131 return rc;
135 while(!selfsig)
137 KBNODE signode;
139 node=find_next_kbnode(node,PKT_USER_ID);
140 if(!node)
142 /* We're out of user IDs - none were self-signed. */
143 if(uid)
144 break;
145 else
147 log_error(_("key %s has no user IDs\n"),keystr(keyid));
148 return G10ERR_GENERAL;
152 if(node->pkt->pkt.user_id->attrib_data)
153 continue;
155 uid=node->pkt->pkt.user_id;
156 signode=node;
158 while((signode=find_next_kbnode(signode,PKT_SIGNATURE)))
160 if(keyid[0]==signode->pkt->pkt.signature->keyid[0] &&
161 keyid[1]==signode->pkt->pkt.signature->keyid[1] &&
162 IS_UID_SIG(signode->pkt->pkt.signature))
164 selfsig=signode->pkt->pkt.signature;
165 break;
170 pkt.pkttype=PKT_USER_ID;
171 pkt.pkt.user_id=uid;
173 rc=build_packet(out,&pkt);
174 if(rc)
176 log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
177 return rc;
180 if(selfsig)
182 pkt.pkttype=PKT_SIGNATURE;
183 pkt.pkt.signature=selfsig;
185 rc=build_packet(out,&pkt);
186 if(rc)
188 log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
189 return rc;
193 return 0;
196 /****************
197 * Generate a revocation certificate for UNAME via a designated revoker
200 gen_desig_revoke( const char *uname, STRLIST locusr )
202 int rc = 0;
203 armor_filter_context_t afx;
204 PKT_public_key *pk = NULL;
205 PKT_secret_key *sk = NULL;
206 PKT_signature *sig = NULL;
207 IOBUF out = NULL;
208 struct revocation_reason_info *reason = NULL;
209 KEYDB_HANDLE kdbhd;
210 KEYDB_SEARCH_DESC desc;
211 KBNODE keyblock=NULL,node;
212 u32 keyid[2];
213 int i,any=0;
214 SK_LIST sk_list=NULL;
216 if( opt.batch )
218 log_error(_("can't do this in batch mode\n"));
219 return G10ERR_GENERAL;
222 memset( &afx, 0, sizeof afx);
224 kdbhd = keydb_new (0);
225 classify_user_id (uname, &desc);
226 rc = desc.mode? keydb_search (kdbhd, &desc, 1) : G10ERR_INV_USER_ID;
227 if (rc) {
228 log_error (_("key \"%s\" not found: %s\n"),uname, g10_errstr (rc));
229 goto leave;
232 rc = keydb_get_keyblock (kdbhd, &keyblock );
233 if( rc ) {
234 log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
235 goto leave;
238 /* To parse the revkeys */
239 merge_keys_and_selfsig(keyblock);
241 /* get the key from the keyblock */
242 node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
243 if( !node )
244 BUG ();
246 pk=node->pkt->pkt.public_key;
248 keyid_from_pk(pk,keyid);
250 if(locusr)
252 rc=build_sk_list(locusr,&sk_list,0,PUBKEY_USAGE_CERT);
253 if(rc)
254 goto leave;
257 /* Are we a designated revoker for this key? */
259 if(!pk->revkey && pk->numrevkeys)
260 BUG();
262 for(i=0;i<pk->numrevkeys;i++)
264 SK_LIST list;
266 if(sk)
267 free_secret_key(sk);
269 if(sk_list)
271 for(list=sk_list;list;list=list->next)
273 byte fpr[MAX_FINGERPRINT_LEN];
274 size_t fprlen;
276 fingerprint_from_sk(list->sk,fpr,&fprlen);
278 /* Don't get involved with keys that don't have 160
279 bit fingerprints */
280 if(fprlen!=20)
281 continue;
283 if(memcmp(fpr,pk->revkey[i].fpr,20)==0)
284 break;
287 if(list)
288 sk=copy_secret_key(NULL,list->sk);
289 else
290 continue;
292 else
294 sk=xmalloc_secure_clear(sizeof(*sk));
295 rc=get_seckey_byfprint(sk,pk->revkey[i].fpr,MAX_FINGERPRINT_LEN);
298 /* We have the revocation key */
299 if(!rc)
301 PKT_signature *revkey = NULL;
303 any = 1;
305 print_pubkey_info (NULL, pk);
306 tty_printf ("\n");
308 tty_printf (_("To be revoked by:\n"));
309 print_seckey_info (sk);
311 if(pk->revkey[i].class&0x40)
312 tty_printf(_("(This is a sensitive revocation key)\n"));
313 tty_printf("\n");
315 if( !cpr_get_answer_is_yes("gen_desig_revoke.okay",
316 _("Create a designated revocation certificate for this key? (y/N) ")))
317 continue;
319 /* get the reason for the revocation (this is always v4) */
320 reason = ask_revocation_reason( 1, 0, 1 );
321 if( !reason )
322 continue;
324 rc = check_secret_key( sk, 0 );
325 if( rc )
326 continue;
328 if( !opt.armor )
329 tty_printf(_("ASCII armored output forced.\n"));
331 if( (rc = open_outfile( NULL, 0, &out )) )
332 goto leave;
334 afx.what = 1;
335 afx.hdrlines = "Comment: A designated revocation certificate"
336 " should follow\n";
337 iobuf_push_filter( out, armor_filter, &afx );
339 /* create it */
340 rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 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;
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 */
366 while(!revkey)
368 KBNODE signode;
370 signode=find_next_kbnode(node,PKT_SIGNATURE);
371 if(!signode)
372 break;
374 node=signode;
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))
380 int j;
382 for(j=0;j<signode->pkt->pkt.signature->numrevkeys;j++)
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)
392 revkey=signode->pkt->pkt.signature;
393 break;
399 if(!revkey)
400 BUG();
402 rc=export_minimal_pk(out,keyblock,sig,revkey);
403 if(rc)
404 goto leave;
406 /* and issue a usage notice */
407 tty_printf(_("Revocation certificate created.\n"));
408 break;
412 if(!any)
413 log_error(_("no revocation keys found for \"%s\"\n"),uname);
415 leave:
416 if( pk )
417 free_public_key( pk );
418 if( sk )
419 free_secret_key( sk );
420 if( sig )
421 free_seckey_enc( sig );
423 release_sk_list(sk_list);
425 if( rc )
426 iobuf_cancel(out);
427 else
428 iobuf_close(out);
429 release_revocation_reason_info( reason );
430 return rc;
434 /****************
435 * Generate a revocation certificate for UNAME
438 gen_revoke( const char *uname )
440 int rc = 0;
441 armor_filter_context_t afx;
442 PACKET pkt;
443 PKT_secret_key *sk; /* used as pointer into a kbnode */
444 PKT_public_key *pk = NULL;
445 PKT_signature *sig = NULL;
446 u32 sk_keyid[2];
447 IOBUF out = NULL;
448 KBNODE keyblock = NULL, pub_keyblock = NULL;
449 KBNODE node;
450 KEYDB_HANDLE kdbhd;
451 struct revocation_reason_info *reason = NULL;
452 KEYDB_SEARCH_DESC desc;
454 if( opt.batch )
456 log_error(_("can't do this in batch mode\n"));
457 return G10ERR_GENERAL;
460 memset( &afx, 0, sizeof afx);
461 init_packet( &pkt );
463 /* search the userid:
464 * We don't want the whole getkey stuff here but the entire keyblock
466 kdbhd = keydb_new (1);
467 classify_user_id (uname, &desc);
468 rc = desc.mode? keydb_search (kdbhd, &desc, 1) : G10ERR_INV_USER_ID;
469 if (rc)
471 log_error (_("secret key \"%s\" not found: %s\n"),
472 uname, g10_errstr (rc));
473 goto leave;
476 rc = keydb_get_keyblock (kdbhd, &keyblock );
477 if( rc ) {
478 log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
479 goto leave;
482 /* get the keyid from the keyblock */
483 node = find_kbnode( keyblock, PKT_SECRET_KEY );
484 if( !node )
485 BUG ();
487 /* fixme: should make a function out of this stuff,
488 * it's used all over the source */
489 sk = node->pkt->pkt.secret_key;
490 keyid_from_sk( sk, sk_keyid );
491 print_seckey_info (sk);
493 pk = xmalloc_clear( sizeof *pk );
495 /* FIXME: We should get the public key direct from the secret one */
497 pub_keyblock=get_pubkeyblock(sk_keyid);
498 if(!pub_keyblock)
500 log_error(_("no corresponding public key: %s\n"), g10_errstr(rc) );
501 goto leave;
504 node=find_kbnode(pub_keyblock,PKT_PUBLIC_KEY);
505 if(!node)
506 BUG();
508 pk=node->pkt->pkt.public_key;
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;
516 tty_printf("\n");
517 if( !cpr_get_answer_is_yes("gen_revoke.okay",
518 _("Create a revocation certificate for this key? (y/N) ")) )
520 rc = 0;
521 goto leave;
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;
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;
549 if( rc )
550 goto leave;
553 if( !opt.armor )
554 tty_printf(_("ASCII armored output forced.\n"));
556 if( (rc = open_outfile( NULL, 0, &out )) )
557 goto leave;
559 afx.what = 1;
560 afx.hdrlines = "Comment: A revocation certificate should follow\n";
561 iobuf_push_filter( out, armor_filter, &afx );
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;
572 if(PGP2 || PGP6 || PGP7 || PGP8)
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;
580 else
582 init_packet( &pkt );
583 pkt.pkttype = PKT_SIGNATURE;
584 pkt.pkt.signature = sig;
586 rc = build_packet( out, &pkt );
587 if( rc ) {
588 log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
589 goto leave;
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"));
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 return rc;
617 struct revocation_reason_info *
618 ask_revocation_reason( int key_rev, int cert_rev, int hint )
620 int code=-1;
621 char *description = NULL;
622 struct revocation_reason_info *reason;
623 const char *text_0 = _("No reason specified");
624 const char *text_1 = _("Key has been compromised");
625 const char *text_2 = _("Key is superseded");
626 const char *text_3 = _("Key is no longer used");
627 const char *text_4 = _("User ID is no longer valid");
628 const char *code_text = NULL;
630 do {
631 code=-1;
632 xfree(description);
633 description = NULL;
635 tty_printf(_("Please select the reason for the revocation:\n"));
636 tty_printf( " 0 = %s\n", text_0 );
637 if( key_rev )
638 tty_printf(" 1 = %s\n", text_1 );
639 if( key_rev )
640 tty_printf(" 2 = %s\n", text_2 );
641 if( key_rev )
642 tty_printf(" 3 = %s\n", text_3 );
643 if( cert_rev )
644 tty_printf(" 4 = %s\n", text_4 );
645 tty_printf( " Q = %s\n", _("Cancel") );
646 if( hint )
647 tty_printf(_("(Probably you want to select %d here)\n"), hint );
649 while(code==-1) {
650 int n;
651 char *answer = cpr_get("ask_revocation_reason.code",
652 _("Your decision? "));
653 trim_spaces( answer );
654 cpr_kill_prompt();
655 if( *answer == 'q' || *answer == 'Q')
656 return NULL; /* cancel */
657 if( hint && !*answer )
658 n = hint;
659 else if(!digitp( answer ) )
660 n = -1;
661 else
662 n = atoi(answer);
663 xfree(answer);
664 if( n == 0 ) {
665 code = 0x00; /* no particular reason */
666 code_text = text_0;
668 else if( key_rev && n == 1 ) {
669 code = 0x02; /* key has been compromised */
670 code_text = text_1;
672 else if( key_rev && n == 2 ) {
673 code = 0x01; /* key is superseded */
674 code_text = text_2;
676 else if( key_rev && n == 3 ) {
677 code = 0x03; /* key is no longer used */
678 code_text = text_3;
680 else if( cert_rev && n == 4 ) {
681 code = 0x20; /* uid is no longer valid */
682 code_text = text_4;
684 else
685 tty_printf(_("Invalid selection.\n"));
688 tty_printf(_("Enter an optional description; "
689 "end it with an empty line:\n") );
690 for(;;) {
691 char *answer = cpr_get("ask_revocation_reason.text", "> " );
692 trim_trailing_ws( answer, strlen(answer) );
693 cpr_kill_prompt();
694 if( !*answer ) {
695 xfree(answer);
696 break;
700 char *p = make_printable_string( answer, strlen(answer), 0 );
701 xfree(answer);
702 answer = p;
705 if( !description )
706 description = xstrdup(answer);
707 else {
708 char *p = xmalloc( strlen(description) + strlen(answer) + 2 );
709 strcpy(stpcpy(stpcpy( p, description),"\n"),answer);
710 xfree(description);
711 description = p;
713 xfree(answer);
716 tty_printf(_("Reason for revocation: %s\n"), code_text );
717 if( !description )
718 tty_printf(_("(No description given)\n") );
719 else
720 tty_printf("%s\n", description );
722 } while( !cpr_get_answer_is_yes("ask_revocation_reason.okay",
723 _("Is this okay? (y/N) ")) );
725 reason = xmalloc( sizeof *reason );
726 reason->code = code;
727 reason->desc = description;
728 return reason;
731 void
732 release_revocation_reason_info( struct revocation_reason_info *reason )
734 if( reason ) {
735 xfree( reason->desc );
736 xfree( reason );