Coverage Report

Created: 2022-12-08 06:10

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