chiark / gitweb /
gpg agent lockup fix: Interrupt main loop when active_connections_value==0
[gnupg2.git] / dirmngr / misc.c
1 /* misc.c - miscellaneous
2  *      Copyright (C) 2002 Klarälvdalens Datakonsult AB
3  *      Copyright (C) 2002, 2003, 2004, 2010 Free Software Foundation, Inc.
4  *
5  * This file is part of DirMngr.
6  *
7  * DirMngr is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * DirMngr is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * 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, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20  */
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <time.h>
27 #include <errno.h>
28
29 #include "dirmngr.h"
30 #include "util.h"
31 #include "misc.h"
32
33
34 /* Convert the hex encoded STRING back into binary and store the
35    result into the provided buffer RESULT.  The actual size of that
36    buffer will be returned.  The caller should provide RESULT of at
37    least strlen(STRING)/2 bytes.  There is no error detection, the
38    parsing stops at the first non hex character.  With RESULT given as
39    NULL, the function does only return the size of the buffer which
40    would be needed.  */
41 size_t
42 unhexify (unsigned char *result, const char *string)
43 {
44   const char *s;
45   size_t n;
46
47   for (s=string,n=0; hexdigitp (s) && hexdigitp(s+1); s += 2)
48     {
49       if (result)
50         result[n] = xtoi_2 (s);
51       n++;
52     }
53   return n;
54 }
55
56
57 char*
58 hashify_data( const char* data, size_t len )
59 {
60   unsigned char buf[20];
61   gcry_md_hash_buffer (GCRY_MD_SHA1, buf, data, len);
62   return hexify_data (buf, 20, 0);
63 }
64
65 char*
66 hexify_data (const unsigned char* data, size_t len, int with_prefix)
67 {
68   int i;
69   char *result = xmalloc (2*len + (with_prefix?2:0) + 1);
70   char *p;
71
72   if (with_prefix)
73     p = stpcpy (result, "0x");
74   else
75     p = result;
76
77   for (i = 0; i < 2*len; i+=2 )
78     snprintf (p+i, 3, "%02X", *data++);
79   return result;
80 }
81
82 char *
83 serial_hex (ksba_sexp_t serial )
84 {
85   unsigned char* p = serial;
86   char *endp;
87   unsigned long n;
88   char *certid;
89
90   if (!p)
91     return NULL;
92   else {
93     p++; /* ignore initial '(' */
94     n = strtoul (p, (char**)&endp, 10);
95     p = endp;
96     if (*p!=':')
97       return NULL;
98     else {
99       int i = 0;
100       certid = xmalloc( sizeof( char )*(2*n + 1 ) );
101       for (p++; n; n--, p++) {
102         sprintf ( certid+i , "%02X", *p);
103         i += 2;
104       }
105     }
106   }
107   return certid;
108 }
109
110
111 /* Take an S-Expression encoded blob and return a pointer to the
112    actual data as well as its length.  Return NULL for an invalid
113    S-Expression.*/
114 const unsigned char *
115 serial_to_buffer (const ksba_sexp_t serial, size_t *length)
116 {
117   unsigned char *p = serial;
118   char *endp;
119   unsigned long n;
120
121   if (!p || *p != '(')
122     return NULL;
123   p++;
124   n = strtoul (p, &endp, 10);
125   p = endp;
126   if (*p != ':')
127     return NULL;
128   p++;
129   *length = n;
130   return p;
131 }
132
133
134 /* Do an in-place percent unescaping of STRING. Returns STRING. Note
135    that this function does not do a '+'-to-space unescaping.*/
136 char *
137 unpercent_string (char *string)
138 {
139   char *s = string;
140   char *d = string;
141
142   while (*s)
143     {
144       if (*s == '%' && s[1] && s[2])
145         {
146           s++;
147           *d++ = xtoi_2 ( s);
148           s += 2;
149         }
150       else
151         *d++ = *s++;
152     }
153   *d = 0;
154   return string;
155 }
156
157 /* Convert a canonical encoded S-expression in CANON into the GCRY
158    type. */
159 gpg_error_t
160 canon_sexp_to_gcry (const unsigned char *canon, gcry_sexp_t *r_sexp)
161 {
162   gpg_error_t err;
163   size_t n;
164   gcry_sexp_t sexp;
165
166   *r_sexp = NULL;
167   n = gcry_sexp_canon_len (canon, 0, NULL, NULL);
168   if (!n)
169     {
170       log_error (_("invalid canonical S-expression found\n"));
171       err = gpg_error (GPG_ERR_INV_SEXP);
172     }
173   else if ((err = gcry_sexp_sscan (&sexp, NULL, canon, n)))
174     log_error (_("converting S-expression failed: %s\n"), gcry_strerror (err));
175   else
176     *r_sexp = sexp;
177   return err;
178 }
179
180
181 /* Return an allocated buffer with the formatted fingerprint as one
182    large hexnumber */
183 char *
184 get_fingerprint_hexstring (ksba_cert_t cert)
185 {
186   unsigned char digest[20];
187   gcry_md_hd_t md;
188   int rc;
189   char *buf;
190   int i;
191
192   rc = gcry_md_open (&md, GCRY_MD_SHA1, 0);
193   if (rc)
194     log_fatal (_("gcry_md_open failed: %s\n"), gpg_strerror (rc));
195
196   rc = ksba_cert_hash (cert, 0, HASH_FNC, md);
197   if (rc)
198     {
199       log_error (_("oops: ksba_cert_hash failed: %s\n"), gpg_strerror (rc));
200       memset (digest, 0xff, 20); /* Use a dummy value. */
201     }
202   else
203     {
204       gcry_md_final (md);
205       memcpy (digest, gcry_md_read (md, GCRY_MD_SHA1), 20);
206     }
207   gcry_md_close (md);
208   buf = xmalloc (41);
209   *buf = 0;
210   for (i=0; i < 20; i++ )
211     sprintf (buf+strlen(buf), "%02X", digest[i]);
212   return buf;
213 }
214
215 /* Return an allocated buffer with the formatted fingerprint as one
216    large hexnumber.  This version inserts the usual colons. */
217 char *
218 get_fingerprint_hexstring_colon (ksba_cert_t cert)
219 {
220   unsigned char digest[20];
221   gcry_md_hd_t md;
222   int rc;
223   char *buf;
224   int i;
225
226   rc = gcry_md_open (&md, GCRY_MD_SHA1, 0);
227   if (rc)
228     log_fatal (_("gcry_md_open failed: %s\n"), gpg_strerror (rc));
229
230   rc = ksba_cert_hash (cert, 0, HASH_FNC, md);
231   if (rc)
232     {
233       log_error (_("oops: ksba_cert_hash failed: %s\n"), gpg_strerror (rc));
234       memset (digest, 0xff, 20); /* Use a dummy value. */
235     }
236   else
237     {
238       gcry_md_final (md);
239       memcpy (digest, gcry_md_read (md, GCRY_MD_SHA1), 20);
240     }
241   gcry_md_close (md);
242   buf = xmalloc (61);
243   *buf = 0;
244   for (i=0; i < 20; i++ )
245     sprintf (buf+strlen(buf), "%02X:", digest[i]);
246   buf[strlen(buf)-1] = 0; /* Remove railing colon. */
247   return buf;
248 }
249
250
251 /* Dump the serial number SERIALNO to the log stream.  */
252 void
253 dump_serial (ksba_sexp_t serialno)
254 {
255   char *p;
256
257   p = serial_hex (serialno);
258   log_printf ("%s", p?p:"?");
259   xfree (p);
260 }
261
262
263 /* Dump STRING to the log file but choose the best readable
264    format.  */
265 void
266 dump_string (const char *string)
267 {
268
269   if (!string)
270     log_printf ("[error]");
271   else
272     {
273       const unsigned char *s;
274
275       for (s=string; *s; s++)
276         {
277           if (*s < ' ' || (*s >= 0x7f && *s <= 0xa0))
278             break;
279         }
280       if (!*s && *string != '[')
281         log_printf ("%s", string);
282       else
283         {
284           log_printf ( "[ ");
285           log_printhex (NULL, string, strlen (string));
286           log_printf ( " ]");
287         }
288     }
289 }
290
291 /* Dump an KSBA cert object to the log stream. Prefix the output with
292    TEXT.  This is used for debugging. */
293 void
294 dump_cert (const char *text, ksba_cert_t cert)
295 {
296   ksba_sexp_t sexp;
297   char *p;
298   ksba_isotime_t t;
299
300   log_debug ("BEGIN Certificate '%s':\n", text? text:"");
301   if (cert)
302     {
303       sexp = ksba_cert_get_serial (cert);
304       p = serial_hex (sexp);
305       log_debug ("     serial: %s\n", p?p:"?");
306       xfree (p);
307       ksba_free (sexp);
308
309       ksba_cert_get_validity (cert, 0, t);
310       log_debug ("  notBefore: ");
311       dump_isotime (t);
312       log_printf ("\n");
313       ksba_cert_get_validity (cert, 1, t);
314       log_debug ("   notAfter: ");
315       dump_isotime (t);
316       log_printf ("\n");
317
318       p = ksba_cert_get_issuer (cert, 0);
319       log_debug ("     issuer: ");
320       dump_string (p);
321       ksba_free (p);
322       log_printf ("\n");
323
324       p = ksba_cert_get_subject (cert, 0);
325       log_debug ("    subject: ");
326       dump_string (p);
327       ksba_free (p);
328       log_printf ("\n");
329
330       log_debug ("  hash algo: %s\n", ksba_cert_get_digest_algo (cert));
331
332       p = get_fingerprint_hexstring (cert);
333       log_debug ("  SHA1 fingerprint: %s\n", p);
334       xfree (p);
335     }
336   log_debug ("END Certificate\n");
337 }
338
339
340
341 /* Log the certificate's name in "#SN/ISSUERDN" format along with
342    TEXT. */
343 void
344 cert_log_name (const char *text, ksba_cert_t cert)
345 {
346   log_info ("%s", text? text:"certificate" );
347   if (cert)
348     {
349       ksba_sexp_t sn;
350       char *p;
351
352       p = ksba_cert_get_issuer (cert, 0);
353       sn = ksba_cert_get_serial (cert);
354       if (p && sn)
355         {
356           log_printf (" #");
357           dump_serial (sn);
358           log_printf ("/");
359           dump_string (p);
360         }
361       else
362         log_printf (" [invalid]");
363       ksba_free (sn);
364       xfree (p);
365     }
366   log_printf ("\n");
367 }
368
369
370 /* Log the certificate's subject DN along with TEXT. */
371 void
372 cert_log_subject (const char *text, ksba_cert_t cert)
373 {
374   log_info ("%s", text? text:"subject" );
375   if (cert)
376     {
377       char *p;
378
379       p = ksba_cert_get_subject (cert, 0);
380       if (p)
381         {
382           log_printf (" /");
383           dump_string (p);
384           xfree (p);
385         }
386       else
387         log_printf (" [invalid]");
388     }
389   log_printf ("\n");
390 }
391
392
393 /* Callback to print infos about the TLS certificates.  */
394 void
395 cert_log_cb (http_session_t sess, gpg_error_t err,
396              const char *hostname, const void **certs, size_t *certlens)
397 {
398   ksba_cert_t cert;
399   size_t n;
400
401   (void)sess;
402
403   if (!err)
404     return; /* No error - no need to log anything  */
405
406   log_debug ("expected hostname: %s\n", hostname);
407   for (n=0; certs[n]; n++)
408     {
409       err = ksba_cert_new (&cert);
410       if (!err)
411         err = ksba_cert_init_from_mem (cert, certs[n], certlens[n]);
412       if (err)
413         log_error ("error parsing cert for logging: %s\n", gpg_strerror (err));
414       else
415         {
416           char textbuf[20];
417           snprintf (textbuf, sizeof textbuf, "server[%u]", (unsigned int)n);
418           dump_cert (textbuf, cert);
419         }
420
421       ksba_cert_release (cert);
422     }
423 }
424
425
426 /****************
427  * Remove all %xx escapes; this is done inplace.
428  * Returns: New length of the string.
429  */
430 static int
431 remove_percent_escapes (unsigned char *string)
432 {
433   int n = 0;
434   unsigned char *p, *s;
435
436   for (p = s = string; *s; s++)
437     {
438       if (*s == '%')
439         {
440           if (s[1] && s[2] && hexdigitp (s+1) && hexdigitp (s+2))
441             {
442               s++;
443               *p = xtoi_2 (s);
444               s++;
445               p++;
446               n++;
447             }
448           else
449             {
450               *p++ = *s++;
451               if (*s)
452                 *p++ = *s++;
453               if (*s)
454                 *p++ = *s++;
455               if (*s)
456                 *p = 0;
457               return -1;   /* Bad URI. */
458             }
459         }
460       else
461         {
462           *p++ = *s;
463           n++;
464         }
465     }
466   *p = 0;  /* Always keep a string terminator. */
467   return n;
468 }
469
470
471 /* Return the host name and the port (0 if none was given) from the
472    URL.  Return NULL on error or if host is not included in the
473    URL.  */
474 char *
475 host_and_port_from_url (const char *url, int *port)
476 {
477   const char *s, *s2;
478   char *buf, *p;
479   int n;
480
481   s = url;
482
483   *port = 0;
484
485   /* Find the scheme */
486   if ( !(s2 = strchr (s, ':')) || s2 == s )
487     return NULL;  /* No scheme given. */
488   s = s2+1;
489
490   /* Find the hostname */
491   if (*s != '/')
492     return NULL; /* Does not start with a slash. */
493
494   s++;
495   if (*s != '/')
496     return NULL; /* No host name.  */
497   s++;
498
499   buf = xtrystrdup (s);
500   if (!buf)
501     {
502       log_error (_("malloc failed: %s\n"), strerror (errno));
503       return NULL;
504     }
505   if ((p = strchr (buf, '/')))
506     *p++ = 0;
507   strlwr (buf);
508   if ((p = strchr (p, ':')))
509     {
510       *p++ = 0;
511       *port = atoi (p);
512     }
513
514   /* Remove quotes and make sure that no Nul has been encoded. */
515   if ((n = remove_percent_escapes (buf)) < 0
516       || n != strlen (buf) )
517     {
518       log_error (_("bad URL encoding detected\n"));
519       xfree (buf);
520       return NULL;
521     }
522
523   return buf;
524 }
525
526
527 /* A KSBA reader callback to read from an estream.  */
528 static int
529 my_estream_ksba_reader_cb (void *cb_value, char *buffer, size_t count,
530                            size_t *r_nread)
531 {
532   estream_t fp = cb_value;
533
534   if (!fp)
535     return gpg_error (GPG_ERR_INV_VALUE);
536
537   if (!buffer && !count && !r_nread)
538     {
539       es_rewind (fp);
540       return 0;
541     }
542
543   *r_nread = es_fread (buffer, 1, count, fp);
544   if (!*r_nread)
545     return -1; /* EOF or error.  */
546   return 0; /* Success.  */
547 }
548
549
550 /* Create a KSBA reader object and connect it to the estream FP.  */
551 gpg_error_t
552 create_estream_ksba_reader (ksba_reader_t *r_reader, estream_t fp)
553 {
554   gpg_error_t err;
555   ksba_reader_t reader;
556
557   *r_reader = NULL;
558   err = ksba_reader_new (&reader);
559   if (!err)
560     err = ksba_reader_set_cb (reader, my_estream_ksba_reader_cb, fp);
561   if (err)
562     {
563       log_error (_("error initializing reader object: %s\n"),
564                  gpg_strerror (err));
565       ksba_reader_release (reader);
566       return err;
567     }
568   *r_reader = reader;
569   return 0;
570 }
571
572 gpg_error_t
573 armor_data (char **r_string, const void *data, size_t datalen)
574 {
575   gpg_error_t err;
576   struct b64state b64state;
577   estream_t fp;
578   long length;
579   char *buffer;
580   size_t nread;
581
582   *r_string = NULL;
583
584   fp = es_fopenmem (0, "rw,samethread");
585   if (!fp)
586     return gpg_error_from_syserror ();
587
588   if ((err=b64enc_start_es (&b64state, fp, "PGP PUBLIC KEY BLOCK"))
589       || (err=b64enc_write (&b64state, data, datalen))
590       || (err = b64enc_finish (&b64state)))
591     {
592       es_fclose (fp);
593       return err;
594     }
595
596   /* FIXME: To avoid the extra buffer allocation estream should
597      provide a function to snatch the internal allocated memory from
598      such a memory stream.  */
599   length = es_ftell (fp);
600   if (length < 0)
601     {
602       err = gpg_error_from_syserror ();
603       es_fclose (fp);
604       return err;
605     }
606
607   buffer = xtrymalloc (length+1);
608   if (!buffer)
609     {
610       err = gpg_error_from_syserror ();
611       es_fclose (fp);
612       return err;
613     }
614
615   es_rewind (fp);
616   if (es_read (fp, buffer, length, &nread))
617     {
618       err = gpg_error_from_syserror ();
619       es_fclose (fp);
620       return err;
621     }
622   buffer[nread] = 0;
623   es_fclose (fp);
624
625   *r_string = buffer;
626   return 0;
627 }
628
629 /* Copy all data from IN to OUT.  */
630 gpg_error_t
631 copy_stream (estream_t in, estream_t out)
632 {
633   char buffer[512];
634   size_t nread;
635
636   while (!es_read (in, buffer, sizeof buffer, &nread))
637     {
638       if (!nread)
639         return 0; /* EOF */
640       if (es_write (out, buffer, nread, NULL))
641         break;
642
643     }
644   return gpg_error_from_syserror ();
645 }