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