~ubuntu-branches/ubuntu/precise/gnupg2/precise-proposed

« back to all changes in this revision

Viewing changes to g10/revoke.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Mueller
  • Date: 2005-03-29 10:30:32 UTC
  • Revision ID: james.westby@ubuntu.com-20050329103032-sj42n2ain3ipx310
Tags: upstream-1.9.15
ImportĀ upstreamĀ versionĀ 1.9.15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* revoke.c
 
2
 * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
 
3
 *
 
4
 * This file is part of GnuPG.
 
5
 *
 
6
 * GnuPG is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License as published by
 
8
 * the Free Software Foundation; either version 2 of the License, or
 
9
 * (at your option) any later version.
 
10
 *
 
11
 * GnuPG is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 * GNU General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License
 
17
 * along with this program; if not, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 
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 "options.h"
 
30
#include "packet.h"
 
31
#include "errors.h"
 
32
#include "keydb.h"
 
33
#include "memory.h"
 
34
#include "util.h"
 
35
#include "main.h"
 
36
#include "ttyio.h"
 
37
#include "status.h"
 
38
#include "i18n.h"
 
39
 
 
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_t 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 %08lX incomplete\n"),(ulong)keyid[1]);
 
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( const char *uname )
 
199
{
 
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_t 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
 
 
213
    if( opt.batch ) {
 
214
        log_error(_("sorry, can't do this in batch mode\n"));
 
215
        return GPG_ERR_GENERAL;
 
216
    }
 
217
 
 
218
    memset( &afx, 0, sizeof afx);
 
219
 
 
220
    kdbhd = keydb_new (0);
 
221
    classify_user_id (uname, &desc);
 
222
    rc = desc.mode? keydb_search (kdbhd, &desc, 1) : GPG_ERR_INV_USER_ID;
 
223
    if (rc) {
 
224
        log_error (_("key `%s' not found: %s\n"),uname, gpg_strerror (rc));
 
225
        goto leave;
 
226
    }
 
227
 
 
228
    rc = keydb_get_keyblock (kdbhd, &keyblock );
 
229
    if( rc ) {
 
230
        log_error (_("error reading keyblock: %s\n"), gpg_strerror (rc) );
 
231
        goto leave;
 
232
    }
 
233
 
 
234
    /* To parse the revkeys */
 
235
    merge_keys_and_selfsig(keyblock);
 
236
 
 
237
    /* get the key from the keyblock */
 
238
    node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
 
239
    if( !node ) 
 
240
      BUG ();
 
241
 
 
242
    pk=node->pkt->pkt.public_key;
 
243
 
 
244
    keyid_from_pk(pk,keyid);
 
245
 
 
246
    /* Are we a designated revoker for this key? */
 
247
 
 
248
    if(!pk->revkey && pk->numrevkeys)
 
249
      BUG();
 
250
 
 
251
    for(i=0;i<pk->numrevkeys;i++)
 
252
      {
 
253
        if(sk)
 
254
          free_secret_key(sk);
 
255
 
 
256
        sk=xcalloc (1,sizeof(*sk));
 
257
 
 
258
        rc=get_seckey_byfprint(sk,pk->revkey[i].fpr,MAX_FINGERPRINT_LEN);
 
259
 
 
260
        /* We have the revocation key */
 
261
        if(!rc)
 
262
          {
 
263
            PKT_signature *revkey = NULL;
 
264
 
 
265
            any = 1;
 
266
 
 
267
            print_pubkey_info (NULL, pk);
 
268
            tty_printf ("\n");
 
269
 
 
270
            tty_printf (_("To be revoked by:\n"));
 
271
            print_seckey_info (sk);
 
272
 
 
273
            if(pk->revkey[i].class&0x40)
 
274
              tty_printf(_("(This is a sensitive revocation key)\n"));
 
275
            tty_printf("\n");
 
276
 
 
277
            if( !cpr_get_answer_is_yes("gen_desig_revoke.okay",
 
278
                       _("Create a revocation certificate for this key? ")) )
 
279
              continue;
 
280
 
 
281
            /* get the reason for the revocation (this is always v4) */
 
282
            reason = ask_revocation_reason( 1, 0, 1 );
 
283
            if( !reason )
 
284
              continue;
 
285
 
 
286
            rc = check_secret_key( sk, 0 );
 
287
            if( rc )
 
288
              continue;
 
289
 
 
290
            if( !opt.armor )
 
291
              tty_printf(_("ASCII armored output forced.\n"));
 
292
 
 
293
            if( (rc = open_outfile( NULL, 0, &out )) )
 
294
              goto leave;
 
295
 
 
296
            afx.what = 1;
 
297
            afx.hdrlines = "Comment: A revocation certificate should follow\n";
 
298
            iobuf_push_filter( out, armor_filter, &afx );
 
299
 
 
300
            /* create it */
 
301
            rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x20, 0,
 
302
                                     0, 0, 0,
 
303
                                     revocation_reason_build_cb, reason );
 
304
            if( rc ) {
 
305
              log_error(_("make_keysig_packet failed: %s\n"), gpg_strerror (rc));
 
306
              goto leave;
 
307
            }
 
308
 
 
309
            /* Spit out a minimal pk as well, since otherwise there is
 
310
               no way to know which key to attach this revocation to.
 
311
               Also include the direct key signature that contains
 
312
               this revocation key.  We're allowed to include
 
313
               sensitive revocation keys along with a revocation, as
 
314
               this may be the only time the recipient has seen it.
 
315
               Note that this means that if we have multiple different
 
316
               sensitive revocation keys in a given direct key
 
317
               signature, we're going to include them all here.  This
 
318
               is annoying, but the good outweighs the bad, since
 
319
               without including this a sensitive revoker can't really
 
320
               do their job.  People should not include multiple
 
321
               sensitive revocation keys in one signature: 2440 says
 
322
               "Note that it may be appropriate to isolate this
 
323
               subpacket within a separate signature so that it is not
 
324
               combined with other subpackets that need to be
 
325
               exported." -dms */
 
326
 
 
327
            while(!revkey)
 
328
              {
 
329
                KBNODE signode;
 
330
 
 
331
                signode=find_next_kbnode(node,PKT_SIGNATURE);
 
332
                if(!signode)
 
333
                  break;
 
334
 
 
335
                node=signode;
 
336
 
 
337
                if(keyid[0]==signode->pkt->pkt.signature->keyid[0] &&
 
338
                   keyid[1]==signode->pkt->pkt.signature->keyid[1] &&
 
339
                   IS_KEY_SIG(signode->pkt->pkt.signature))
 
340
                  {
 
341
                    int j;
 
342
 
 
343
                    for(j=0;j<signode->pkt->pkt.signature->numrevkeys;j++)
 
344
                      {
 
345
                        if(pk->revkey[i].class==
 
346
                           signode->pkt->pkt.signature->revkey[j]->class &&
 
347
                           pk->revkey[i].algid==
 
348
                           signode->pkt->pkt.signature->revkey[j]->algid &&
 
349
                           memcmp(pk->revkey[i].fpr,
 
350
                                  signode->pkt->pkt.signature->revkey[j]->fpr,
 
351
                                  MAX_FINGERPRINT_LEN)==0)
 
352
                          {
 
353
                            revkey=signode->pkt->pkt.signature;
 
354
                            break;
 
355
                          }
 
356
                      }
 
357
                  }
 
358
              }
 
359
 
 
360
            if(!revkey)
 
361
              BUG();
 
362
 
 
363
            rc=export_minimal_pk(out,keyblock,sig,revkey);
 
364
            if(rc)
 
365
              goto leave;
 
366
 
 
367
            /* and issue a usage notice */
 
368
            tty_printf(_("Revocation certificate created.\n"));
 
369
            break;
 
370
          }
 
371
      }
 
372
 
 
373
    if(!any)
 
374
      log_error(_("no revocation keys found for `%s'\n"),uname);
 
375
 
 
376
  leave:
 
377
    if( pk )
 
378
        free_public_key( pk );
 
379
    if( sk )
 
380
        free_secret_key( sk );
 
381
    if( sig )
 
382
        free_seckey_enc( sig );
 
383
 
 
384
    if( rc )
 
385
        iobuf_cancel(out);
 
386
    else
 
387
        iobuf_close(out);
 
388
    release_revocation_reason_info( reason );
 
389
    return rc;
 
390
}
 
391
 
 
392
 
 
393
/****************
 
394
 * Generate a revocation certificate for UNAME
 
395
 */
 
396
int
 
397
gen_revoke( const char *uname )
 
398
{
 
399
    int rc = 0;
 
400
    armor_filter_context_t afx;
 
401
    PACKET pkt;
 
402
    PKT_secret_key *sk; /* used as pointer into a kbnode */
 
403
    PKT_public_key *pk = NULL;
 
404
    PKT_signature *sig = NULL;
 
405
    u32 sk_keyid[2];
 
406
    iobuf_t out = NULL;
 
407
    KBNODE keyblock = NULL, pub_keyblock = NULL;
 
408
    KBNODE node;
 
409
    KEYDB_HANDLE kdbhd;
 
410
    struct revocation_reason_info *reason = NULL;
 
411
    KEYDB_SEARCH_DESC desc;
 
412
 
 
413
    if( opt.batch ) {
 
414
        log_error(_("sorry, can't do this in batch mode\n"));
 
415
        return GPG_ERR_GENERAL;
 
416
    }
 
417
 
 
418
    memset( &afx, 0, sizeof afx);
 
419
    init_packet( &pkt );
 
420
 
 
421
    /* search the userid: 
 
422
     * We don't want the whole getkey stuff here but the entire keyblock
 
423
     */
 
424
    kdbhd = keydb_new (1);
 
425
    classify_user_id (uname, &desc);
 
426
    rc = desc.mode? keydb_search (kdbhd, &desc, 1) : GPG_ERR_INV_USER_ID;
 
427
    if (rc) {
 
428
        log_error (_("secret key `%s' not found: %s\n"),
 
429
                   uname, gpg_strerror (rc));
 
430
        goto leave;
 
431
    }
 
432
 
 
433
    rc = keydb_get_keyblock (kdbhd, &keyblock );
 
434
    if( rc ) {
 
435
        log_error (_("error reading keyblock: %s\n"), gpg_strerror (rc) );
 
436
        goto leave;
 
437
    }
 
438
 
 
439
    /* get the keyid from the keyblock */
 
440
    node = find_kbnode( keyblock, PKT_SECRET_KEY );
 
441
    if( !node ) 
 
442
        BUG ();
 
443
 
 
444
    /* fixme: should make a function out of this stuff,
 
445
     * it's used all over the source */
 
446
    sk = node->pkt->pkt.secret_key;
 
447
    keyid_from_sk( sk, sk_keyid );
 
448
    print_seckey_info (sk);
 
449
 
 
450
    pk = xcalloc (1, sizeof *pk );
 
451
 
 
452
    /* FIXME: We should get the public key direct from the secret one */
 
453
 
 
454
    pub_keyblock=get_pubkeyblock(sk_keyid);
 
455
    if(!pub_keyblock)
 
456
      {
 
457
        log_error(_("no corresponding public key: %s\n"), gpg_strerror (rc) );
 
458
        goto leave;
 
459
      }
 
460
 
 
461
    node=find_kbnode(pub_keyblock,PKT_PUBLIC_KEY);
 
462
    if(!node)
 
463
      BUG();
 
464
 
 
465
    pk=node->pkt->pkt.public_key;
 
466
 
 
467
    if( cmp_public_secret_key( pk, sk ) ) {
 
468
        log_error(_("public key does not match secret key!\n") );
 
469
        rc = GPG_ERR_GENERAL;
 
470
        goto leave;
 
471
    }
 
472
 
 
473
    tty_printf("\n");
 
474
    if( !cpr_get_answer_is_yes("gen_revoke.okay",
 
475
                        _("Create a revocation certificate for this key? ")) ){
 
476
        rc = 0;
 
477
        goto leave;
 
478
    }
 
479
 
 
480
    if(sk->version>=4 || opt.force_v4_certs) {
 
481
      /* get the reason for the revocation */
 
482
      reason = ask_revocation_reason( 1, 0, 1 );
 
483
      if( !reason ) { /* user decided to cancel */
 
484
        rc = 0;
 
485
        goto leave;
 
486
      }
 
487
    }
 
488
 
 
489
    switch( is_secret_key_protected( sk ) ) {
 
490
      case -1:
 
491
        log_error(_("unknown protection algorithm\n"));
 
492
        rc = GPG_ERR_PUBKEY_ALGO;
 
493
        break;
 
494
      case 0:
 
495
        tty_printf(_("NOTE: This key is not protected!\n"));
 
496
        break;
 
497
      default:
 
498
        rc = check_secret_key( sk, 0 );
 
499
        break;
 
500
    }
 
501
    if( rc )
 
502
        goto leave;
 
503
 
 
504
 
 
505
    if( !opt.armor )
 
506
        tty_printf(_("ASCII armored output forced.\n"));
 
507
 
 
508
    if( (rc = open_outfile( NULL, 0, &out )) )
 
509
        goto leave;
 
510
 
 
511
    afx.what = 1;
 
512
    afx.hdrlines = "Comment: A revocation certificate should follow\n";
 
513
    iobuf_push_filter( out, armor_filter, &afx );
 
514
 
 
515
    /* create it */
 
516
    rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x20, 0,
 
517
                             opt.force_v4_certs?4:0, 0, 0,
 
518
                             revocation_reason_build_cb, reason );
 
519
    if( rc ) {
 
520
        log_error(_("make_keysig_packet failed: %s\n"), gpg_strerror (rc));
 
521
        goto leave;
 
522
    }
 
523
 
 
524
    if(PGP2 || PGP6 || PGP7 || PGP8)
 
525
      {
 
526
        /* Use a minimal pk for PGPx mode, since PGP can't import bare
 
527
           revocation certificates. */
 
528
        rc=export_minimal_pk(out,pub_keyblock,sig,NULL);
 
529
        if(rc)
 
530
          goto leave;
 
531
      }
 
532
    else
 
533
      {
 
534
        init_packet( &pkt );
 
535
        pkt.pkttype = PKT_SIGNATURE;
 
536
        pkt.pkt.signature = sig;
 
537
 
 
538
        rc = build_packet( out, &pkt );
 
539
        if( rc ) {
 
540
          log_error(_("build_packet failed: %s\n"), gpg_strerror (rc) );
 
541
          goto leave;
 
542
        }
 
543
      }
 
544
 
 
545
    /* and issue a usage notice */
 
546
    tty_printf(_("Revocation certificate created.\n\n"
 
547
"Please move it to a medium which you can hide away; if Mallory gets\n"
 
548
"access to this certificate he can use it to make your key unusable.\n"
 
549
"It is smart to print this certificate and store it away, just in case\n"
 
550
"your media become unreadable.  But have some caution:  The print system of\n"
 
551
"your machine might store the data and make it available to others!\n"));
 
552
 
 
553
  leave:
 
554
    if( sig )
 
555
        free_seckey_enc( sig );
 
556
    release_kbnode( keyblock );
 
557
    release_kbnode( pub_keyblock );
 
558
    keydb_release (kdbhd);
 
559
    if( rc )
 
560
        iobuf_cancel(out);
 
561
    else
 
562
        iobuf_close(out);
 
563
    release_revocation_reason_info( reason );
 
564
    return rc;
 
565
}
 
566
 
 
567
 
 
568
 
 
569
struct revocation_reason_info *
 
570
ask_revocation_reason( int key_rev, int cert_rev, int hint )
 
571
{
 
572
    int code=-1;
 
573
    char *description = NULL;
 
574
    struct revocation_reason_info *reason;
 
575
    const char *text_0 = _("No reason specified");
 
576
    const char *text_1 = _("Key has been compromised");
 
577
    const char *text_2 = _("Key is superseded");
 
578
    const char *text_3 = _("Key is no longer used");
 
579
    const char *text_4 = _("User ID is no longer valid");
 
580
    const char *code_text = NULL;
 
581
 
 
582
    do {
 
583
        code=-1;
 
584
        xfree (description);
 
585
        description = NULL;
 
586
 
 
587
        tty_printf(_("Please select the reason for the revocation:\n"));
 
588
        tty_printf(    "  0 = %s\n", text_0 );
 
589
        if( key_rev )
 
590
            tty_printf("  1 = %s\n", text_1 );
 
591
        if( key_rev )
 
592
            tty_printf("  2 = %s\n", text_2 );
 
593
        if( key_rev )
 
594
            tty_printf("  3 = %s\n", text_3 );
 
595
        if( cert_rev )
 
596
            tty_printf("  4 = %s\n", text_4 );
 
597
        tty_printf(    "  Q = %s\n", _("Cancel") );
 
598
        if( hint )
 
599
            tty_printf(_("(Probably you want to select %d here)\n"), hint );
 
600
 
 
601
        while(code==-1) {
 
602
            int n;
 
603
            char *answer = cpr_get("ask_revocation_reason.code",
 
604
                                                _("Your decision? "));
 
605
            trim_spaces( answer );
 
606
            cpr_kill_prompt();
 
607
            if( *answer == 'q' || *answer == 'Q')
 
608
              return NULL; /* cancel */
 
609
            if( hint && !*answer )
 
610
                n = hint;
 
611
            else if(!digitp( answer ) )
 
612
                n = -1;
 
613
            else
 
614
                n = atoi(answer);
 
615
            xfree (answer);
 
616
            if( n == 0 ) {
 
617
                code = 0x00; /* no particular reason */
 
618
                code_text = text_0;
 
619
            }
 
620
            else if( key_rev && n == 1 ) {
 
621
                code = 0x02; /* key has been compromised */
 
622
                code_text = text_1;
 
623
            }
 
624
            else if( key_rev && n == 2 ) {
 
625
                code = 0x01; /* key is superseded */
 
626
                code_text = text_2;
 
627
            }
 
628
            else if( key_rev && n == 3 ) {
 
629
                code = 0x03; /* key is no longer used */
 
630
                code_text = text_3;
 
631
            }
 
632
            else if( cert_rev && n == 4 ) {
 
633
                code = 0x20; /* uid is no longer valid */
 
634
                code_text = text_4;
 
635
            }
 
636
            else
 
637
                tty_printf(_("Invalid selection.\n"));
 
638
        }
 
639
 
 
640
        tty_printf(_("Enter an optional description; "
 
641
                     "end it with an empty line:\n") );
 
642
        for(;;) {
 
643
            char *answer = cpr_get("ask_revocation_reason.text", "> " );
 
644
            trim_trailing_ws( answer, strlen(answer) );
 
645
            cpr_kill_prompt();
 
646
            if( !*answer ) {
 
647
                xfree (answer);
 
648
                break;
 
649
            }
 
650
 
 
651
            {
 
652
                char *p = make_printable_string( answer, strlen(answer), 0 );
 
653
                xfree (answer);
 
654
                answer = p;
 
655
            }
 
656
 
 
657
            if( !description )
 
658
                description = xstrdup (answer);
 
659
            else {
 
660
                char *p = xmalloc ( strlen(description) + strlen(answer) + 2 );
 
661
                strcpy(stpcpy(stpcpy( p, description),"\n"),answer);
 
662
                xfree (description);
 
663
                description = p;
 
664
            }
 
665
            xfree (answer);
 
666
        }
 
667
 
 
668
        tty_printf(_("Reason for revocation: %s\n"), code_text );
 
669
        if( !description )
 
670
            tty_printf(_("(No description given)\n") );
 
671
        else
 
672
            tty_printf("%s\n", description );
 
673
 
 
674
    } while( !cpr_get_answer_is_yes("ask_revocation_reason.okay",
 
675
                                            _("Is this okay? "))  );
 
676
 
 
677
    reason = xmalloc ( sizeof *reason );
 
678
    reason->code = code;
 
679
    reason->desc = description;
 
680
    return reason;
 
681
}
 
682
 
 
683
void
 
684
release_revocation_reason_info( struct revocation_reason_info *reason )
 
685
{
 
686
    if( reason ) {
 
687
        xfree ( reason->desc );
 
688
        xfree ( reason );
 
689
    }
 
690
}