Line data Source code
1 : /* revoke.c - Create recovation certificates.
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 <https://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 <ctype.h>
27 :
28 : #include "gpg.h"
29 : #include "options.h"
30 : #include "packet.h"
31 : #include "status.h"
32 : #include "keydb.h"
33 : #include "util.h"
34 : #include "main.h"
35 : #include "ttyio.h"
36 : #include "status.h"
37 : #include "i18n.h"
38 : #include "call-agent.h"
39 :
40 : struct revocation_reason_info {
41 : int code;
42 : char *desc;
43 : };
44 :
45 :
46 : int
47 4 : revocation_reason_build_cb( PKT_signature *sig, void *opaque )
48 : {
49 4 : struct revocation_reason_info *reason = opaque;
50 4 : char *ud = NULL;
51 : byte *buffer;
52 4 : size_t buflen = 1;
53 :
54 4 : if(!reason)
55 0 : return 0;
56 :
57 4 : if( reason->desc ) {
58 1 : ud = native_to_utf8( reason->desc );
59 1 : buflen += strlen(ud);
60 : }
61 4 : buffer = xmalloc( buflen );
62 4 : *buffer = reason->code;
63 4 : if( ud ) {
64 1 : memcpy(buffer+1, ud, strlen(ud) );
65 1 : xfree( ud );
66 : }
67 :
68 4 : build_sig_subpkt( sig, SIGSUBPKT_REVOC_REASON, buffer, buflen );
69 4 : xfree( buffer );
70 4 : return 0;
71 : }
72 :
73 : /* Outputs a minimal pk (as defined by 2440) from a keyblock. A
74 : minimal pk consists of the public key packet and a user ID. We try
75 : and pick a user ID that has a uid signature, and include it if
76 : possible. */
77 : static int
78 0 : export_minimal_pk(IOBUF out,KBNODE keyblock,
79 : PKT_signature *revsig,PKT_signature *revkey)
80 : {
81 : KBNODE node;
82 : PACKET pkt;
83 0 : PKT_user_id *uid=NULL;
84 0 : PKT_signature *selfsig=NULL;
85 : u32 keyid[2];
86 : int rc;
87 :
88 0 : node=find_kbnode(keyblock,PKT_PUBLIC_KEY);
89 0 : if(!node)
90 : {
91 0 : log_error("key incomplete\n");
92 0 : return GPG_ERR_GENERAL;
93 : }
94 :
95 0 : keyid_from_pk(node->pkt->pkt.public_key,keyid);
96 :
97 0 : pkt=*node->pkt;
98 0 : rc=build_packet(out,&pkt);
99 0 : if(rc)
100 : {
101 0 : log_error(_("build_packet failed: %s\n"), gpg_strerror (rc) );
102 0 : return rc;
103 : }
104 :
105 0 : init_packet(&pkt);
106 0 : pkt.pkttype=PKT_SIGNATURE;
107 :
108 : /* the revocation itself, if any. 2440 likes this to come first. */
109 0 : if(revsig)
110 : {
111 0 : pkt.pkt.signature=revsig;
112 0 : rc=build_packet(out,&pkt);
113 0 : if(rc)
114 : {
115 0 : log_error("build_packet failed: %s\n", gpg_strerror (rc) );
116 0 : return rc;
117 : }
118 : }
119 :
120 : /* If a revkey in a 1F sig is present, include it too */
121 0 : if(revkey)
122 : {
123 0 : pkt.pkt.signature=revkey;
124 0 : rc=build_packet(out,&pkt);
125 0 : if(rc)
126 : {
127 0 : log_error(_("build_packet failed: %s\n"), gpg_strerror (rc) );
128 0 : return rc;
129 : }
130 : }
131 :
132 0 : while(!selfsig)
133 : {
134 : KBNODE signode;
135 :
136 0 : node=find_next_kbnode(node,PKT_USER_ID);
137 0 : if(!node)
138 : {
139 : /* We're out of user IDs - none were self-signed. */
140 0 : if(uid)
141 0 : break;
142 : else
143 : {
144 0 : log_error(_("key %s has no user IDs\n"),keystr(keyid));
145 0 : return GPG_ERR_GENERAL;
146 : }
147 : }
148 :
149 0 : if(node->pkt->pkt.user_id->attrib_data)
150 0 : continue;
151 :
152 0 : uid=node->pkt->pkt.user_id;
153 0 : signode=node;
154 :
155 0 : while((signode=find_next_kbnode(signode,PKT_SIGNATURE)))
156 : {
157 0 : if(keyid[0]==signode->pkt->pkt.signature->keyid[0] &&
158 0 : keyid[1]==signode->pkt->pkt.signature->keyid[1] &&
159 0 : IS_UID_SIG(signode->pkt->pkt.signature))
160 : {
161 0 : selfsig=signode->pkt->pkt.signature;
162 0 : break;
163 : }
164 : }
165 : }
166 :
167 0 : pkt.pkttype=PKT_USER_ID;
168 0 : pkt.pkt.user_id=uid;
169 :
170 0 : rc=build_packet(out,&pkt);
171 0 : if(rc)
172 : {
173 0 : log_error(_("build_packet failed: %s\n"), gpg_strerror (rc) );
174 0 : return rc;
175 : }
176 :
177 0 : if(selfsig)
178 : {
179 0 : pkt.pkttype=PKT_SIGNATURE;
180 0 : pkt.pkt.signature=selfsig;
181 :
182 0 : rc=build_packet(out,&pkt);
183 0 : if(rc)
184 : {
185 0 : log_error(_("build_packet failed: %s\n"), gpg_strerror (rc) );
186 0 : return rc;
187 : }
188 : }
189 :
190 0 : return 0;
191 : }
192 :
193 : /****************
194 : * Generate a revocation certificate for UNAME via a designated revoker
195 : */
196 : int
197 0 : gen_desig_revoke (ctrl_t ctrl, const char *uname, strlist_t locusr)
198 : {
199 0 : int rc = 0;
200 : armor_filter_context_t *afx;
201 0 : PKT_public_key *pk = NULL;
202 0 : PKT_public_key *pk2 = NULL;
203 0 : PKT_signature *sig = NULL;
204 0 : IOBUF out = NULL;
205 0 : struct revocation_reason_info *reason = NULL;
206 : KEYDB_HANDLE kdbhd;
207 : KEYDB_SEARCH_DESC desc;
208 0 : KBNODE keyblock=NULL,node;
209 : u32 keyid[2];
210 0 : int i,any=0;
211 0 : SK_LIST sk_list=NULL;
212 :
213 0 : if( opt.batch )
214 : {
215 0 : log_error(_("can't do this in batch mode\n"));
216 0 : return GPG_ERR_GENERAL;
217 : }
218 :
219 0 : afx = new_armor_context ();
220 :
221 0 : kdbhd = keydb_new ();
222 0 : if (!kdbhd)
223 : {
224 0 : rc = gpg_error_from_syserror ();
225 0 : goto leave;
226 : }
227 0 : rc = classify_user_id (uname, &desc, 1);
228 0 : if (!rc)
229 0 : rc = keydb_search (kdbhd, &desc, 1, NULL);
230 0 : if (rc) {
231 0 : log_error (_("key \"%s\" not found: %s\n"),uname, gpg_strerror (rc));
232 0 : goto leave;
233 : }
234 :
235 0 : rc = keydb_get_keyblock (kdbhd, &keyblock );
236 0 : if( rc ) {
237 0 : log_error (_("error reading keyblock: %s\n"), gpg_strerror (rc) );
238 0 : goto leave;
239 : }
240 :
241 : /* To parse the revkeys */
242 0 : merge_keys_and_selfsig(keyblock);
243 :
244 : /* get the key from the keyblock */
245 0 : node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
246 0 : if( !node )
247 0 : BUG ();
248 :
249 0 : pk=node->pkt->pkt.public_key;
250 :
251 0 : keyid_from_pk(pk,keyid);
252 :
253 0 : if(locusr)
254 : {
255 0 : rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_CERT);
256 0 : if(rc)
257 0 : goto leave;
258 : }
259 :
260 : /* Are we a designated revoker for this key? */
261 :
262 0 : if(!pk->revkey && pk->numrevkeys)
263 0 : BUG();
264 :
265 0 : for(i=0;i<pk->numrevkeys;i++)
266 : {
267 : SK_LIST list;
268 :
269 0 : free_public_key (pk2);
270 0 : pk2 = NULL;
271 :
272 0 : if(sk_list)
273 : {
274 0 : for(list=sk_list;list;list=list->next)
275 : {
276 : byte fpr[MAX_FINGERPRINT_LEN];
277 : size_t fprlen;
278 :
279 0 : fingerprint_from_pk (list->pk, fpr, &fprlen);
280 :
281 : /* Don't get involved with keys that don't have 160
282 : bit fingerprints */
283 0 : if(fprlen!=20)
284 0 : continue;
285 :
286 0 : if(memcmp(fpr,pk->revkey[i].fpr,20)==0)
287 0 : break;
288 : }
289 :
290 0 : if (list)
291 0 : pk2 = copy_public_key (NULL, list->pk);
292 : else
293 0 : continue;
294 : }
295 : else
296 : {
297 0 : pk2 = xmalloc_clear (sizeof *pk2);
298 0 : rc = get_pubkey_byfprint (pk2, NULL,
299 0 : pk->revkey[i].fpr, MAX_FINGERPRINT_LEN);
300 : }
301 :
302 : /* We have the revocation key. */
303 0 : if(!rc)
304 : {
305 0 : PKT_signature *revkey = NULL;
306 :
307 0 : any = 1;
308 :
309 0 : print_pubkey_info (NULL, pk);
310 0 : tty_printf ("\n");
311 :
312 0 : tty_printf (_("To be revoked by:\n"));
313 0 : print_seckey_info (pk2);
314 :
315 0 : if(pk->revkey[i].class&0x40)
316 0 : tty_printf(_("(This is a sensitive revocation key)\n"));
317 0 : tty_printf("\n");
318 :
319 0 : rc = agent_probe_secret_key (ctrl, pk2);
320 0 : if (rc)
321 : {
322 0 : tty_printf (_("Secret key is not available.\n"));
323 0 : continue;
324 : }
325 :
326 0 : if( !cpr_get_answer_is_yes("gen_desig_revoke.okay",
327 0 : _("Create a designated revocation certificate for this key? (y/N) ")))
328 0 : continue;
329 :
330 : /* get the reason for the revocation (this is always v4) */
331 0 : reason = ask_revocation_reason( 1, 0, 1 );
332 0 : if( !reason )
333 0 : continue;
334 :
335 0 : if( !opt.armor )
336 0 : tty_printf(_("ASCII armored output forced.\n"));
337 :
338 0 : if( (rc = open_outfile (-1, NULL, 0, 1, &out )) )
339 0 : goto leave;
340 :
341 0 : afx->what = 1;
342 0 : afx->hdrlines = "Comment: A designated revocation certificate"
343 : " should follow\n";
344 0 : push_armor_filter (afx, out);
345 :
346 : /* create it */
347 0 : rc = make_keysig_packet( &sig, pk, NULL, NULL, pk2, 0x20, 0,
348 : 0, 0,
349 : revocation_reason_build_cb, reason,
350 : NULL);
351 0 : if( rc ) {
352 0 : log_error(_("make_keysig_packet failed: %s\n"), gpg_strerror (rc));
353 0 : goto leave;
354 : }
355 :
356 : /* Spit out a minimal pk as well, since otherwise there is
357 : no way to know which key to attach this revocation to.
358 : Also include the direct key signature that contains
359 : this revocation key. We're allowed to include
360 : sensitive revocation keys along with a revocation, as
361 : this may be the only time the recipient has seen it.
362 : Note that this means that if we have multiple different
363 : sensitive revocation keys in a given direct key
364 : signature, we're going to include them all here. This
365 : is annoying, but the good outweighs the bad, since
366 : without including this a sensitive revoker can't really
367 : do their job. People should not include multiple
368 : sensitive revocation keys in one signature: 2440 says
369 : "Note that it may be appropriate to isolate this
370 : subpacket within a separate signature so that it is not
371 : combined with other subpackets that need to be
372 : exported." -dms */
373 :
374 0 : while(!revkey)
375 : {
376 : KBNODE signode;
377 :
378 0 : signode=find_next_kbnode(node,PKT_SIGNATURE);
379 0 : if(!signode)
380 0 : break;
381 :
382 0 : node=signode;
383 :
384 0 : if(keyid[0]==signode->pkt->pkt.signature->keyid[0] &&
385 0 : keyid[1]==signode->pkt->pkt.signature->keyid[1] &&
386 0 : IS_KEY_SIG(signode->pkt->pkt.signature))
387 : {
388 : int j;
389 :
390 0 : for(j=0;j<signode->pkt->pkt.signature->numrevkeys;j++)
391 : {
392 0 : if(pk->revkey[i].class==
393 0 : signode->pkt->pkt.signature->revkey[j].class &&
394 0 : pk->revkey[i].algid==
395 0 : signode->pkt->pkt.signature->revkey[j].algid &&
396 0 : memcmp(pk->revkey[i].fpr,
397 0 : signode->pkt->pkt.signature->revkey[j].fpr,
398 : MAX_FINGERPRINT_LEN)==0)
399 : {
400 0 : revkey=signode->pkt->pkt.signature;
401 0 : break;
402 : }
403 : }
404 : }
405 : }
406 :
407 0 : if(!revkey)
408 0 : BUG();
409 :
410 0 : rc=export_minimal_pk(out,keyblock,sig,revkey);
411 0 : if(rc)
412 0 : goto leave;
413 :
414 : /* and issue a usage notice */
415 0 : tty_printf(_("Revocation certificate created.\n"));
416 0 : break;
417 : }
418 : }
419 :
420 0 : if(!any)
421 0 : log_error(_("no revocation keys found for \"%s\"\n"),uname);
422 :
423 : leave:
424 0 : free_public_key (pk);
425 0 : free_public_key (pk2);
426 0 : if( sig )
427 0 : free_seckey_enc( sig );
428 :
429 0 : release_sk_list(sk_list);
430 :
431 0 : if( rc )
432 0 : iobuf_cancel(out);
433 : else
434 0 : iobuf_close(out);
435 0 : release_revocation_reason_info( reason );
436 0 : release_armor_context (afx);
437 0 : return rc;
438 : }
439 :
440 :
441 : /* Common core to create the revocation. FILENAME may be NULL to write
442 : to stdout or the filename given by --output. REASON describes the
443 : revocation reason. PSK is the public primary key - we expect that
444 : a corresponding secret key is available. KEYBLOCK is the entire
445 : KEYBLOCK which is used in PGP mode to write a a minimal key and not
446 : just the naked revocation signature; it may be NULL. If LEADINTEXT
447 : is not NULL, it is written right before the (armored) output.*/
448 : static int
449 3 : create_revocation (const char *filename,
450 : struct revocation_reason_info *reason,
451 : PKT_public_key *psk,
452 : kbnode_t keyblock,
453 : const char *leadintext, int suffix,
454 : const char *cache_nonce)
455 : {
456 : int rc;
457 3 : iobuf_t out = NULL;
458 : armor_filter_context_t *afx;
459 3 : PKT_signature *sig = NULL;
460 : PACKET pkt;
461 :
462 3 : afx = new_armor_context ();
463 :
464 3 : if ((rc = open_outfile (-1, filename, suffix, 1, &out)))
465 0 : goto leave;
466 :
467 3 : if (leadintext )
468 3 : iobuf_writestr (out, leadintext);
469 :
470 3 : afx->what = 1;
471 3 : afx->hdrlines = "Comment: This is a revocation certificate\n";
472 3 : push_armor_filter (afx, out);
473 :
474 3 : rc = make_keysig_packet (&sig, psk, NULL, NULL, psk, 0x20, 0,
475 : 0, 0,
476 : revocation_reason_build_cb, reason, cache_nonce);
477 3 : if (rc)
478 : {
479 0 : log_error (_("make_keysig_packet failed: %s\n"), gpg_strerror (rc));
480 0 : goto leave;
481 : }
482 :
483 3 : if (keyblock && (PGP6 || PGP7 || PGP8))
484 : {
485 : /* Use a minimal pk for PGPx mode, since PGP can't import bare
486 : revocation certificates. */
487 0 : rc = export_minimal_pk (out, keyblock, sig, NULL);
488 0 : if (rc)
489 0 : goto leave;
490 : }
491 : else
492 : {
493 3 : init_packet (&pkt);
494 3 : pkt.pkttype = PKT_SIGNATURE;
495 3 : pkt.pkt.signature = sig;
496 :
497 3 : rc = build_packet (out, &pkt);
498 3 : if (rc)
499 : {
500 0 : log_error (_("build_packet failed: %s\n"), gpg_strerror (rc));
501 0 : goto leave;
502 : }
503 : }
504 :
505 : leave:
506 3 : if (sig)
507 3 : free_seckey_enc (sig);
508 3 : if (rc)
509 0 : iobuf_cancel (out);
510 : else
511 3 : iobuf_close (out);
512 3 : release_armor_context (afx);
513 3 : return rc;
514 : }
515 :
516 :
517 : /* This function is used to generate a standard revocation certificate
518 : by gpg's interactive key generation function. The certificate is
519 : stored at a dedicated place in a slightly modified form to avoid an
520 : accidental import. PSK is the primary key; a corresponding secret
521 : key must be available. CACHE_NONCE is optional but can be used to
522 : help gpg-agent to avoid an extra passphrase prompt. */
523 : int
524 3 : gen_standard_revoke (PKT_public_key *psk, const char *cache_nonce)
525 : {
526 : int rc;
527 : estream_t memfp;
528 : struct revocation_reason_info reason;
529 : char *dir, *tmpstr, *fname;
530 : void *leadin;
531 : size_t len;
532 : u32 keyid[2];
533 : int kl;
534 : char *orig_codeset;
535 :
536 3 : dir = get_openpgp_revocdir (gnupg_homedir ());
537 3 : tmpstr = hexfingerprint (psk, NULL, 0);
538 3 : fname = xstrconcat (dir, DIRSEP_S, tmpstr, NULL);
539 3 : xfree (tmpstr);
540 3 : xfree (dir);
541 :
542 3 : keyid_from_pk (psk, keyid);
543 :
544 3 : memfp = es_fopenmem (0, "r+");
545 3 : if (!memfp)
546 0 : log_fatal ("error creating memory stream\n");
547 :
548 3 : orig_codeset = i18n_switchto_utf8 ();
549 :
550 3 : es_fprintf (memfp, "%s\n\n",
551 : _("This is a revocation certificate for the OpenPGP key:"));
552 :
553 3 : print_key_line (memfp, psk, 0);
554 :
555 3 : if (opt.keyid_format != KF_NONE)
556 0 : print_fingerprint (memfp, psk, 3);
557 :
558 3 : kl = opt.keyid_format == KF_NONE? 0 : keystrlen ();
559 :
560 3 : tmpstr = get_user_id (keyid, &len);
561 3 : es_fprintf (memfp, "uid%*s%.*s\n\n",
562 : kl + 10, "",
563 : (int)len, tmpstr);
564 3 : xfree (tmpstr);
565 :
566 3 : es_fprintf (memfp, "%s\n\n%s\n\n%s\n\n:",
567 : _("A revocation certificate is a kind of \"kill switch\" to publicly\n"
568 : "declare that a key shall not anymore be used. It is not possible\n"
569 : "to retract such a revocation certificate once it has been published."),
570 : _("Use it to revoke this key in case of a compromise or loss of\n"
571 : "the secret key. However, if the secret key is still accessible,\n"
572 : "it is better to generate a new revocation certificate and give\n"
573 : "a reason for the revocation. For details see the description of\n"
574 : "of the gpg command \"--gen-revoke\" in the GnuPG manual."),
575 : _("To avoid an accidental use of this file, a colon has been inserted\n"
576 : "before the 5 dashes below. Remove this colon with a text editor\n"
577 : "before importing and publishing this revocation certificate."));
578 :
579 3 : es_putc (0, memfp);
580 :
581 3 : i18n_switchback (orig_codeset);
582 :
583 3 : if (es_fclose_snatch (memfp, &leadin, NULL))
584 0 : log_fatal ("error snatching memory stream\n");
585 :
586 3 : reason.code = 0x00; /* No particular reason. */
587 3 : reason.desc = NULL;
588 3 : rc = create_revocation (fname, &reason, psk, NULL, leadin, 3, cache_nonce);
589 3 : if (!rc && !opt.quiet)
590 1 : log_info (_("revocation certificate stored as '%s.rev'\n"), fname);
591 :
592 3 : xfree (leadin);
593 3 : xfree (fname);
594 :
595 3 : return rc;
596 : }
597 :
598 :
599 :
600 : /****************
601 : * Generate a revocation certificate for UNAME
602 : */
603 : int
604 0 : gen_revoke (const char *uname)
605 : {
606 0 : int rc = 0;
607 : PKT_public_key *psk;
608 : u32 keyid[2];
609 0 : kbnode_t keyblock = NULL;
610 : kbnode_t node;
611 : KEYDB_HANDLE kdbhd;
612 0 : struct revocation_reason_info *reason = NULL;
613 : KEYDB_SEARCH_DESC desc;
614 :
615 0 : if( opt.batch )
616 : {
617 0 : log_error(_("can't do this in batch mode\n"));
618 0 : return GPG_ERR_GENERAL;
619 : }
620 :
621 : /* Search the userid; we don't want the whole getkey stuff here. */
622 0 : kdbhd = keydb_new ();
623 0 : if (!kdbhd)
624 : {
625 0 : rc = gpg_error_from_syserror ();
626 0 : goto leave;
627 : }
628 0 : rc = classify_user_id (uname, &desc, 1);
629 0 : if (!rc)
630 0 : rc = keydb_search (kdbhd, &desc, 1, NULL);
631 0 : if (rc)
632 : {
633 0 : if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
634 0 : log_error (_("secret key \"%s\" not found\n"), uname);
635 : else
636 0 : log_error (_("secret key \"%s\" not found: %s\n"),
637 : uname, gpg_strerror (rc));
638 0 : goto leave;
639 : }
640 :
641 0 : rc = keydb_get_keyblock (kdbhd, &keyblock );
642 0 : if (rc)
643 : {
644 0 : log_error (_("error reading keyblock: %s\n"), gpg_strerror (rc) );
645 0 : goto leave;
646 : }
647 :
648 0 : rc = keydb_search (kdbhd, &desc, 1, NULL);
649 0 : if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
650 : /* Not ambiguous. */
651 : {
652 : }
653 0 : else if (rc == 0)
654 : /* Ambiguous. */
655 : {
656 : char *info;
657 :
658 : /* TRANSLATORS: The %s prints a key specification which
659 : for example has been given at the command line. Several lines
660 : lines with secret key infos are printed after this message. */
661 0 : log_error (_("'%s' matches multiple secret keys:\n"), uname);
662 :
663 0 : info = format_seckey_info (keyblock->pkt->pkt.public_key);
664 0 : log_error (" %s\n", info);
665 0 : xfree (info);
666 0 : release_kbnode (keyblock);
667 :
668 0 : rc = keydb_get_keyblock (kdbhd, &keyblock);
669 0 : while (! rc)
670 : {
671 0 : info = format_seckey_info (keyblock->pkt->pkt.public_key);
672 0 : log_info (" %s\n", info);
673 0 : xfree (info);
674 0 : release_kbnode (keyblock);
675 0 : keyblock = NULL;
676 :
677 0 : rc = keydb_search (kdbhd, &desc, 1, NULL);
678 0 : if (! rc)
679 0 : rc = keydb_get_keyblock (kdbhd, &keyblock);
680 : }
681 :
682 0 : rc = GPG_ERR_AMBIGUOUS_NAME;
683 :
684 0 : goto leave;
685 : }
686 : else
687 : {
688 0 : log_error (_("error searching the keyring: %s\n"), gpg_strerror (rc));
689 0 : goto leave;
690 : }
691 :
692 : /* Get the keyid from the keyblock. */
693 0 : node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
694 0 : if (!node)
695 0 : BUG ();
696 :
697 0 : psk = node->pkt->pkt.public_key;
698 0 : rc = agent_probe_secret_key (NULL, psk);
699 0 : if (rc)
700 : {
701 0 : log_error (_("secret key \"%s\" not found: %s\n"),
702 : uname, gpg_strerror (rc));
703 0 : goto leave;
704 : }
705 :
706 0 : keyid_from_pk (psk, keyid );
707 0 : print_seckey_info (psk);
708 :
709 0 : tty_printf("\n");
710 0 : if (!cpr_get_answer_is_yes ("gen_revoke.okay",
711 0 : _("Create a revocation certificate for this key? (y/N) ")))
712 : {
713 0 : rc = 0;
714 0 : goto leave;
715 : }
716 :
717 : /* Get the reason for the revocation. */
718 0 : reason = ask_revocation_reason (1, 0, 1);
719 0 : if (!reason)
720 : {
721 : /* User decided to cancel. */
722 0 : rc = 0;
723 0 : goto leave;
724 : }
725 :
726 0 : if (!opt.armor)
727 0 : tty_printf (_("ASCII armored output forced.\n"));
728 :
729 0 : rc = create_revocation (NULL, reason, psk, keyblock, NULL, 0, NULL);
730 0 : if (rc)
731 0 : goto leave;
732 :
733 : /* and issue a usage notice */
734 0 : tty_printf (_(
735 : "Revocation certificate created.\n\n"
736 : "Please move it to a medium which you can hide away; if Mallory gets\n"
737 : "access to this certificate he can use it to make your key unusable.\n"
738 : "It is smart to print this certificate and store it away, just in case\n"
739 : "your media become unreadable. But have some caution: The print system of\n"
740 : "your machine might store the data and make it available to others!\n"));
741 :
742 : leave:
743 0 : release_kbnode (keyblock);
744 0 : keydb_release (kdbhd);
745 0 : release_revocation_reason_info( reason );
746 0 : return rc;
747 : }
748 :
749 :
750 :
751 : struct revocation_reason_info *
752 0 : ask_revocation_reason( int key_rev, int cert_rev, int hint )
753 : {
754 0 : int code=-1;
755 0 : char *description = NULL;
756 : struct revocation_reason_info *reason;
757 0 : const char *text_0 = _("No reason specified");
758 0 : const char *text_1 = _("Key has been compromised");
759 0 : const char *text_2 = _("Key is superseded");
760 0 : const char *text_3 = _("Key is no longer used");
761 0 : const char *text_4 = _("User ID is no longer valid");
762 0 : const char *code_text = NULL;
763 :
764 : do {
765 0 : code=-1;
766 0 : xfree(description);
767 0 : description = NULL;
768 :
769 0 : tty_printf(_("Please select the reason for the revocation:\n"));
770 0 : tty_printf( " 0 = %s\n", text_0 );
771 0 : if( key_rev )
772 0 : tty_printf(" 1 = %s\n", text_1 );
773 0 : if( key_rev )
774 0 : tty_printf(" 2 = %s\n", text_2 );
775 0 : if( key_rev )
776 0 : tty_printf(" 3 = %s\n", text_3 );
777 0 : if( cert_rev )
778 0 : tty_printf(" 4 = %s\n", text_4 );
779 0 : tty_printf( " Q = %s\n", _("Cancel") );
780 0 : if( hint )
781 0 : tty_printf(_("(Probably you want to select %d here)\n"), hint );
782 :
783 0 : while(code==-1) {
784 : int n;
785 0 : char *answer = cpr_get("ask_revocation_reason.code",
786 0 : _("Your decision? "));
787 0 : trim_spaces( answer );
788 0 : cpr_kill_prompt();
789 0 : if( *answer == 'q' || *answer == 'Q')
790 0 : return NULL; /* cancel */
791 0 : if( hint && !*answer )
792 0 : n = hint;
793 0 : else if(!digitp( answer ) )
794 0 : n = -1;
795 : else
796 0 : n = atoi(answer);
797 0 : xfree(answer);
798 0 : if( n == 0 ) {
799 0 : code = 0x00; /* no particular reason */
800 0 : code_text = text_0;
801 : }
802 0 : else if( key_rev && n == 1 ) {
803 0 : code = 0x02; /* key has been compromised */
804 0 : code_text = text_1;
805 : }
806 0 : else if( key_rev && n == 2 ) {
807 0 : code = 0x01; /* key is superseded */
808 0 : code_text = text_2;
809 : }
810 0 : else if( key_rev && n == 3 ) {
811 0 : code = 0x03; /* key is no longer used */
812 0 : code_text = text_3;
813 : }
814 0 : else if( cert_rev && n == 4 ) {
815 0 : code = 0x20; /* uid is no longer valid */
816 0 : code_text = text_4;
817 : }
818 : else
819 0 : tty_printf(_("Invalid selection.\n"));
820 : }
821 :
822 0 : tty_printf(_("Enter an optional description; "
823 : "end it with an empty line:\n") );
824 : for(;;) {
825 0 : char *answer = cpr_get("ask_revocation_reason.text", "> " );
826 0 : trim_trailing_ws( answer, strlen(answer) );
827 0 : cpr_kill_prompt();
828 0 : if( !*answer ) {
829 0 : xfree(answer);
830 0 : break;
831 : }
832 :
833 : {
834 0 : char *p = make_printable_string( answer, strlen(answer), 0 );
835 0 : xfree(answer);
836 0 : answer = p;
837 : }
838 :
839 0 : if( !description )
840 0 : description = xstrdup(answer);
841 : else {
842 0 : char *p = xmalloc( strlen(description) + strlen(answer) + 2 );
843 0 : strcpy(stpcpy(stpcpy( p, description),"\n"),answer);
844 0 : xfree(description);
845 0 : description = p;
846 : }
847 0 : xfree(answer);
848 0 : }
849 :
850 0 : tty_printf(_("Reason for revocation: %s\n"), code_text );
851 0 : if( !description )
852 0 : tty_printf(_("(No description given)\n") );
853 : else
854 0 : tty_printf("%s\n", description );
855 :
856 0 : } while( !cpr_get_answer_is_yes("ask_revocation_reason.okay",
857 0 : _("Is this okay? (y/N) ")) );
858 :
859 0 : reason = xmalloc( sizeof *reason );
860 0 : reason->code = code;
861 0 : reason->desc = description;
862 0 : return reason;
863 : }
864 :
865 : struct revocation_reason_info *
866 1 : get_default_uid_revocation_reason(void)
867 : {
868 : struct revocation_reason_info *reason;
869 1 : reason = xmalloc( sizeof *reason );
870 1 : reason->code = 0x20; /* uid is no longer valid */
871 1 : reason->desc = strdup(""); /* no text */
872 1 : return reason;
873 : }
874 :
875 : void
876 1 : release_revocation_reason_info( struct revocation_reason_info *reason )
877 : {
878 1 : if( reason ) {
879 1 : xfree( reason->desc );
880 1 : xfree( reason );
881 : }
882 1 : }
|