~ubuntu-branches/ubuntu/precise/gnupg2/precise-updates

« back to all changes in this revision

Viewing changes to agent/findkey.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Urlichs
  • Date: 2005-12-08 22:13:21 UTC
  • mto: (5.1.1 edgy) (7.1.1 squeeze) (1.1.13 upstream)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20051208221321-d54343ca8hlwzkac
Tags: upstream-1.9.19
ImportĀ upstreamĀ versionĀ 1.9.19

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* findkey.c - locate the secret key
2
 
 * Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
 
2
 * Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
3
3
 *
4
4
 * This file is part of GnuPG.
5
5
 *
39
39
};
40
40
 
41
41
 
42
 
 
 
42
/* Write an S-expression formatted key to our key storage.  With FORCE
 
43
   pased as true an existsing key with the given GRIP will get
 
44
   overwritten.  */
43
45
int
44
46
agent_write_private_key (const unsigned char *grip,
45
47
                         const void *buffer, size_t length, int force)
48
50
  char *fname;
49
51
  FILE *fp;
50
52
  char hexgrip[40+4+1];
 
53
  int fd;
51
54
  
52
55
  for (i=0; i < 20; i++)
53
56
    sprintf (hexgrip+2*i, "%02X", grip[i]);
54
57
  strcpy (hexgrip+40, ".key");
55
58
 
56
59
  fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
57
 
  if (force)
58
 
    fp = fopen (fname, "wb");
59
 
  else
 
60
 
 
61
  if (!force && !access (fname, F_OK))
60
62
    {
61
 
      int fd;
62
 
 
63
 
      if (!access (fname, F_OK))
64
 
      {
65
 
        log_error ("secret key file `%s' already exists\n", fname);
66
 
        xfree (fname);
67
 
        return gpg_error (GPG_ERR_GENERAL);
68
 
      }
69
 
 
70
 
      /* We would like to create FNAME but only if it does not already
71
 
         exist.  We cannot make this guarantee just using POSIX (GNU
72
 
         provides the "x" opentype for fopen, however, this is not
73
 
         portable).  Thus, we use the more flexible open function and
74
 
         then use fdopen to obtain a stream.
75
 
 
76
 
         The mode parameter to open is what fopen uses.  It will be
77
 
         combined with the process' umask automatically.  */
78
 
      fd = open (fname, O_CREAT | O_EXCL | O_RDWR,
79
 
                 S_IRUSR | S_IWUSR 
 
63
      log_error ("secret key file `%s' already exists\n", fname);
 
64
      xfree (fname);
 
65
      return gpg_error (GPG_ERR_GENERAL);
 
66
    }
 
67
 
 
68
  /* In FORCE mode we would like to create FNAME but only if it does
 
69
     not already exist.  We cannot make this guarantee just using
 
70
     POSIX (GNU provides the "x" opentype for fopen, however, this is
 
71
     not portable).  Thus, we use the more flexible open function and
 
72
     then use fdopen to obtain a stream. */
 
73
  fd = open (fname, force? (O_CREAT | O_TRUNC | O_WRONLY)
 
74
                         : (O_CREAT | O_EXCL | O_WRONLY),
 
75
             S_IRUSR | S_IWUSR 
80
76
#ifndef HAVE_W32_SYSTEM
81
 
                 | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH
 
77
                 | S_IRGRP 
82
78
#endif
83
79
                 );
84
 
      if (fd < 0)
85
 
        fp = 0;
86
 
      else
87
 
        {
88
 
          fp = fdopen (fd, "wb");
89
 
          if (!fp)
90
 
            { 
91
 
              int save_e = errno;
92
 
              close (fd);
93
 
              errno = save_e;
94
 
            }
95
 
        }
 
80
  if (fd < 0)
 
81
    fp = NULL;
 
82
  else
 
83
    {
 
84
      fp = fdopen (fd, "wb");
 
85
      if (!fp)
 
86
        { 
 
87
          int save_e = errno;
 
88
          close (fd);
 
89
          errno = save_e;
 
90
        }
96
91
    }
97
92
 
98
93
  if (!fp) 
140
135
}
141
136
 
142
137
 
 
138
/* Modify a Key description, replacing certain special format
 
139
   characters.  List of currently supported replacements:
 
140
 
 
141
   %% - Replaced by a single %
 
142
   %c - Replaced by the content of COMMENT.
 
143
 
 
144
   The functions returns 0 on success or an error code.  On success a
 
145
   newly allocated string is stored at the address of RESULT.
 
146
 */
 
147
static gpg_error_t
 
148
modify_description (const char *in, const char *comment, char **result)
 
149
{
 
150
  size_t comment_length;
 
151
  size_t in_len;
 
152
  size_t out_len;
 
153
  char *out;
 
154
  size_t i;
 
155
  int special, pass;
 
156
 
 
157
  comment_length = strlen (comment);
 
158
  in_len  = strlen (in);
 
159
 
 
160
  /* First pass calculates the length, second pass does the actual
 
161
     copying.  */
 
162
  out = NULL;
 
163
  out_len = 0;
 
164
  for (pass=0; pass < 2; pass++)
 
165
    {
 
166
      special = 0;
 
167
      for (i = 0; i < in_len; i++)
 
168
        {
 
169
          if (special)
 
170
            {
 
171
              special = 0;
 
172
              switch (in[i])
 
173
                {
 
174
                case '%':
 
175
                  if (out)
 
176
                    *out++ = '%';
 
177
                  else
 
178
                    out_len++;
 
179
                  break;
 
180
 
 
181
                case 'c': /* Comment.  */
 
182
                  if (out)
 
183
                    {
 
184
                      memcpy (out, comment, comment_length);
 
185
                      out += comment_length;
 
186
                    }
 
187
                  else
 
188
                    out_len += comment_length;
 
189
                  break;
 
190
 
 
191
                default: /* Invalid special sequences are kept as they are. */
 
192
                  if (out)
 
193
                    {
 
194
                      *out++ = '%';
 
195
                      *out++ = in[i];
 
196
                    }
 
197
                  else
 
198
                    out_len+=2;
 
199
                  break;
 
200
                }
 
201
            }
 
202
          else if (in[i] == '%')
 
203
            special = 1;
 
204
          else
 
205
            {
 
206
              if (out)
 
207
                *out++ = in[i];
 
208
              else
 
209
                out_len++;
 
210
            }
 
211
        }
 
212
      
 
213
      if (!pass)
 
214
        {
 
215
          *result = out = xtrymalloc (out_len + 1);
 
216
          if (!out)
 
217
            return gpg_error_from_errno (errno);
 
218
        }
 
219
    }
 
220
 
 
221
  *out = 0;
 
222
  assert (*result + out_len == out);
 
223
  return 0;
 
224
}
 
225
 
 
226
  
 
227
 
143
228
/* Unprotect the canconical encoded S-expression key in KEYBUF.  GRIP
144
229
   should be the hex encoded keygrip of that key to be used with the
145
230
   caching mechanism. DESC_TEXT may be set to override the default
146
231
   description used for the pinentry. */
147
232
static int
148
 
unprotect (CTRL ctrl, const char *desc_text,
149
 
           unsigned char **keybuf, const unsigned char *grip, int ignore_cache)
 
233
unprotect (ctrl_t ctrl, const char *desc_text,
 
234
           unsigned char **keybuf, const unsigned char *grip, 
 
235
           cache_mode_t cache_mode)
150
236
{
151
237
  struct pin_entry_info_s *pi;
152
238
  struct try_unprotect_arg_s arg;
161
247
 
162
248
  /* First try to get it from the cache - if there is none or we can't
163
249
     unprotect it, we fall back to ask the user */
164
 
  if (!ignore_cache)
 
250
  if (cache_mode != CACHE_MODE_IGNORE)
165
251
    {
166
252
      void *cache_marker;
167
 
      const char *pw = agent_get_cache (hexgrip, &cache_marker);
 
253
      const char *pw;
 
254
      
 
255
      pw = agent_get_cache (hexgrip, cache_mode, &cache_marker);
168
256
      if (pw)
169
257
        {
170
258
          rc = agent_unprotect (*keybuf, pw, &result, &resultlen);
180
268
    }
181
269
  
182
270
  pi = gcry_calloc_secure (1, sizeof (*pi) + 100);
 
271
  if (!pi)
 
272
    return gpg_error_from_errno (errno);
183
273
  pi->max_length = 100;
184
274
  pi->min_digits = 0;  /* we want a real passphrase */
185
275
  pi->max_digits = 8;
189
279
  arg.unprotected_key = NULL;
190
280
  pi->check_cb_arg = &arg;
191
281
 
192
 
  rc = agent_askpin (ctrl, desc_text, NULL, pi);
 
282
  rc = agent_askpin (ctrl, desc_text, NULL, NULL, pi);
193
283
  if (!rc)
194
284
    {
195
285
      assert (arg.unprotected_key);
196
 
      agent_put_cache (hexgrip, pi->pin, 0);
 
286
      agent_put_cache (hexgrip, cache_mode, pi->pin, 0);
197
287
      xfree (*keybuf);
198
288
      *keybuf = arg.unprotected_key;
199
289
    }
202
292
}
203
293
 
204
294
 
205
 
 
206
 
/* Return the secret key as an S-Exp in RESULT after locating it using
207
 
   the grip.  Returns NULL in RESULT if the operation should be
208
 
   diverted to a token; SHADOW_INFO will point then to an allocated
209
 
   S-Expression with the shadow_info part from the file.  With
210
 
   IGNORE_CACHE passed as true the passphrase is not taken from the
211
 
   cache.  DESC_TEXT may be set to present a custom description for the
212
 
   pinentry. */
213
 
gpg_error_t
214
 
agent_key_from_file (CTRL ctrl, const char *desc_text,
215
 
                     const unsigned char *grip, unsigned char **shadow_info,
216
 
                     int ignore_cache, gcry_sexp_t *result)
 
295
/* Read the key identified by GRIP from the private key directory and
 
296
   return it as an gcrypt S-expression object in RESULT.  On failure
 
297
   returns an error code and stores NULL at RESULT. */
 
298
static gpg_error_t
 
299
read_key_file (const unsigned char *grip, gcry_sexp_t *result)
217
300
{
218
301
  int i, rc;
219
302
  char *fname;
220
303
  FILE *fp;
221
304
  struct stat st;
222
305
  unsigned char *buf;
223
 
  size_t len, buflen, erroff;
 
306
  size_t buflen, erroff;
224
307
  gcry_sexp_t s_skey;
225
308
  char hexgrip[40+4+1];
226
 
  int got_shadow_info = 0;
227
309
  
228
310
  *result = NULL;
229
 
  if (shadow_info)
230
 
      *shadow_info = NULL;
231
311
 
232
312
  for (i=0; i < 20; i++)
233
313
    sprintf (hexgrip+2*i, "%02X", grip[i]);
253
333
    }
254
334
 
255
335
  buflen = st.st_size;
256
 
  buf = xmalloc (buflen+1);
257
 
  if (fread (buf, buflen, 1, fp) != 1)
 
336
  buf = xtrymalloc (buflen+1);
 
337
  if (!buf || fread (buf, buflen, 1, fp) != 1)
258
338
    {
259
339
      rc = gpg_error_from_errno (errno);
260
340
      log_error ("error reading `%s': %s\n", fname, strerror (errno));
264
344
      return rc;
265
345
    }
266
346
 
267
 
  rc = gcry_sexp_sscan (&s_skey, &erroff, buf, buflen);
 
347
  /* Convert the file into a gcrypt S-expression object.  */
 
348
  rc = gcry_sexp_sscan (&s_skey, &erroff, (char*)buf, buflen);
268
349
  xfree (fname);
269
350
  fclose (fp);
270
351
  xfree (buf);
274
355
                 (unsigned int)erroff, gpg_strerror (rc));
275
356
      return rc;
276
357
    }
 
358
  *result = s_skey;
 
359
  return 0;
 
360
}
 
361
 
 
362
 
 
363
/* Return the secret key as an S-Exp in RESULT after locating it using
 
364
   the grip.  Returns NULL in RESULT if the operation should be
 
365
   diverted to a token; SHADOW_INFO will point then to an allocated
 
366
   S-Expression with the shadow_info part from the file.  CACHE_MODE
 
367
   defines now the cache shall be used.  DESC_TEXT may be set to
 
368
   present a custom description for the pinentry. */
 
369
gpg_error_t
 
370
agent_key_from_file (ctrl_t ctrl, const char *desc_text,
 
371
                     const unsigned char *grip, unsigned char **shadow_info,
 
372
                     cache_mode_t cache_mode, gcry_sexp_t *result)
 
373
{
 
374
  int rc;
 
375
  unsigned char *buf;
 
376
  size_t len, buflen, erroff;
 
377
  gcry_sexp_t s_skey;
 
378
  int got_shadow_info = 0;
 
379
  
 
380
  *result = NULL;
 
381
  if (shadow_info)
 
382
      *shadow_info = NULL;
 
383
 
 
384
  rc = read_key_file (grip, &s_skey);
 
385
  if (rc)
 
386
    return rc;
 
387
 
 
388
  /* For use with the protection functions we also need the key as an
 
389
     canonical encoded S-expression in abuffer.  Create this buffer
 
390
     now.  */
277
391
  len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, NULL, 0);
278
392
  assert (len);
279
393
  buf = xtrymalloc (len);
280
394
  if (!buf)
281
395
    {
282
 
      rc = out_of_core ();
 
396
      rc = gpg_error_from_errno (errno);
283
397
      gcry_sexp_release (s_skey);
284
398
      return rc;
285
399
    }
286
400
  len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, buf, len);
287
401
  assert (len);
288
 
  gcry_sexp_release (s_skey);
 
402
 
289
403
 
290
404
  switch (agent_private_key_type (buf))
291
405
    {
292
406
    case PRIVATE_KEY_CLEAR:
293
407
      break; /* no unprotection needed */
294
408
    case PRIVATE_KEY_PROTECTED:
295
 
      rc = unprotect (ctrl, desc_text, &buf, grip, ignore_cache);
296
 
      if (rc)
297
 
        log_error ("failed to unprotect the secret key: %s\n",
298
 
                   gpg_strerror (rc));
 
409
      {
 
410
        gcry_sexp_t comment_sexp;
 
411
        size_t comment_length;
 
412
        char *desc_text_final;
 
413
        const char *comment = NULL;
 
414
 
 
415
        /* Note, that we will take the comment as a C string for
 
416
           display purposes; i.e. all stuff beyond a Nul character is
 
417
           ignored.  */
 
418
        comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0);
 
419
        if (comment_sexp)
 
420
          comment = gcry_sexp_nth_data (comment_sexp, 1, &comment_length);
 
421
        if (!comment)
 
422
          {
 
423
            comment = "";
 
424
            comment_length = 0;
 
425
          }
 
426
 
 
427
        desc_text_final = NULL;
 
428
        if (desc_text)
 
429
          {
 
430
            if (comment[comment_length])
 
431
              {
 
432
                /* Not a C-string; create one.  We might here allocate
 
433
                   more than actually displayed but well, that
 
434
                   shouldn't be a problem.  */
 
435
                char *tmp = xtrymalloc (comment_length+1);
 
436
                if (!tmp)
 
437
                  rc = gpg_error_from_errno (errno);
 
438
                else
 
439
                  {
 
440
                    memcpy (tmp, comment, comment_length);
 
441
                    tmp[comment_length] = 0;
 
442
                    rc = modify_description (desc_text, tmp, &desc_text_final);
 
443
                    xfree (tmp);
 
444
                  }
 
445
              }
 
446
            else
 
447
              rc = modify_description (desc_text, comment, &desc_text_final);
 
448
          }
 
449
 
 
450
        if (!rc)
 
451
          {
 
452
            rc = unprotect (ctrl, desc_text_final, &buf, grip, cache_mode);
 
453
            if (rc)
 
454
              log_error ("failed to unprotect the secret key: %s\n",
 
455
                         gpg_strerror (rc));
 
456
          }
 
457
        
 
458
        gcry_sexp_release (comment_sexp);
 
459
        xfree (desc_text_final);
 
460
      }
299
461
      break;
300
462
    case PRIVATE_KEY_SHADOWED:
301
463
      if (shadow_info)
329
491
      rc = gpg_error (GPG_ERR_BAD_SECKEY);
330
492
      break;
331
493
    }
 
494
  gcry_sexp_release (s_skey);
 
495
  s_skey = NULL;
332
496
  if (rc || got_shadow_info)
333
497
    {
334
498
      xfree (buf);
336
500
    }
337
501
 
338
502
  buflen = gcry_sexp_canon_len (buf, 0, NULL, NULL);
339
 
  rc = gcry_sexp_sscan (&s_skey, &erroff, buf, buflen);
 
503
  rc = gcry_sexp_sscan (&s_skey, &erroff, (char*)buf, buflen);
340
504
  wipememory (buf, buflen);
341
505
  xfree (buf);
342
506
  if (rc)
350
514
  return 0;
351
515
}
352
516
 
 
517
 
 
518
 
 
519
/* Return the public key for the keygrip GRIP.  The result is stored
 
520
   at RESULT.  This function extracts the public key from the private
 
521
   key database.  On failure an error code is returned and NULL stored
 
522
   at RESULT. */
 
523
gpg_error_t
 
524
agent_public_key_from_file (ctrl_t ctrl, 
 
525
                            const unsigned char *grip,
 
526
                            gcry_sexp_t *result)
 
527
{
 
528
  int i, idx, rc;
 
529
  gcry_sexp_t s_skey;
 
530
  const char *algoname;
 
531
  gcry_sexp_t uri_sexp, comment_sexp;
 
532
  const char *uri, *comment;
 
533
  size_t uri_length, comment_length;
 
534
  char *format, *p;
 
535
  void *args[4+2+2+1]; /* Size is max. # of elements + 2 for uri + 2
 
536
                           for comment + end-of-list.  */
 
537
  int argidx;
 
538
  gcry_sexp_t list, l2;
 
539
  const char *name;
 
540
  const char *s;
 
541
  size_t n;
 
542
  const char *elems;
 
543
  gcry_mpi_t *array;
 
544
 
 
545
  *result = NULL;
 
546
 
 
547
  rc = read_key_file (grip, &s_skey);
 
548
  if (rc)
 
549
    return rc;
 
550
 
 
551
  list = gcry_sexp_find_token (s_skey, "shadowed-private-key", 0 );
 
552
  if (!list)
 
553
    list = gcry_sexp_find_token (s_skey, "protected-private-key", 0 );
 
554
  if (!list)
 
555
    list = gcry_sexp_find_token (s_skey, "private-key", 0 );
 
556
  if (!list)
 
557
    {
 
558
      log_error ("invalid private key format\n");
 
559
      gcry_sexp_release (s_skey);
 
560
      return gpg_error (GPG_ERR_BAD_SECKEY);
 
561
    }
 
562
 
 
563
  l2 = gcry_sexp_cadr (list);
 
564
  gcry_sexp_release (list);
 
565
  list = l2;
 
566
  name = gcry_sexp_nth_data (list, 0, &n);
 
567
  if (n==3 && !memcmp (name, "rsa", 3))
 
568
    {
 
569
      algoname = "rsa";
 
570
      elems = "ne";
 
571
    }
 
572
  else if (n==3 && !memcmp (name, "dsa", 3))
 
573
    {
 
574
      algoname = "dsa";
 
575
      elems = "pqgy";
 
576
    }
 
577
  else if (n==3 && !memcmp (name, "elg", 3))
 
578
    {
 
579
      algoname = "elg";
 
580
      elems = "pgy";
 
581
    }
 
582
  else
 
583
    {
 
584
      log_error ("unknown private key algorithm\n");
 
585
      gcry_sexp_release (list);
 
586
      gcry_sexp_release (s_skey);
 
587
      return gpg_error (GPG_ERR_BAD_SECKEY);
 
588
    }
 
589
 
 
590
  /* Allocate an array for the parameters and copy them out of the
 
591
     secret key.   FIXME: We should have a generic copy function. */
 
592
  array = xtrycalloc (strlen(elems) + 1, sizeof *array);
 
593
  if (!array)
 
594
    {
 
595
      rc = gpg_error_from_errno (errno);
 
596
      gcry_sexp_release (list);
 
597
      gcry_sexp_release (s_skey);
 
598
      return rc;
 
599
    }
 
600
 
 
601
  for (idx=0, s=elems; *s; s++, idx++ ) 
 
602
    {
 
603
      l2 = gcry_sexp_find_token (list, s, 1);
 
604
      if (!l2)
 
605
        {
 
606
          /* Required parameter not found.  */
 
607
          for (i=0; i<idx; i++)
 
608
            gcry_mpi_release (array[i]);
 
609
          xfree (array);
 
610
          gcry_sexp_release (list);
 
611
          gcry_sexp_release (s_skey);
 
612
          return gpg_error (GPG_ERR_BAD_SECKEY);
 
613
        }
 
614
      array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
 
615
      gcry_sexp_release (l2);
 
616
      if (!array[idx])
 
617
        {
 
618
          /* Required parameter is invalid. */
 
619
          for (i=0; i<idx; i++)
 
620
            gcry_mpi_release (array[i]);
 
621
          xfree (array);
 
622
          gcry_sexp_release (list);
 
623
          gcry_sexp_release (s_skey);
 
624
          return gpg_error (GPG_ERR_BAD_SECKEY);
 
625
        }
 
626
    }
 
627
  gcry_sexp_release (list);
 
628
  list = NULL;
 
629
 
 
630
  uri = NULL;
 
631
  uri_length = 0;
 
632
  uri_sexp = gcry_sexp_find_token (s_skey, "uri", 0);
 
633
  if (uri_sexp)
 
634
    uri = gcry_sexp_nth_data (uri_sexp, 1, &uri_length);
 
635
 
 
636
  comment = NULL;
 
637
  comment_length = 0;
 
638
  comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0);
 
639
  if (comment_sexp)
 
640
    comment = gcry_sexp_nth_data (comment_sexp, 1, &comment_length);
 
641
 
 
642
  gcry_sexp_release (s_skey);
 
643
  s_skey = NULL;
 
644
 
 
645
 
 
646
  /* FIXME: The following thing is pretty ugly code; we should
 
647
     investigate how to make it cleaner. Probably code to handle
 
648
     canonical S-expressions in a memory buffer is better suioted for
 
649
     such a task.  After all that is what we do in protect.c.  Neeed
 
650
     to find common patterns and write a straightformward API to use
 
651
     them.  */
 
652
  assert (sizeof (size_t) <= sizeof (void*));
 
653
 
 
654
  format = xtrymalloc (15+7*strlen (elems)+10+15+1+1);
 
655
  if (!format)
 
656
    {
 
657
      rc = gpg_error_from_errno (errno);
 
658
      for (i=0; array[i]; i++)
 
659
        gcry_mpi_release (array[i]);
 
660
      xfree (array);
 
661
      gcry_sexp_release (uri_sexp);
 
662
      gcry_sexp_release (comment_sexp);
 
663
      return rc;
 
664
    }
 
665
 
 
666
  argidx = 0;
 
667
  p = stpcpy (stpcpy (format, "(public-key("), algoname);
 
668
  for (idx=0, s=elems; *s; s++, idx++ ) 
 
669
    {
 
670
      *p++ = '(';
 
671
      *p++ = *s;
 
672
      p = stpcpy (p, " %m)");
 
673
      assert (argidx < DIM (args));
 
674
      args[argidx++] = &array[idx];
 
675
    }
 
676
  *p++ = ')';
 
677
  if (uri)
 
678
    {
 
679
      p = stpcpy (p, "(uri %b)");
 
680
      assert (argidx+1 < DIM (args));
 
681
      args[argidx++] = (void *)uri_length;
 
682
      args[argidx++] = (void *)uri;
 
683
    }
 
684
  if (comment)
 
685
    {
 
686
      p = stpcpy (p, "(comment %b)");
 
687
      assert (argidx+1 < DIM (args));
 
688
      args[argidx++] = (void *)comment_length;
 
689
      args[argidx++] = (void*)comment;
 
690
    }
 
691
  *p++ = ')';
 
692
  *p = 0;
 
693
  assert (argidx < DIM (args));
 
694
  args[argidx] = NULL;
 
695
    
 
696
  rc = gcry_sexp_build_array (&list, NULL, format, args);
 
697
  xfree (format);
 
698
  for (i=0; array[i]; i++)
 
699
    gcry_mpi_release (array[i]);
 
700
  xfree (array);
 
701
  gcry_sexp_release (uri_sexp);
 
702
  gcry_sexp_release (comment_sexp);
 
703
 
 
704
  if (!rc)
 
705
    *result = list;
 
706
  return rc;
 
707
}
 
708
 
 
709
 
 
710
 
353
711
/* Return the secret key as an S-Exp after locating it using the grip.
354
712
   Returns NULL if key is not available. 0 = key is available */
355
713
int