Let gpgsm do the actual key selection work.
[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
49 /* The maximum length of a key listing line.  We take the double of
50  * the allowed Assuan line length plus some extra space to avoid a
51  * memmove after a part of a line has been processed.  */
52 #define MAX_LINE_LEN    (ASSUAN_LINELENGTH*2 + 200)
53
54 struct keylist_ctx
55 {
56   /* The pending line in an active key listing.  */
57   char pending[MAX_LINE_LEN + 1];
58   unsigned int pending_len;
59
60   /* The current certificate.  */
61   struct cert cert;
62
63   /* The caller's search callback, invoked for each certificate.  */
64   cert_search_cb_t search_cb;
65   void *search_cb_hook;
66 };
67
68
69 /* Support macros  */
70 #define atoi_1(p)   (*(p) - '0' )
71 #define atoi_2(p)   ((atoi_1(p) * 10) + atoi_1((p)+1))
72 #define atoi_4(p)   ((atoi_2(p) * 100) + atoi_2((p)+2))
73
74
75 /*** Local prototypes  ***/
76 static gpg_error_t export_cert (const char *fpr, struct cert *cert);
77
78
79
80 \f
81 /* Release allocated storage for the certificate CERT and reset the
82    certificate.  */
83 static void
84 cert_reset (struct cert *cert)
85 {
86   if (cert->issuer_serial)
87     free (cert->issuer_serial);
88   if (cert->issuer_name)
89     free (cert->issuer_name);
90   if (cert->uid)
91     free (cert->uid);
92   if (cert->cert_der)
93     free (cert->cert_der);
94
95   memset (cert, '\0', sizeof (struct cert));
96 }
97
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
255 \f
256 /* Helper for keylist_cb.  This fucntion is invoked for each complete
257  * line assembled by keylist_cb.  */
258 static gpg_error_t
259 keylist_cb_line (struct keylist_ctx *ctx)
260 {
261   char *line;
262   enum { RT_NONE, RT_CRT, RT_CRS, RT_FPR, RT_GRP, RT_UID } rectype = RT_NONE;
263 #define NR_FIELDS 16
264   char *field[NR_FIELDS];
265   int fields = 0;
266   struct cert *cert;
267
268   /* Strip a trailing carriage return.  */
269   if (ctx->pending_len > 0
270       && ctx->pending[ctx->pending_len - 1] == '\r')
271     ctx->pending_len--;
272   ctx->pending[ctx->pending_len - 1] = '\0';
273   ctx->pending_len = 0;
274
275   cert = &ctx->cert;
276   line = ctx->pending;
277   while (line && fields < NR_FIELDS)
278     {
279       field[fields++] = line;
280       line = strchr (line, ':');
281       if (line)
282         *(line++) = '\0';
283     }
284
285   if (!strcmp (field[0], "crt"))
286     rectype = RT_CRT;
287   else if (!strcmp (field[0], "crs"))
288     rectype = RT_CRS;
289   else if (!strcmp (field[0], "fpr"))
290     rectype = RT_FPR;
291   else if (!strcmp (field[0], "grp"))
292     rectype = RT_GRP;
293   else if (!strcmp (field[0], "uid"))
294     rectype = RT_UID;
295   else
296     rectype = RT_NONE;
297
298   switch (rectype)
299     {
300     case RT_CRT:
301     case RT_CRS:
302       /* Reinitialize CERT.  */
303       if (cert->valid)
304         {
305           gpg_error_t err;
306
307           /* Return the cert.  */
308           err = export_cert (ctx->cert.fpr, &ctx->cert);
309           if (!err)
310             err = ctx->search_cb (ctx->search_cb_hook, &ctx->cert);
311           if (err)
312             return err;
313
314           cert_reset (cert);
315         }
316
317       cert->valid = true;
318
319 #if 0
320       /* Field 2 has the trust info.  */
321       if (fields >= 2)
322         set_mainkey_trust_info (key, field[1]);
323 #endif
324
325       /* Field 3 has the key length.  */
326       if (fields >= 3)
327         {
328           int i = atoi (field[2]);
329           /* Ignore invalid values.  */
330           if (i > 1)
331             cert->length = i;
332         }
333
334       /* Field 4 has the public key algorithm.  */
335       if (fields >= 4)
336         {
337           int i = atoi (field[3]);
338           if (i >= 1 && i < 128)
339             cert->pubkey_algo = i;
340         }
341
342       /* Field 5 has the long keyid.  Allow short key IDs for the
343          output of an external keyserver listing.  */
344       if (fields >= 5 && strlen (field[4]) <= sizeof (cert->keyid) - 1)
345         strcpy (cert->keyid, field[4]);
346
347       /* Field 6 has the timestamp (seconds).  */
348       if (fields >= 6)
349         cert->timestamp = parse_timestamp (field[5], NULL);
350
351       /* Field 7 has the expiration time (seconds).  */
352       if (fields >= 7)
353         cert->expires = parse_timestamp (field[6], NULL);
354
355       /* Field 8 has the X.509 serial number.  */
356       if (fields >= 8)
357         {
358           cert->issuer_serial = strdup (field[7]);
359           if (!cert->issuer_serial)
360             return gpg_error_from_syserror ();
361         }
362
363 #if 0
364       /* Field 9 has the ownertrust.  */
365       if (fields >= 9)
366         set_ownertrust (key, field[8]);
367 #endif
368
369       /* Field 10 is the issuer name.  */
370       if (fields >= 10)
371         if (decode_c_string (field[9], &cert->issuer_name, 0))
372           return gpg_error (GPG_ERR_ENOMEM);    /* FIXME */
373
374       /* Field 11 has the signature class.  */
375
376 #if 0
377       /* Field 12 has the capabilities.  */
378       if (fields >= 12)
379         set_mainkey_capability (key, field[11]);
380 #endif
381       break;
382
383     case RT_UID:
384       if (cert->valid)
385         {
386           /* Field 2 has the trust info, and field 10 has the user ID.
387              Note that more than one UID field can appear.  We only
388              remember the last one.  It's not used anyway.  */
389           if (fields >= 10 && !cert->uid)
390             {
391               if (decode_c_string (field[9], &cert->uid, 0))
392                 return gpg_error (GPG_ERR_ENOMEM);      /* FIXME */
393             }
394         }
395       break;
396
397     case RT_FPR:
398       if (cert->valid)
399         {
400           /* Field 10 has the fingerprint (take only the first one).  */
401           if (fields >= 10 && strlen (field[9]) <= sizeof (cert->fpr) - 1)
402             strcpy (cert->fpr, field[9]);
403
404           /* Field 13 has the gpgsm chain ID (take only the first one).  */
405           if (fields >= 13 && strlen (field[12])
406               <= sizeof (cert->chain_id) - 1)
407             strcpy (cert->chain_id, field[12]);
408         }
409       break;
410
411     case RT_GRP:
412       if (cert->valid)
413         {
414           /* Field 10 has the key grip.  */
415           if (fields >= 10 && strlen (field[9]) <= sizeof (cert->grip) - 1)
416             strcpy (cert->grip, field[9]);
417         }
418       break;
419
420     case RT_NONE:
421       /* Unknown record.  */
422       break;
423     }
424
425   return 0;
426 }
427
428
429 /* This is the data line callback handler provided to assuan_transact
430  * in scute_gpgsm_search_certs_by_{grip,fpr}.  It buffers incomplete
431  * lines, and is also used to handle the EOF signal directly outside
432  * of assuan_transact.  */
433 static gpg_error_t
434 keylist_cb (void *hook, const void *line_data, size_t line_len)
435 {
436   struct keylist_ctx *ctx = hook;
437   const char *line = line_data;
438   gpg_error_t err;
439
440   if (!line)
441     {
442       /* This indicates an EOF.  */
443
444       /* Check for a pending line, in case GPGSM didn't close with a
445          newline.  */
446       if (ctx->pending_len)
447         {
448           err = keylist_cb_line (ctx);
449           if (err)
450             return err;
451         }
452
453       /* Check for a pending certificate and return it.  */
454       if (ctx->cert.valid)
455         {
456           err = export_cert (ctx->cert.fpr, &ctx->cert);
457           if (!err)
458             err = ctx->search_cb (ctx->search_cb_hook, &ctx->cert);
459         }
460       else
461         err = 0;
462
463       return err;
464     }
465
466   while (line_len)
467     {
468       if (*line == '\n')
469         {
470           err = keylist_cb_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 \f
490
491 struct export_hook
492 {
493   /* The exported data.  */
494   char *buffer;
495
496   /* The length of the exported data buffer.  */
497   unsigned int buffer_len;
498
499   /* The size of the allocated exported data buffer.  */
500   unsigned int buffer_size;
501 };
502
503 #define EXP_DATA_START 4096
504
505 static gpg_error_t
506 export_cert_cb (void *hook, const void *line_data, size_t line_len)
507 {
508   struct export_hook *exp = hook;
509   const char *line = line_data;
510
511   if (exp->buffer_size - exp->buffer_len < line_len)
512     {
513       unsigned int new_buffer_size = exp->buffer_size ?
514         (exp->buffer_size * 2) : EXP_DATA_START;
515       char *new_buffer = realloc (exp->buffer, new_buffer_size);
516
517       if (!new_buffer)
518         return gpg_error_from_syserror ();
519
520       exp->buffer = new_buffer;
521       exp->buffer_size = new_buffer_size;
522     }
523
524   memcpy (exp->buffer + exp->buffer_len, line, line_len);
525   exp->buffer_len += line_len;
526
527   return 0;
528 }
529
530
531 /* Export the certifciate using a second assuan connection.  This is
532  * called during the key listing after a "crt" record has been
533  * received.  */
534 static gpg_error_t
535 export_cert (const char *fpr, struct cert *cert)
536 {
537   gpg_error_t err;
538   assuan_context_t ctx;
539   const char *argv[] = { "gpgsm", "--server", NULL };
540 #define COMMANDLINELEN 80
541   char cmd[COMMANDLINELEN];
542   struct export_hook exp;
543
544   err = assuan_new (&ctx);
545   if (err)
546     {
547       DEBUG (DBG_CRIT, "failed to allocate assuan context: %s",
548              gpg_strerror (err));
549       return err;
550     }
551
552   err = assuan_pipe_connect (ctx, get_gpgsm_path (), argv, NULL,
553                              NULL, NULL, 128);
554   if (err)
555     {
556       assuan_release (ctx);
557       DEBUG (DBG_CRIT, "spawning %s\n", get_gpgsm_path ());
558       return err;
559     }
560
561   exp.buffer = NULL;
562   exp.buffer_len = 0;
563   exp.buffer_size = 0;
564
565   snprintf (cmd, sizeof (cmd), "EXPORT --data -- %s", cert->fpr);
566   err = assuan_transact (ctx, cmd, export_cert_cb, &exp,
567                          NULL, NULL, NULL, NULL);
568   assuan_release (ctx);
569
570   if (!err)
571     {
572       cert->cert_der = exp.buffer;
573       cert->cert_der_len = exp.buffer_len;
574     }
575
576   if (!err)
577     err = scute_agent_is_trusted (fpr, &cert->is_trusted);
578
579   return err;
580 }
581
582
583 /* Search for certificates using a key listing using PATTERN which is
584  * described by MODE.  Invoke SEARCH_CB for each certificate found.  */
585 gpg_error_t
586 scute_gpgsm_search_certs (enum keylist_modes mode, const char *pattern,
587                           cert_search_cb_t search_cb,
588                           void *search_cb_hook)
589 {
590   gpg_error_t err;
591   assuan_context_t ctx;
592   const char *argv[] = { "gpgsm", "--server", NULL };
593   char line[ASSUAN_LINELENGTH];
594   struct keylist_ctx  keylist_ctx;
595
596   err = assuan_new (&ctx);
597   if (err)
598     {
599       DEBUG (DBG_CRIT, "failed to allocate assuan context: %s",
600              gpg_strerror (err));
601       return err;
602     }
603
604   err = assuan_pipe_connect (ctx, get_gpgsm_path (), argv, NULL,
605                              NULL, NULL, 128);
606   if (err)
607     {
608       assuan_release (ctx);
609       DEBUG (DBG_CRIT, "failed to spawn %s\n", get_gpgsm_path ());
610       return err;
611     }
612
613   memset (&keylist_ctx, 0, sizeof keylist_ctx);
614   keylist_ctx.search_cb = search_cb;
615   keylist_ctx.search_cb_hook = search_cb_hook;
616
617   err = assuan_transact (ctx, "OPTION with-key-data", NULL, NULL,
618                          NULL, NULL, NULL, NULL);
619   if (err)
620     goto leave;
621
622
623   snprintf (line, sizeof line, "LISTKEYS %s%s",
624             mode == KEYLIST_BY_GRIP? "&":"",
625             pattern);
626   err = assuan_transact (ctx, line,
627                          keylist_cb, &keylist_ctx,
628                          NULL, NULL,
629                          NULL, NULL);
630   if (err)
631     goto leave;
632
633   /* Signal the EOF.  This is not done by Assuan for us.  */
634   err = keylist_cb (&keylist_ctx, NULL, 0);
635   if (err)
636     goto leave;
637
638  leave:
639   cert_reset (&keylist_ctx.cert);
640   assuan_release (ctx);
641   return err;
642 }