c982b7548c662b6ab9caf5d3f6e87b25425bdcee
[scute.git] / src / cert-gpgsm.c
1 /* cert-gpgsm.c - Scute certificate searching.
2    Copyright (C) 2006, 2007 g10 Code GmbH
3
4    This file is part of Scute.
5  
6    Scute is free software; you can redistribute it and/or modify it
7    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    Scute is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with Scute; if not, write to the Free Software Foundation,
18    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
20    In addition, as a special exception, g10 Code GmbH gives permission
21    to link this library: with the Mozilla Foundation's code for
22    Mozilla (or with modified versions of it that use the same license
23    as the "Mozilla" code), and distribute the linked executables.  You
24    must obey the GNU General Public License in all respects for all of
25    the code used other than "Mozilla".  If you modify this file, you
26    may extend this exception to your version of the file, but you are
27    not obligated to do so.  If you do not wish to do so, delete this
28    exception statement from your version.  */
29
30 #if HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33
34 #include <time.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <stdbool.h>
39
40 #include <gpg-error.h>
41 #include <assuan.h>
42
43 #include "agent.h"
44 #include "cert.h"
45 #include "support.h"
46 #include "debug.h"
47
48 \f
49 #ifndef HAVE_W32_SYSTEM
50 #define COMPAT_FALLBACK
51 #endif
52
53 \f
54 /* The maximum length of a key listing line.  We take the double of
55    the allowed Assuan line length to avoid a memmove after a part of a
56    line has been processed.  FIXME: There is actually no limit on the
57    length of the line. */
58 #define MAX_LINE_LEN    (1024*2)
59
60 struct search_ctx
61 {
62   /* The pending line in an active key listing.  */
63   char pending[MAX_LINE_LEN + 1];
64   unsigned int pending_len;
65
66   /* The caller's search callback, invoked for each certificate.  */
67   cert_search_cb_t search_cb;
68   void *search_cb_hook;
69
70   /* The current certificate.  */
71   struct cert cert;
72 };
73
74
75 /* Release allocated storage for the certificate CERT and reset the
76    certificate.  */
77 static void
78 cert_reset (struct cert *cert)
79 {
80   if (cert->issuer_serial)
81     free (cert->issuer_serial);
82   if (cert->issuer_name)
83     free (cert->issuer_name);
84   if (cert->uid)
85     free (cert->uid);
86   if (cert->cert_der)
87     free (cert->cert_der);
88
89   memset (cert, '\0', sizeof (struct cert));
90 }
91
92 \f
93 /* Support routines for key list processing.  */
94
95 #define atoi_1(p)   (*(p) - '0' )
96 #define atoi_2(p)   ((atoi_1(p) * 10) + atoi_1((p)+1))
97 #define atoi_4(p)   ((atoi_2(p) * 100) + atoi_2((p)+2))
98
99 /* Parse the string TIMESTAMP into a time_t.  The string may either be
100    seconds since Epoch or in the ISO 8601 format like
101    "20390815T143012".  Returns 0 for an empty string or seconds since
102    Epoch. Leading spaces are skipped. If ENDP is not NULL, it will
103    point to the next non-parsed character in TIMESTRING. */
104 static time_t
105 parse_timestamp (const char *timestamp, char **endp)
106 {
107   /* Need to skip leading spaces, because that is what strtoul does
108      but not our ISO 8601 checking code. */
109   while (*timestamp && *timestamp== ' ')
110     timestamp++;
111   if (!*timestamp)
112     return 0;
113
114   if (strlen (timestamp) >= 15 && timestamp[8] == 'T')
115     {
116       struct tm buf;
117       int year;
118
119       year = atoi_4 (timestamp);
120       if (year < 1900)
121         return (time_t)(-1);
122
123       /* Fixme: We would better use a configure test to see whether
124          mktime can handle dates beyond 2038. */
125       if (sizeof (time_t) <= 4 && year >= 2038)
126         return (time_t)2145914603; /* 2037-12-31 23:23:23 */
127
128       memset (&buf, 0, sizeof buf);
129       buf.tm_year = year - 1900;
130       buf.tm_mon = atoi_2 (timestamp+4) - 1; 
131       buf.tm_mday = atoi_2 (timestamp+6);
132       buf.tm_hour = atoi_2 (timestamp+9);
133       buf.tm_min = atoi_2 (timestamp+11);
134       buf.tm_sec = atoi_2 (timestamp+13);
135
136       if (endp)
137         *endp = (char*)(timestamp + 15);
138 #ifdef HAVE_TIMEGM
139       return timegm (&buf);
140 #else
141       /* FIXME: Need to set TZ to UTC, but that is not
142          thread-safe.  */
143       return mktime (&buf);
144 #endif
145
146     }
147   else
148     return (time_t)strtoul (timestamp, endp, 10);
149 }
150
151
152 /* Decode the C formatted string SRC and store the result in the
153    buffer *DESTP which is LEN bytes long.  If LEN is zero, then a
154    large enough buffer is allocated with malloc and *DESTP is set to
155    the result.  Currently, LEN is only used to specify if allocation
156    is desired or not, the caller is expected to make sure that *DESTP
157    is large enough if LEN is not zero.  */
158 static gpg_error_t
159 decode_c_string (const char *src, char **destp, size_t len)
160 {
161   char *dest;
162
163   /* Set up the destination buffer.  */
164   if (len)
165     {
166       if (len < strlen (src) + 1)
167         return gpg_error (GPG_ERR_INTERNAL);
168
169       dest = *destp;
170     }
171   else
172     {
173       /* The converted string will never be larger than the original
174          string.  */
175       dest = malloc (strlen (src) + 1);
176       if (!dest)
177         return gpg_error_from_syserror ();
178
179       *destp = dest;
180     }
181
182   /* Convert the string.  */
183   while (*src)
184     {
185       if (*src != '\\')
186         {
187           *(dest++) = *(src++);
188           continue;
189         }
190
191       switch (src[1])
192         {
193 #define DECODE_ONE(match,result)        \
194         case match:                     \
195           src += 2;                     \
196           *(dest++) = result;           \
197           break;
198
199           DECODE_ONE ('\'', '\'');
200           DECODE_ONE ('\"', '\"');
201           DECODE_ONE ('\?', '\?');
202           DECODE_ONE ('\\', '\\');
203           DECODE_ONE ('a', '\a');
204           DECODE_ONE ('b', '\b');
205           DECODE_ONE ('f', '\f');
206           DECODE_ONE ('n', '\n');
207           DECODE_ONE ('r', '\r');
208           DECODE_ONE ('t', '\t');
209           DECODE_ONE ('v', '\v');
210
211         case 'x':
212           {
213             int val = xtoi_2 (&src[2]);
214
215             if (val == -1)
216               {
217                 /* Should not happen.  */
218                 *(dest++) = *(src++);
219                 *(dest++) = *(src++);
220                 if (*src)
221                   *(dest++) = *(src++);
222                 if (*src)
223                   *(dest++) = *(src++);
224               }
225             else
226               {
227                 if (!val)
228                   {
229                     /* A binary zero is not representable in a C
230                        string.  */
231                     *(dest++) = '\\';
232                     *(dest++) = '0'; 
233                   }
234                 else 
235                   *((unsigned char *) dest++) = val;
236                 src += 4;
237               }
238           }
239           break;
240
241         default:
242           {
243             /* Should not happen.  */
244             *(dest++) = *(src++);
245             *(dest++) = *(src++);
246           }
247         } 
248     }
249   *(dest++) = 0;
250
251   return 0;
252 }
253
254 \f
255 /* The cert handler for certificate searches.  This is invoked for
256    each complete certificate found by search_certs_line, and the last
257    pending certificate when EOF is encountered by search_certs.  */
258 static gpg_error_t
259 search_certs_cert (struct search_ctx *ctx)
260 {
261   return (*ctx->search_cb) (ctx->search_cb_hook, &ctx->cert);
262 }
263
264
265 /* The line handler for certificate searches.  This is invoked for
266    each complete line found by search_certs.  */
267 static gpg_error_t
268 search_certs_line (struct search_ctx *ctx)
269 {
270   char *line;
271   enum { RT_NONE, RT_CRT, RT_CRS, RT_FPR, RT_GRP, RT_UID } rectype = RT_NONE;
272 #define NR_FIELDS 16
273   char *field[NR_FIELDS];
274   int fields = 0;
275   struct cert *cert;
276
277   /* Strip a trailing carriage return.  */
278   if (ctx->pending_len > 0
279       && ctx->pending[ctx->pending_len - 1] == '\r')
280     ctx->pending_len--;
281   ctx->pending[ctx->pending_len - 1] = '\0';
282   ctx->pending_len = 0;
283
284   cert = &ctx->cert;
285   line = ctx->pending;
286   while (line && fields < NR_FIELDS)
287     {
288       field[fields++] = line;
289       line = strchr (line, ':');
290       if (line)
291         *(line++) = '\0';
292     }
293
294   if (!strcmp (field[0], "crt"))
295     rectype = RT_CRT;
296   else if (!strcmp (field[0], "crs"))
297     rectype = RT_CRS;
298   else if (!strcmp (field[0], "fpr"))
299     rectype = RT_FPR;
300   else if (!strcmp (field[0], "grp"))
301     rectype = RT_GRP;
302   else if (!strcmp (field[0], "uid"))
303     rectype = RT_UID;
304   else 
305     rectype = RT_NONE;
306
307   switch (rectype)
308     {
309     case RT_CRT:
310     case RT_CRS:
311       /* Reinitialize CERT.  */
312       if (cert->valid)
313         {
314           gpg_error_t err;
315
316           err = search_certs_cert (ctx);
317           if (err)
318             return err;
319
320           cert_reset (cert);
321         }
322
323       cert->valid = true;
324
325 #if 0
326       /* Field 2 has the trust info.  */
327       if (fields >= 2)
328         set_mainkey_trust_info (key, field[1]);
329 #endif
330
331       /* Field 3 has the key length.  */
332       if (fields >= 3)
333         {
334           int i = atoi (field[2]);
335           /* Ignore invalid values.  */
336           if (i > 1)
337             cert->length = i; 
338         }
339
340       /* Field 4 has the public key algorithm.  */
341       if (fields >= 4)
342         {
343           int i = atoi (field[3]);
344           if (i >= 1 && i < 128)
345             cert->pubkey_algo = i;
346         }
347
348       /* Field 5 has the long keyid.  Allow short key IDs for the
349          output of an external keyserver listing.  */
350       if (fields >= 5 && strlen (field[4]) <= sizeof (cert->keyid) - 1)
351         strcpy (cert->keyid, field[4]);
352
353       /* Field 6 has the timestamp (seconds).  */
354       if (fields >= 6)
355         cert->timestamp = parse_timestamp (field[5], NULL);
356
357       /* Field 7 has the expiration time (seconds).  */
358       if (fields >= 7)
359         cert->expires = parse_timestamp (field[6], NULL);
360
361       /* Field 8 has the X.509 serial number.  */
362       if (fields >= 8)
363         {
364           cert->issuer_serial = strdup (field[7]);
365           if (!cert->issuer_serial)
366             return gpg_error_from_syserror ();
367         }
368
369 #if 0
370       /* Field 9 has the ownertrust.  */
371       if (fields >= 9)
372         set_ownertrust (key, field[8]);
373 #endif
374
375       /* Field 10 is the issuer name.  */
376       if (fields >= 10)
377         if (decode_c_string (field[9], &cert->issuer_name, 0))
378           return gpg_error (GPG_ERR_ENOMEM);    /* FIXME */
379
380       /* Field 11 has the signature class.  */
381
382 #if 0
383       /* Field 12 has the capabilities.  */
384       if (fields >= 12)
385         set_mainkey_capability (key, field[11]);
386 #endif
387       break;
388
389     case RT_UID:
390       if (cert->valid)
391         {
392           /* Field 2 has the trust info, and field 10 has the user ID.
393              Note that more than one UID field can appear.  We only
394              remember the last one.  It's not used anyway.  */
395           if (fields >= 10 && !cert->uid)
396             {
397               if (decode_c_string (field[9], &cert->uid, 0))
398                 return gpg_error (GPG_ERR_ENOMEM);      /* FIXME */
399             }
400         }
401       break;
402
403     case RT_FPR:
404       if (cert->valid)
405         {
406           /* Field 10 has the fingerprint (take only the first one).  */
407           if (fields >= 10 && strlen (field[9]) <= sizeof (cert->fpr) - 1)
408             strcpy (cert->fpr, field[9]);
409
410           /* Field 13 has the gpgsm chain ID (take only the first one).  */
411           if (fields >= 13 && strlen (field[12])
412               <= sizeof (cert->chain_id) - 1)
413             strcpy (cert->chain_id, field[12]);
414         }
415       break;
416
417     case RT_GRP:
418       if (cert->valid)
419         {
420           /* Field 10 has the key grip.  */
421           if (fields >= 10 && strlen (field[9]) <= sizeof (cert->grip) - 1)
422             strcpy (cert->grip, field[9]);
423         }
424       break;
425
426     case RT_NONE:
427       /* Unknown record.  */
428       break;
429     }
430
431   return 0;
432 }
433
434
435 /* This is the data line callback handler provided to assuan_transact
436    in scute_gpgsm_search_certs.  It buffers incomplete lines, and also
437    handles the EOF signal provided directly by
438    scute_gpgsm_search_certs.  */
439 static gpg_error_t
440 search_certs (void *hook, const void *line_data, size_t line_len)
441 {
442   struct search_ctx *ctx = hook;
443   const char *line = line_data;
444   gpg_error_t err;
445
446   if (!line)
447     {
448       /* This indicates an EOF.  */
449
450       /* Check for a pending line, in case GPGSM didn't close with a
451          newline.  */
452       if (ctx->pending_len)
453         {
454           err = search_certs_line (ctx);
455           if (err)
456             return err;
457         }
458
459       /* Check for a pending certificate.  */
460       if (ctx->cert.valid)
461         return search_certs_cert (ctx);
462
463       return 0;
464     }
465
466   while (line_len)
467     {
468       if (*line == '\n')
469         {
470           err = search_certs_line (ctx);
471           if (err)
472             return err;
473         }
474       else
475         {
476           if (ctx->pending_len >= MAX_LINE_LEN)
477             return gpg_error (GPG_ERR_LINE_TOO_LONG);
478
479           ctx->pending[ctx->pending_len++] = *line;
480         }
481       line++;
482       line_len--;
483     }
484
485   return 0;
486 }
487
488
489 /* Invoke SEARCH_CB for each certificate found using assuan connection
490    CTX to GPGSM.  */
491 static gpg_error_t
492 scute_gpgsm_search_certs (assuan_context_t ctx, cert_search_cb_t search_cb,
493                           void *search_cb_hook)
494 {
495   gpg_error_t err;
496   struct search_ctx search;
497
498   err = assuan_transact (ctx, "OPTION with-key-data", NULL, NULL,
499                          NULL, NULL, NULL, NULL);
500   if (err)
501     return err;
502
503   search.pending_len = 0;
504   search.search_cb = search_cb;
505   search.search_cb_hook = search_cb_hook;
506   memset (&search.cert, '\0', sizeof (search.cert));
507
508   err = assuan_transact (ctx, "DUMPKEYS", &search_certs, &search, NULL,
509                          NULL, NULL, NULL);
510   if (err)
511     goto out;
512
513   /* Signal the EOF.  This is not done by Assuan for us.  */
514   err = search_certs (&search, NULL, 0);
515   if (err)
516     goto out;
517
518  out:
519   cert_reset (&search.cert);
520   return err;
521 }
522
523 \f
524 struct search_ctx_by_field
525 {
526   /* What we are searching for.  */
527   enum { SEARCH_BY_GRIP, SEARCH_BY_FPR } field;
528
529   /* The pattern we are looking for.  */
530   const char *pattern;
531
532   cert_search_cb_t search_cb;
533   void *search_cb_hook;
534 };
535   
536
537 #ifdef COMPAT_FALLBACK
538 /* This is a compatibility function for GPGSM 2.0.0, which does not
539    support the --data option with the EXPORT command.  */
540 static gpg_error_t
541 export_cert_compat (char *fpr, struct cert *cert)
542 {
543   gpg_error_t err;
544   assuan_context_t ctx;
545   const char *argv[] = { "gpgsm", "--server", NULL };
546   int got;
547 #define COMMANDLINELEN 80
548   char cmd[COMMANDLINELEN];
549   int output_fds[2];
550   int child_fds[2];
551
552 #define MAX_CERT_SIZE 4096
553   cert->cert_der = malloc (MAX_CERT_SIZE);
554   if (!cert->cert_der)
555     return gpg_error_from_syserror ();
556
557   if(pipe (output_fds) < 0)
558     return gpg_error_from_syserror ();
559
560   child_fds[0] = assuan_fd_from_posix_fd (output_fds[1]);
561   child_fds[1] = -1;
562
563   err = assuan_new (&ctx);
564   if (err)
565     {
566       close (output_fds[0]);
567       close (output_fds[1]);
568       DEBUG (DBG_CRIT, "failed to allocate assuan context: %s\n",
569              gpg_strerror (err));
570       return err;
571     }
572
573   err = assuan_pipe_connect (ctx, get_gpgsm_path (), argv, child_fds,
574                              NULL, NULL, 128);
575   close (output_fds[1]);
576   if (err)
577     {
578       close (output_fds[0]);
579       assuan_release (ctx);
580       DEBUG (DBG_CRIT, "failed to spawn %s\n", get_gpgsm_path ());
581       return err;
582     }
583
584   snprintf (cmd, sizeof (cmd), "OUTPUT FD=%i", output_fds[1]);
585   err = assuan_transact (ctx, cmd, NULL, NULL, NULL, NULL, NULL, NULL);
586   if (err)
587     goto export_out;
588
589   /* FIXME: This will only work if the certificate is small and fits
590      into the pipe buffer completely!!!  */
591   snprintf (cmd, sizeof (cmd), "EXPORT %s\n", cert->fpr);
592   err = assuan_transact (ctx, cmd, NULL, NULL, NULL, NULL, NULL, NULL);
593   if (err)
594     goto export_out;
595
596   do
597     {
598       got = read (output_fds[0], cert->cert_der + cert->cert_der_len,
599                   MAX_CERT_SIZE - cert->cert_der_len);
600       if (got > 0)
601         cert->cert_der_len += got;
602     }
603   while (!err && got > 0 && cert->cert_der_len < MAX_CERT_SIZE);
604   
605   if (got < 0 || cert->cert_der_len == MAX_CERT_SIZE)
606     err = gpg_error (GPG_ERR_GENERAL);
607
608  export_out:
609   assuan_release (ctx);
610   close (output_fds[0]);
611   return err;
612 }
613 #endif
614
615
616 struct export_hook
617 {
618   /* The exported data.  */
619   char *buffer;
620
621   /* The length of the exported data buffer.  */
622   unsigned int buffer_len;
623
624   /* The size of the allocated exported data buffer.  */
625   unsigned int buffer_size;
626 };
627
628 #define EXP_DATA_START 4096
629
630 static gpg_error_t
631 export_cert_cb (void *hook, const void *line_data, size_t line_len)
632 {
633   struct export_hook *exp = hook;
634   const char *line = line_data;
635
636   if (exp->buffer_size - exp->buffer_len < line_len)
637     {
638       unsigned int new_buffer_size = exp->buffer_size ?
639         (exp->buffer_size * 2) : EXP_DATA_START;
640       char *new_buffer = realloc (exp->buffer, new_buffer_size);
641
642       if (!new_buffer)
643         return gpg_error_from_syserror ();
644
645       exp->buffer = new_buffer;
646       exp->buffer_size = new_buffer_size;
647     }
648
649   memcpy (exp->buffer + exp->buffer_len, line, line_len);
650   exp->buffer_len += line_len;
651
652   return 0;
653 }
654
655
656 static gpg_error_t
657 export_cert (char *fpr, struct cert *cert)
658 {
659   gpg_error_t err;
660   assuan_context_t ctx;
661   const char *argv[] = { "gpgsm", "--server", NULL };
662 #define COMMANDLINELEN 80
663   char cmd[COMMANDLINELEN];
664   struct export_hook exp;
665
666   err = assuan_new (&ctx);
667   if (err)
668     {
669       DEBUG (DBG_CRIT, "failed to allocate assuan context: %s",
670              gpg_strerror (err));
671       return err;
672     }
673
674   err = assuan_pipe_connect (ctx, get_gpgsm_path (), argv, NULL,
675                              NULL, NULL, 128);
676   if (err)
677     {
678       assuan_release (ctx);
679       DEBUG (DBG_CRIT, "spawning %s\n", get_gpgsm_path ());
680       return err;
681     }
682
683   exp.buffer = NULL;
684   exp.buffer_len = 0;
685   exp.buffer_size = 0;
686
687   snprintf (cmd, sizeof (cmd), "EXPORT --data -- %s\n", cert->fpr);
688   err = assuan_transact (ctx, cmd, export_cert_cb, &exp,
689                          NULL, NULL, NULL, NULL);
690   assuan_release (ctx);
691
692   if (!err)
693     {
694       cert->cert_der = exp.buffer;
695       cert->cert_der_len = exp.buffer_len;
696     }
697 #ifdef COMPAT_FALLBACK
698   else if (gpg_err_code (err) == GPG_ERR_ASS_NO_OUTPUT)
699     {
700       /* For compatibility with GPGSM 2.0.0, we fall back to a work
701          around in that case.  */
702       if (cert->cert_der)
703         {
704           free (cert->cert_der);
705           cert->cert_der = NULL;
706         }
707       err = export_cert_compat (fpr, cert);
708     }
709 #endif
710
711   if (!err)
712     err = scute_agent_is_trusted (fpr, &cert->is_trusted);
713
714   return err;
715 }
716
717
718 static gpg_error_t
719 search_certs_by_field (void *hook, struct cert *cert)
720 {
721   struct search_ctx_by_field *ctx = hook;
722   gpg_error_t err = 0;
723
724   if ((ctx->field == SEARCH_BY_GRIP && !strcmp (ctx->pattern, cert->grip))
725       || (ctx->field == SEARCH_BY_FPR && !strcmp (ctx->pattern, cert->fpr)))
726     {
727       if (strlen (cert->fpr) != 40)
728         return gpg_error (GPG_ERR_GENERAL);
729
730       err = export_cert (cert->fpr, cert);
731       if (err)
732         return err;
733
734       err = (*ctx->search_cb) (ctx->search_cb_hook, cert);
735     }
736
737   return err;
738 }
739
740
741 /* Invoke SEARCH_CB for each certificate found using assuan connection
742    CTX to GPGSM.  */
743 gpg_error_t
744 scute_gpgsm_search_certs_by_grip (const char *grip,
745                                   cert_search_cb_t search_cb,
746                                   void *search_cb_hook)
747 {
748   gpg_error_t err;
749   assuan_context_t ctx;
750   const char *argv[] = { "gpgsm", "--server", NULL };
751   struct search_ctx_by_field search;
752
753   err = assuan_new (&ctx);
754   if (err)
755     {
756       DEBUG (DBG_CRIT, "failed to allocate assuan context: %s",
757              gpg_strerror (err));
758       return err;
759     }
760
761   err = assuan_pipe_connect (ctx, get_gpgsm_path (), argv, NULL,
762                              NULL, NULL, 128);
763   if (err)
764     {
765       assuan_release (ctx);
766       DEBUG (DBG_CRIT, "spawning %s\n", get_gpgsm_path ());
767       return err;
768     }
769
770   search.field = SEARCH_BY_GRIP;
771   search.pattern = grip;
772   search.search_cb = search_cb;
773   search.search_cb_hook = search_cb_hook;
774
775   err = scute_gpgsm_search_certs (ctx, &search_certs_by_field, &search);
776   assuan_release (ctx);
777   return err;
778 }
779
780
781 /* Invoke SEARCH_CB for each certificate found using assuan connection
782    CTX to GPGSM.  */
783 gpg_error_t
784 scute_gpgsm_search_certs_by_fpr (const char *fpr,
785                                  cert_search_cb_t search_cb,
786                                  void *search_cb_hook)
787 {
788   gpg_error_t err;
789   assuan_context_t ctx;
790   const char *argv[] = { "gpgsm", "--server", NULL };
791   struct search_ctx_by_field search;
792
793   err = assuan_new (&ctx);
794   if (err)
795     {
796       DEBUG (DBG_CRIT, "failed to allocate assuan context: %s",
797              gpg_strerror (err));
798       return err;
799     }
800
801   err = assuan_pipe_connect (ctx, get_gpgsm_path (), argv, NULL,
802                              NULL, NULL, 128);
803   if (err)
804     {
805       assuan_release (ctx);
806       DEBUG (DBG_CRIT, "failed to spawn %s\n", get_gpgsm_path ());
807       return err;
808     }
809
810   search.field = SEARCH_BY_FPR;
811   search.pattern = fpr;
812   search.search_cb = search_cb;
813   search.search_cb_hook = search_cb_hook;
814
815   err = scute_gpgsm_search_certs (ctx, &search_certs_by_field, &search);
816   assuan_release (ctx);
817   return err;
818 }