2009-05-15 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / g10 / revoke.c
blobcc66dfced62de1a9d53013f2e214cd72930a9f86
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 3 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, see <http://www.gnu.org/licenses/>.
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>
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"
41 struct revocation_reason_info {
42 int code;
43 char *desc;
47 int
48 revocation_reason_build_cb( PKT_signature *sig, void *opaque )
50 struct revocation_reason_info *reason = opaque;
51 char *ud = NULL;
52 byte *buffer;
53 size_t buflen = 1;
55 if(!reason)
56 return 0;
58 if( reason->desc ) {
59 ud = native_to_utf8( reason->desc );
60 buflen += strlen(ud);
62 buffer = xmalloc( buflen );
63 *buffer = reason->code;
64 if( ud ) {
65 memcpy(buffer+1, ud, strlen(ud) );
66 xfree( ud );
69 build_sig_subpkt( sig, SIGSUBPKT_REVOC_REASON, buffer, buflen );
70 xfree( buffer );
71 return 0;
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)
82 KBNODE node;
83 PACKET pkt;
84 PKT_user_id *uid=NULL;
85 PKT_signature *selfsig=NULL;
86 u32 keyid[2];
87 int rc;
89 node=find_kbnode(keyblock,PKT_PUBLIC_KEY);
90 if(!node)
92 log_error("key incomplete\n");
93 return G10ERR_GENERAL;
96 keyid_from_pk(node->pkt->pkt.public_key,keyid);
98 pkt=*node->pkt;
99 rc=build_packet(out,&pkt);
100 if(rc)
102 log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
103 return rc;
106 init_packet(&pkt);
107 pkt.pkttype=PKT_SIGNATURE;
109 /* the revocation itself, if any. 2440 likes this to come first. */
110 if(revsig)
112 pkt.pkt.signature=revsig;
113 rc=build_packet(out,&pkt);
114 if(rc)
116 log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
117 return rc;
121 /* If a revkey in a 1F sig is present, include it too */
122 if(revkey)
124 pkt.pkt.signature=revkey;
125 rc=build_packet(out,&pkt);
126 if(rc)
128 log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
129 return rc;
133 while(!selfsig)
135 KBNODE signode;
137 node=find_next_kbnode(node,PKT_USER_ID);
138 if(!node)
140 /* We're out of user IDs - none were self-signed. */
141 if(uid)
142 break;
143 else
145 log_error(_("key %s has no user IDs\n"),keystr(keyid));
146 return G10ERR_GENERAL;
150 if(node->pkt->pkt.user_id->attrib_data)
151 continue;
153 uid=node->pkt->pkt.user_id;
154 signode=node;
156 while((signode=find_next_kbnode(signode,PKT_SIGNATURE)))
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))
162 selfsig=signode->pkt->pkt.signature;
163 break;
168 pkt.pkttype=PKT_USER_ID;
169 pkt.pkt.user_id=uid;
171 rc=build_packet(out,&pkt);
172 if(rc)
174 log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
175 return rc;
178 if(selfsig)
180 pkt.pkttype=PKT_SIGNATURE;
181 pkt.pkt.signature=selfsig;
183 rc=build_packet(out,&pkt);
184 if(rc)
186 log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
187 return rc;
191 return 0;
194 /****************
195 * Generate a revocation certificate for UNAME via a designated revoker
198 gen_desig_revoke( const char *uname, strlist_t locusr )
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 SK_LIST sk_list=NULL;
214 if( opt.batch )
216 log_error(_("can't do this in batch mode\n"));
217 return G10ERR_GENERAL;
220 afx = new_armor_context ();
222 kdbhd = keydb_new (0);
223 classify_user_id (uname, &desc);
224 rc = desc.mode? keydb_search (kdbhd, &desc, 1) : G10ERR_INV_USER_ID;
225 if (rc) {
226 log_error (_("key \"%s\" not found: %s\n"),uname, g10_errstr (rc));
227 goto leave;
230 rc = keydb_get_keyblock (kdbhd, &keyblock );
231 if( rc ) {
232 log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
233 goto leave;
236 /* To parse the revkeys */
237 merge_keys_and_selfsig(keyblock);
239 /* get the key from the keyblock */
240 node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
241 if( !node )
242 BUG ();
244 pk=node->pkt->pkt.public_key;
246 keyid_from_pk(pk,keyid);
248 if(locusr)
250 rc=build_sk_list(locusr,&sk_list,0,PUBKEY_USAGE_CERT);
251 if(rc)
252 goto leave;
255 /* Are we a designated revoker for this key? */
257 if(!pk->revkey && pk->numrevkeys)
258 BUG();
260 for(i=0;i<pk->numrevkeys;i++)
262 SK_LIST list;
264 if(sk)
265 free_secret_key(sk);
267 if(sk_list)
269 for(list=sk_list;list;list=list->next)
271 byte fpr[MAX_FINGERPRINT_LEN];
272 size_t fprlen;
274 fingerprint_from_sk(list->sk,fpr,&fprlen);
276 /* Don't get involved with keys that don't have 160
277 bit fingerprints */
278 if(fprlen!=20)
279 continue;
281 if(memcmp(fpr,pk->revkey[i].fpr,20)==0)
282 break;
285 if(list)
286 sk=copy_secret_key(NULL,list->sk);
287 else
288 continue;
290 else
292 sk=xmalloc_secure_clear(sizeof(*sk));
293 rc=get_seckey_byfprint(sk,pk->revkey[i].fpr,MAX_FINGERPRINT_LEN);
296 /* We have the revocation key */
297 if(!rc)
299 PKT_signature *revkey = NULL;
301 any = 1;
303 print_pubkey_info (NULL, pk);
304 tty_printf ("\n");
306 tty_printf (_("To be revoked by:\n"));
307 print_seckey_info (sk);
309 if(pk->revkey[i].class&0x40)
310 tty_printf(_("(This is a sensitive revocation key)\n"));
311 tty_printf("\n");
313 if( !cpr_get_answer_is_yes("gen_desig_revoke.okay",
314 _("Create a designated revocation certificate for this key? (y/N) ")))
315 continue;
317 /* get the reason for the revocation (this is always v4) */
318 reason = ask_revocation_reason( 1, 0, 1 );
319 if( !reason )
320 continue;
322 rc = check_secret_key( sk, 0 );
323 if( rc )
324 continue;
326 if( !opt.armor )
327 tty_printf(_("ASCII armored output forced.\n"));
329 if( (rc = open_outfile( NULL, 0, &out )) )
330 goto leave;
332 afx->what = 1;
333 afx->hdrlines = "Comment: A designated revocation certificate"
334 " should follow\n";
335 push_armor_filter (afx, out);
337 /* create it */
338 rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x20, 0,
339 0, 0, 0,
340 revocation_reason_build_cb, reason );
341 if( rc ) {
342 log_error(_("make_keysig_packet failed: %s\n"), g10_errstr(rc));
343 goto leave;
346 /* Spit out a minimal pk as well, since otherwise there is
347 no way to know which key to attach this revocation to.
348 Also include the direct key signature that contains
349 this revocation key. We're allowed to include
350 sensitive revocation keys along with a revocation, as
351 this may be the only time the recipient has seen it.
352 Note that this means that if we have multiple different
353 sensitive revocation keys in a given direct key
354 signature, we're going to include them all here. This
355 is annoying, but the good outweighs the bad, since
356 without including this a sensitive revoker can't really
357 do their job. People should not include multiple
358 sensitive revocation keys in one signature: 2440 says
359 "Note that it may be appropriate to isolate this
360 subpacket within a separate signature so that it is not
361 combined with other subpackets that need to be
362 exported." -dms */
364 while(!revkey)
366 KBNODE signode;
368 signode=find_next_kbnode(node,PKT_SIGNATURE);
369 if(!signode)
370 break;
372 node=signode;
374 if(keyid[0]==signode->pkt->pkt.signature->keyid[0] &&
375 keyid[1]==signode->pkt->pkt.signature->keyid[1] &&
376 IS_KEY_SIG(signode->pkt->pkt.signature))
378 int j;
380 for(j=0;j<signode->pkt->pkt.signature->numrevkeys;j++)
382 if(pk->revkey[i].class==
383 signode->pkt->pkt.signature->revkey[j]->class &&
384 pk->revkey[i].algid==
385 signode->pkt->pkt.signature->revkey[j]->algid &&
386 memcmp(pk->revkey[i].fpr,
387 signode->pkt->pkt.signature->revkey[j]->fpr,
388 MAX_FINGERPRINT_LEN)==0)
390 revkey=signode->pkt->pkt.signature;
391 break;
397 if(!revkey)
398 BUG();
400 rc=export_minimal_pk(out,keyblock,sig,revkey);
401 if(rc)
402 goto leave;
404 /* and issue a usage notice */
405 tty_printf(_("Revocation certificate created.\n"));
406 break;
410 if(!any)
411 log_error(_("no revocation keys found for \"%s\"\n"),uname);
413 leave:
414 if( pk )
415 free_public_key( pk );
416 if( sk )
417 free_secret_key( sk );
418 if( sig )
419 free_seckey_enc( sig );
421 release_sk_list(sk_list);
423 if( rc )
424 iobuf_cancel(out);
425 else
426 iobuf_close(out);
427 release_revocation_reason_info( reason );
428 release_armor_context (afx);
429 return rc;
433 /****************
434 * Generate a revocation certificate for UNAME
437 gen_revoke( const char *uname )
439 int rc = 0;
440 armor_filter_context_t *afx;
441 PACKET pkt;
442 PKT_secret_key *sk; /* used as pointer into a kbnode */
443 PKT_public_key *pk = NULL;
444 PKT_signature *sig = NULL;
445 u32 sk_keyid[2];
446 IOBUF out = NULL;
447 KBNODE keyblock = NULL, pub_keyblock = NULL;
448 KBNODE node;
449 KEYDB_HANDLE kdbhd;
450 struct revocation_reason_info *reason = NULL;
451 KEYDB_SEARCH_DESC desc;
453 if( opt.batch )
455 log_error(_("can't do this in batch mode\n"));
456 return G10ERR_GENERAL;
459 afx = new_armor_context ();
460 init_packet( &pkt );
462 /* search the userid:
463 * We don't want the whole getkey stuff here but the entire keyblock
465 kdbhd = keydb_new (1);
466 classify_user_id (uname, &desc);
467 rc = desc.mode? keydb_search (kdbhd, &desc, 1) : G10ERR_INV_USER_ID;
468 if (rc)
470 log_error (_("secret key \"%s\" not found: %s\n"),
471 uname, g10_errstr (rc));
472 goto leave;
475 rc = keydb_get_keyblock (kdbhd, &keyblock );
476 if( rc ) {
477 log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
478 goto leave;
481 /* get the keyid from the keyblock */
482 node = find_kbnode( keyblock, PKT_SECRET_KEY );
483 if( !node )
484 BUG ();
486 /* fixme: should make a function out of this stuff,
487 * it's used all over the source */
488 sk = node->pkt->pkt.secret_key;
489 keyid_from_sk( sk, sk_keyid );
490 print_seckey_info (sk);
492 pk = xmalloc_clear( sizeof *pk );
494 /* FIXME: We should get the public key direct from the secret one */
496 pub_keyblock=get_pubkeyblock(sk_keyid);
497 if(!pub_keyblock)
499 log_error(_("no corresponding public key: %s\n"), g10_errstr(rc) );
500 goto leave;
503 node=find_kbnode(pub_keyblock,PKT_PUBLIC_KEY);
504 if(!node)
505 BUG();
507 pk=node->pkt->pkt.public_key;
509 if( cmp_public_secret_key( pk, sk ) ) {
510 log_error(_("public key does not match secret key!\n") );
511 rc = G10ERR_GENERAL;
512 goto leave;
515 tty_printf("\n");
516 if( !cpr_get_answer_is_yes("gen_revoke.okay",
517 _("Create a revocation certificate for this key? (y/N) ")) )
519 rc = 0;
520 goto leave;
523 if(sk->version>=4 || opt.force_v4_certs) {
524 /* get the reason for the revocation */
525 reason = ask_revocation_reason( 1, 0, 1 );
526 if( !reason ) { /* user decided to cancel */
527 rc = 0;
528 goto leave;
532 switch( is_secret_key_protected( sk ) ) {
533 case -1:
534 log_error(_("unknown protection algorithm\n"));
535 rc = G10ERR_PUBKEY_ALGO;
536 break;
537 case -3:
538 tty_printf (_("Secret parts of primary key are not available.\n"));
539 rc = G10ERR_NO_SECKEY;
540 break;
541 case 0:
542 tty_printf(_("NOTE: This key is not protected!\n"));
543 break;
544 default:
545 rc = check_secret_key( sk, 0 );
546 break;
548 if( rc )
549 goto leave;
552 if( !opt.armor )
553 tty_printf(_("ASCII armored output forced.\n"));
555 if( (rc = open_outfile( NULL, 0, &out )) )
556 goto leave;
558 afx->what = 1;
559 afx->hdrlines = "Comment: A revocation certificate should follow\n";
560 push_armor_filter (afx, out);
562 /* create it */
563 rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x20, 0,
564 opt.force_v4_certs?4:0, 0, 0,
565 revocation_reason_build_cb, reason );
566 if( rc ) {
567 log_error(_("make_keysig_packet failed: %s\n"), g10_errstr(rc));
568 goto leave;
571 if(PGP2 || PGP6 || PGP7 || PGP8)
573 /* Use a minimal pk for PGPx mode, since PGP can't import bare
574 revocation certificates. */
575 rc=export_minimal_pk(out,pub_keyblock,sig,NULL);
576 if(rc)
577 goto leave;
579 else
581 init_packet( &pkt );
582 pkt.pkttype = PKT_SIGNATURE;
583 pkt.pkt.signature = sig;
585 rc = build_packet( out, &pkt );
586 if( rc ) {
587 log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
588 goto leave;
592 /* and issue a usage notice */
593 tty_printf(_("Revocation certificate created.\n\n"
594 "Please move it to a medium which you can hide away; if Mallory gets\n"
595 "access to this certificate he can use it to make your key unusable.\n"
596 "It is smart to print this certificate and store it away, just in case\n"
597 "your media become unreadable. But have some caution: The print system of\n"
598 "your machine might store the data and make it available to others!\n"));
600 leave:
601 if( sig )
602 free_seckey_enc( sig );
603 release_kbnode( keyblock );
604 release_kbnode( pub_keyblock );
605 keydb_release (kdbhd);
606 if( rc )
607 iobuf_cancel(out);
608 else
609 iobuf_close(out);
610 release_revocation_reason_info( reason );
611 release_armor_context (afx);
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 );