gpg: Implement --keyid-format=none.
[gnupg.git] / g10 / revoke.c
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 <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 <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 revocation_reason_build_cb( PKT_signature *sig, void *opaque )
48 {
49     struct revocation_reason_info *reason = opaque;
50     char *ud = NULL;
51     byte *buffer;
52     size_t buflen = 1;
53
54     if(!reason)
55       return 0;
56
57     if( reason->desc ) {
58         ud = native_to_utf8( reason->desc );
59         buflen += strlen(ud);
60     }
61     buffer = xmalloc( buflen );
62     *buffer = reason->code;
63     if( ud ) {
64         memcpy(buffer+1, ud, strlen(ud) );
65         xfree( ud );
66     }
67
68     build_sig_subpkt( sig, SIGSUBPKT_REVOC_REASON, buffer, buflen );
69     xfree( buffer );
70     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 export_minimal_pk(IOBUF out,KBNODE keyblock,
79                   PKT_signature *revsig,PKT_signature *revkey)
80 {
81   KBNODE node;
82   PACKET pkt;
83   PKT_user_id *uid=NULL;
84   PKT_signature *selfsig=NULL;
85   u32 keyid[2];
86   int rc;
87
88   node=find_kbnode(keyblock,PKT_PUBLIC_KEY);
89   if(!node)
90     {
91       log_error("key incomplete\n");
92       return GPG_ERR_GENERAL;
93     }
94
95   keyid_from_pk(node->pkt->pkt.public_key,keyid);
96
97   pkt=*node->pkt;
98   rc=build_packet(out,&pkt);
99   if(rc)
100     {
101       log_error(_("build_packet failed: %s\n"), gpg_strerror (rc) );
102       return rc;
103     }
104
105   init_packet(&pkt);
106   pkt.pkttype=PKT_SIGNATURE;
107
108   /* the revocation itself, if any.  2440 likes this to come first. */
109   if(revsig)
110     {
111       pkt.pkt.signature=revsig;
112       rc=build_packet(out,&pkt);
113       if(rc)
114         {
115           log_error("build_packet failed: %s\n", gpg_strerror (rc) );
116           return rc;
117         }
118     }
119
120   /* If a revkey in a 1F sig is present, include it too */
121   if(revkey)
122     {
123       pkt.pkt.signature=revkey;
124       rc=build_packet(out,&pkt);
125       if(rc)
126         {
127           log_error(_("build_packet failed: %s\n"), gpg_strerror (rc) );
128           return rc;
129         }
130     }
131
132   while(!selfsig)
133     {
134       KBNODE signode;
135
136       node=find_next_kbnode(node,PKT_USER_ID);
137       if(!node)
138         {
139           /* We're out of user IDs - none were self-signed. */
140           if(uid)
141             break;
142           else
143             {
144               log_error(_("key %s has no user IDs\n"),keystr(keyid));
145               return GPG_ERR_GENERAL;
146             }
147         }
148
149       if(node->pkt->pkt.user_id->attrib_data)
150         continue;
151
152       uid=node->pkt->pkt.user_id;
153       signode=node;
154
155       while((signode=find_next_kbnode(signode,PKT_SIGNATURE)))
156         {
157           if(keyid[0]==signode->pkt->pkt.signature->keyid[0] &&
158              keyid[1]==signode->pkt->pkt.signature->keyid[1] &&
159              IS_UID_SIG(signode->pkt->pkt.signature))
160             {
161               selfsig=signode->pkt->pkt.signature;
162               break;
163             }
164         }
165     }
166
167   pkt.pkttype=PKT_USER_ID;
168   pkt.pkt.user_id=uid;
169
170   rc=build_packet(out,&pkt);
171   if(rc)
172     {
173       log_error(_("build_packet failed: %s\n"), gpg_strerror (rc) );
174       return rc;
175     }
176
177   if(selfsig)
178     {
179       pkt.pkttype=PKT_SIGNATURE;
180       pkt.pkt.signature=selfsig;
181
182       rc=build_packet(out,&pkt);
183       if(rc)
184         {
185           log_error(_("build_packet failed: %s\n"), gpg_strerror (rc) );
186           return rc;
187         }
188     }
189
190   return 0;
191 }
192
193 /****************
194  * Generate a revocation certificate for UNAME via a designated revoker
195  */
196 int
197 gen_desig_revoke (ctrl_t ctrl, const char *uname, strlist_t locusr)
198 {
199     int rc = 0;
200     armor_filter_context_t *afx;
201     PKT_public_key *pk = NULL;
202     PKT_public_key *pk2 = NULL;
203     PKT_signature *sig = NULL;
204     IOBUF out = NULL;
205     struct revocation_reason_info *reason = NULL;
206     KEYDB_HANDLE kdbhd;
207     KEYDB_SEARCH_DESC desc;
208     KBNODE keyblock=NULL,node;
209     u32 keyid[2];
210     int i,any=0;
211     SK_LIST sk_list=NULL;
212
213     if( opt.batch )
214       {
215         log_error(_("can't do this in batch mode\n"));
216         return GPG_ERR_GENERAL;
217       }
218
219     afx = new_armor_context ();
220
221     kdbhd = keydb_new ();
222     if (!kdbhd)
223       {
224         rc = gpg_error_from_syserror ();
225         goto leave;
226       }
227     rc = classify_user_id (uname, &desc, 1);
228     if (!rc)
229       rc = keydb_search (kdbhd, &desc, 1, NULL);
230     if (rc) {
231         log_error (_("key \"%s\" not found: %s\n"),uname, gpg_strerror (rc));
232         goto leave;
233     }
234
235     rc = keydb_get_keyblock (kdbhd, &keyblock );
236     if( rc ) {
237         log_error (_("error reading keyblock: %s\n"), gpg_strerror (rc) );
238         goto leave;
239     }
240
241     /* To parse the revkeys */
242     merge_keys_and_selfsig(keyblock);
243
244     /* get the key from the keyblock */
245     node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
246     if( !node )
247       BUG ();
248
249     pk=node->pkt->pkt.public_key;
250
251     keyid_from_pk(pk,keyid);
252
253     if(locusr)
254       {
255         rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_CERT);
256         if(rc)
257           goto leave;
258       }
259
260     /* Are we a designated revoker for this key? */
261
262     if(!pk->revkey && pk->numrevkeys)
263       BUG();
264
265     for(i=0;i<pk->numrevkeys;i++)
266       {
267         SK_LIST list;
268
269         free_public_key (pk2);
270         pk2 = NULL;
271
272         if(sk_list)
273           {
274             for(list=sk_list;list;list=list->next)
275               {
276                 byte fpr[MAX_FINGERPRINT_LEN];
277                 size_t fprlen;
278
279                 fingerprint_from_pk (list->pk, fpr, &fprlen);
280
281                 /* Don't get involved with keys that don't have 160
282                    bit fingerprints */
283                 if(fprlen!=20)
284                   continue;
285
286                 if(memcmp(fpr,pk->revkey[i].fpr,20)==0)
287                   break;
288               }
289
290             if (list)
291               pk2 = copy_public_key (NULL, list->pk);
292             else
293               continue;
294           }
295         else
296           {
297             pk2 = xmalloc_clear (sizeof *pk2);
298             rc = get_pubkey_byfprint (pk2, NULL,
299                                       pk->revkey[i].fpr, MAX_FINGERPRINT_LEN);
300           }
301
302         /* We have the revocation key.  */
303         if(!rc)
304           {
305             PKT_signature *revkey = NULL;
306
307             any = 1;
308
309             print_pubkey_info (NULL, pk);
310             tty_printf ("\n");
311
312             tty_printf (_("To be revoked by:\n"));
313             print_seckey_info (pk2);
314
315             if(pk->revkey[i].class&0x40)
316               tty_printf(_("(This is a sensitive revocation key)\n"));
317             tty_printf("\n");
318
319             rc = agent_probe_secret_key (ctrl, pk2);
320             if (rc)
321               {
322                 tty_printf (_("Secret key is not available.\n"));
323                 continue;
324               }
325
326             if( !cpr_get_answer_is_yes("gen_desig_revoke.okay",
327          _("Create a designated revocation certificate for this key? (y/N) ")))
328               continue;
329
330             /* get the reason for the revocation (this is always v4) */
331             reason = ask_revocation_reason( 1, 0, 1 );
332             if( !reason )
333               continue;
334
335             if( !opt.armor )
336               tty_printf(_("ASCII armored output forced.\n"));
337
338             if( (rc = open_outfile (-1, NULL, 0, 1, &out )) )
339               goto leave;
340
341             afx->what = 1;
342             afx->hdrlines = "Comment: A designated revocation certificate"
343               " should follow\n";
344             push_armor_filter (afx, out);
345
346             /* create it */
347             rc = make_keysig_packet( &sig, pk, NULL, NULL, pk2, 0x20, 0,
348                                      0, 0,
349                                      revocation_reason_build_cb, reason,
350                                      NULL);
351             if( rc ) {
352               log_error(_("make_keysig_packet failed: %s\n"), gpg_strerror (rc));
353               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             while(!revkey)
375               {
376                 KBNODE signode;
377
378                 signode=find_next_kbnode(node,PKT_SIGNATURE);
379                 if(!signode)
380                   break;
381
382                 node=signode;
383
384                 if(keyid[0]==signode->pkt->pkt.signature->keyid[0] &&
385                    keyid[1]==signode->pkt->pkt.signature->keyid[1] &&
386                    IS_KEY_SIG(signode->pkt->pkt.signature))
387                   {
388                     int j;
389
390                     for(j=0;j<signode->pkt->pkt.signature->numrevkeys;j++)
391                       {
392                         if(pk->revkey[i].class==
393                            signode->pkt->pkt.signature->revkey[j].class &&
394                            pk->revkey[i].algid==
395                            signode->pkt->pkt.signature->revkey[j].algid &&
396                            memcmp(pk->revkey[i].fpr,
397                                   signode->pkt->pkt.signature->revkey[j].fpr,
398                                   MAX_FINGERPRINT_LEN)==0)
399                           {
400                             revkey=signode->pkt->pkt.signature;
401                             break;
402                           }
403                       }
404                   }
405               }
406
407             if(!revkey)
408               BUG();
409
410             rc=export_minimal_pk(out,keyblock,sig,revkey);
411             if(rc)
412               goto leave;
413
414             /* and issue a usage notice */
415             tty_printf(_("Revocation certificate created.\n"));
416             break;
417           }
418       }
419
420     if(!any)
421       log_error(_("no revocation keys found for \"%s\"\n"),uname);
422
423   leave:
424     free_public_key (pk);
425     free_public_key (pk2);
426     if( sig )
427         free_seckey_enc( sig );
428
429     release_sk_list(sk_list);
430
431     if( rc )
432         iobuf_cancel(out);
433     else
434         iobuf_close(out);
435     release_revocation_reason_info( reason );
436     release_armor_context (afx);
437     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 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   iobuf_t out = NULL;
458   armor_filter_context_t *afx;
459   PKT_signature *sig = NULL;
460   PACKET pkt;
461
462   afx = new_armor_context ();
463
464   if ((rc = open_outfile (-1, filename, suffix, 1, &out)))
465     goto leave;
466
467   if (leadintext )
468     iobuf_writestr (out, leadintext);
469
470   afx->what = 1;
471   afx->hdrlines = "Comment: This is a revocation certificate\n";
472   push_armor_filter (afx, out);
473
474   rc = make_keysig_packet (&sig, psk, NULL, NULL, psk, 0x20, 0,
475                            0, 0,
476                            revocation_reason_build_cb, reason, cache_nonce);
477   if (rc)
478     {
479       log_error (_("make_keysig_packet failed: %s\n"), gpg_strerror (rc));
480       goto leave;
481     }
482
483   if (keyblock && (PGP6 || PGP7 || PGP8))
484     {
485       /* Use a minimal pk for PGPx mode, since PGP can't import bare
486          revocation certificates. */
487       rc = export_minimal_pk (out, keyblock, sig, NULL);
488       if (rc)
489         goto leave;
490     }
491   else
492     {
493       init_packet (&pkt);
494       pkt.pkttype = PKT_SIGNATURE;
495       pkt.pkt.signature = sig;
496
497       rc = build_packet (out, &pkt);
498       if (rc)
499         {
500           log_error (_("build_packet failed: %s\n"), gpg_strerror (rc));
501           goto leave;
502         }
503     }
504
505  leave:
506   if (sig)
507     free_seckey_enc (sig);
508   if (rc)
509     iobuf_cancel (out);
510   else
511     iobuf_close (out);
512   release_armor_context (afx);
513   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 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   dir = get_openpgp_revocdir (opt.homedir);
537   tmpstr = hexfingerprint (psk, NULL, 0);
538   fname = xstrconcat (dir, DIRSEP_S, tmpstr, NULL);
539   xfree (tmpstr);
540   xfree (dir);
541
542   keyid_from_pk (psk, keyid);
543
544   memfp = es_fopenmem (0, "r+");
545   if (!memfp)
546     log_fatal ("error creating memory stream\n");
547
548   orig_codeset = i18n_switchto_utf8 ();
549
550   es_fprintf (memfp, "%s\n\n",
551               _("This is a revocation certificate for the OpenPGP key:"));
552
553   print_key_line (memfp, psk, 0);
554
555   if (opt.keyid_format != KF_NONE)
556     print_fingerprint (memfp, psk, 3);
557
558   kl = opt.keyid_format == KF_NONE? 0 : keystrlen ();
559
560   tmpstr = get_user_id (keyid, &len);
561   es_fprintf (memfp, "uid%*s%.*s\n\n",
562               kl + 10, "",
563               (int)len, tmpstr);
564   xfree (tmpstr);
565
566   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   es_putc (0, memfp);
580
581   i18n_switchback (orig_codeset);
582
583   if (es_fclose_snatch (memfp, &leadin, NULL))
584     log_fatal ("error snatching memory stream\n");
585
586   reason.code = 0x00; /* No particular reason.  */
587   reason.desc = NULL;
588   rc = create_revocation (fname, &reason, psk, NULL, leadin, 3, cache_nonce);
589   if (!rc && !opt.quiet)
590     log_info (_("revocation certificate stored as '%s.rev'\n"), fname);
591
592   xfree (leadin);
593   xfree (fname);
594
595   return rc;
596 }
597
598
599
600 /****************
601  * Generate a revocation certificate for UNAME
602  */
603 int
604 gen_revoke (const char *uname)
605 {
606   int rc = 0;
607   PKT_public_key *psk;
608   u32 keyid[2];
609   kbnode_t keyblock = NULL;
610   kbnode_t node;
611   KEYDB_HANDLE kdbhd;
612   struct revocation_reason_info *reason = NULL;
613   KEYDB_SEARCH_DESC desc;
614
615   if( opt.batch )
616     {
617       log_error(_("can't do this in batch mode\n"));
618       return GPG_ERR_GENERAL;
619     }
620
621   /* Search the userid; we don't want the whole getkey stuff here.  */
622   kdbhd = keydb_new ();
623   if (!kdbhd)
624     {
625       rc = gpg_error_from_syserror ();
626       goto leave;
627     }
628   rc = classify_user_id (uname, &desc, 1);
629   if (!rc)
630     rc = keydb_search (kdbhd, &desc, 1, NULL);
631   if (rc)
632     {
633       if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
634         log_error (_("secret key \"%s\" not found\n"), uname);
635       else
636         log_error (_("secret key \"%s\" not found: %s\n"),
637                    uname, gpg_strerror (rc));
638       goto leave;
639     }
640
641   rc = keydb_get_keyblock (kdbhd, &keyblock );
642   if (rc)
643     {
644       log_error (_("error reading keyblock: %s\n"), gpg_strerror (rc) );
645       goto leave;
646     }
647
648   rc = keydb_search (kdbhd, &desc, 1, NULL);
649   if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
650     /* Not ambiguous.  */
651     {
652     }
653   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       log_error (_("'%s' matches multiple secret keys:\n"), uname);
662
663       info = format_seckey_info (keyblock->pkt->pkt.public_key);
664       log_error ("  %s\n", info);
665       xfree (info);
666       release_kbnode (keyblock);
667
668       rc = keydb_get_keyblock (kdbhd, &keyblock);
669       while (! rc)
670         {
671           info = format_seckey_info (keyblock->pkt->pkt.public_key);
672           log_info ("  %s\n", info);
673           xfree (info);
674           release_kbnode (keyblock);
675           keyblock = NULL;
676
677           rc = keydb_search (kdbhd, &desc, 1, NULL);
678           if (! rc)
679             rc = keydb_get_keyblock (kdbhd, &keyblock);
680         }
681
682       rc = GPG_ERR_AMBIGUOUS_NAME;
683
684       goto leave;
685     }
686   else
687     {
688       log_error (_("error searching the keyring: %s\n"), gpg_strerror (rc));
689       goto leave;
690     }
691
692   /* Get the keyid from the keyblock.  */
693   node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
694   if (!node)
695     BUG ();
696
697   psk = node->pkt->pkt.public_key;
698   rc = agent_probe_secret_key (NULL, psk);
699   if (rc)
700     {
701       log_error (_("secret key \"%s\" not found: %s\n"),
702                  uname, gpg_strerror (rc));
703       goto leave;
704     }
705
706   keyid_from_pk (psk, keyid );
707   print_seckey_info (psk);
708
709   tty_printf("\n");
710   if (!cpr_get_answer_is_yes ("gen_revoke.okay",
711                 _("Create a revocation certificate for this key? (y/N) ")))
712     {
713       rc = 0;
714       goto leave;
715     }
716
717   /* Get the reason for the revocation.  */
718   reason = ask_revocation_reason (1, 0, 1);
719   if (!reason)
720     {
721       /* User decided to cancel.  */
722       rc = 0;
723       goto leave;
724     }
725
726   if (!opt.armor)
727     tty_printf (_("ASCII armored output forced.\n"));
728
729   rc = create_revocation (NULL, reason, psk, keyblock, NULL, 0, NULL);
730   if (rc)
731     goto leave;
732
733   /* and issue a usage notice */
734   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   release_kbnode (keyblock);
744   keydb_release (kdbhd);
745   release_revocation_reason_info( reason );
746   return rc;
747 }
748
749
750
751 struct revocation_reason_info *
752 ask_revocation_reason( int key_rev, int cert_rev, int hint )
753 {
754     int code=-1;
755     char *description = NULL;
756     struct revocation_reason_info *reason;
757     const char *text_0 = _("No reason specified");
758     const char *text_1 = _("Key has been compromised");
759     const char *text_2 = _("Key is superseded");
760     const char *text_3 = _("Key is no longer used");
761     const char *text_4 = _("User ID is no longer valid");
762     const char *code_text = NULL;
763
764     do {
765         code=-1;
766         xfree(description);
767         description = NULL;
768
769         tty_printf(_("Please select the reason for the revocation:\n"));
770         tty_printf(    "  0 = %s\n", text_0 );
771         if( key_rev )
772             tty_printf("  1 = %s\n", text_1 );
773         if( key_rev )
774             tty_printf("  2 = %s\n", text_2 );
775         if( key_rev )
776             tty_printf("  3 = %s\n", text_3 );
777         if( cert_rev )
778             tty_printf("  4 = %s\n", text_4 );
779         tty_printf(    "  Q = %s\n", _("Cancel") );
780         if( hint )
781             tty_printf(_("(Probably you want to select %d here)\n"), hint );
782
783         while(code==-1) {
784             int n;
785             char *answer = cpr_get("ask_revocation_reason.code",
786                                                 _("Your decision? "));
787             trim_spaces( answer );
788             cpr_kill_prompt();
789             if( *answer == 'q' || *answer == 'Q')
790               return NULL; /* cancel */
791             if( hint && !*answer )
792                 n = hint;
793             else if(!digitp( answer ) )
794                 n = -1;
795             else
796                 n = atoi(answer);
797             xfree(answer);
798             if( n == 0 ) {
799                 code = 0x00; /* no particular reason */
800                 code_text = text_0;
801             }
802             else if( key_rev && n == 1 ) {
803                 code = 0x02; /* key has been compromised */
804                 code_text = text_1;
805             }
806             else if( key_rev && n == 2 ) {
807                 code = 0x01; /* key is superseded */
808                 code_text = text_2;
809             }
810             else if( key_rev && n == 3 ) {
811                 code = 0x03; /* key is no longer used */
812                 code_text = text_3;
813             }
814             else if( cert_rev && n == 4 ) {
815                 code = 0x20; /* uid is no longer valid */
816                 code_text = text_4;
817             }
818             else
819                 tty_printf(_("Invalid selection.\n"));
820         }
821
822         tty_printf(_("Enter an optional description; "
823                      "end it with an empty line:\n") );
824         for(;;) {
825             char *answer = cpr_get("ask_revocation_reason.text", "> " );
826             trim_trailing_ws( answer, strlen(answer) );
827             cpr_kill_prompt();
828             if( !*answer ) {
829                 xfree(answer);
830                 break;
831             }
832
833             {
834                 char *p = make_printable_string( answer, strlen(answer), 0 );
835                 xfree(answer);
836                 answer = p;
837             }
838
839             if( !description )
840                 description = xstrdup(answer);
841             else {
842                 char *p = xmalloc( strlen(description) + strlen(answer) + 2 );
843                 strcpy(stpcpy(stpcpy( p, description),"\n"),answer);
844                 xfree(description);
845                 description = p;
846             }
847             xfree(answer);
848         }
849
850         tty_printf(_("Reason for revocation: %s\n"), code_text );
851         if( !description )
852             tty_printf(_("(No description given)\n") );
853         else
854             tty_printf("%s\n", description );
855
856     } while( !cpr_get_answer_is_yes("ask_revocation_reason.okay",
857                                             _("Is this okay? (y/N) "))  );
858
859     reason = xmalloc( sizeof *reason );
860     reason->code = code;
861     reason->desc = description;
862     return reason;
863 }
864
865 void
866 release_revocation_reason_info( struct revocation_reason_info *reason )
867 {
868     if( reason ) {
869         xfree( reason->desc );
870         xfree( reason );
871     }
872 }