Line data Source code
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 0 : unhexify (unsigned char *result, const char *string)
43 : {
44 : const char *s;
45 : size_t n;
46 :
47 0 : for (s=string,n=0; hexdigitp (s) && hexdigitp(s+1); s += 2)
48 : {
49 0 : if (result)
50 0 : result[n] = xtoi_2 (s);
51 0 : n++;
52 : }
53 0 : return n;
54 : }
55 :
56 :
57 : char*
58 0 : hashify_data( const char* data, size_t len )
59 : {
60 : unsigned char buf[20];
61 0 : gcry_md_hash_buffer (GCRY_MD_SHA1, buf, data, len);
62 0 : return hexify_data (buf, 20, 0);
63 : }
64 :
65 : char*
66 0 : hexify_data (const unsigned char* data, size_t len, int with_prefix)
67 : {
68 : int i;
69 0 : char *result = xmalloc (2*len + (with_prefix?2:0) + 1);
70 : char *p;
71 :
72 0 : if (with_prefix)
73 0 : p = stpcpy (result, "0x");
74 : else
75 0 : p = result;
76 :
77 0 : for (i = 0; i < 2*len; i+=2 )
78 0 : snprintf (p+i, 3, "%02X", *data++);
79 0 : return result;
80 : }
81 :
82 : char *
83 0 : serial_hex (ksba_sexp_t serial )
84 : {
85 0 : unsigned char* p = serial;
86 : char *endp;
87 : unsigned long n;
88 : char *certid;
89 :
90 0 : if (!p)
91 0 : return NULL;
92 : else {
93 0 : p++; /* ignore initial '(' */
94 0 : n = strtoul (p, (char**)&endp, 10);
95 0 : p = endp;
96 0 : if (*p!=':')
97 0 : return NULL;
98 : else {
99 0 : int i = 0;
100 0 : certid = xmalloc( sizeof( char )*(2*n + 1 ) );
101 0 : for (p++; n; n--, p++) {
102 0 : sprintf ( certid+i , "%02X", *p);
103 0 : i += 2;
104 : }
105 : }
106 : }
107 0 : 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 0 : serial_to_buffer (const ksba_sexp_t serial, size_t *length)
116 : {
117 0 : unsigned char *p = serial;
118 : char *endp;
119 : unsigned long n;
120 :
121 0 : if (!p || *p != '(')
122 0 : return NULL;
123 0 : p++;
124 0 : n = strtoul (p, &endp, 10);
125 0 : p = endp;
126 0 : if (*p != ':')
127 0 : return NULL;
128 0 : p++;
129 0 : *length = n;
130 0 : 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 0 : unpercent_string (char *string)
138 : {
139 0 : char *s = string;
140 0 : char *d = string;
141 :
142 0 : while (*s)
143 : {
144 0 : if (*s == '%' && s[1] && s[2])
145 : {
146 0 : s++;
147 0 : *d++ = xtoi_2 ( s);
148 0 : s += 2;
149 : }
150 : else
151 0 : *d++ = *s++;
152 : }
153 0 : *d = 0;
154 0 : return string;
155 : }
156 :
157 : /* Convert a canonical encoded S-expression in CANON into the GCRY
158 : type. */
159 : gpg_error_t
160 0 : 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 0 : *r_sexp = NULL;
167 0 : n = gcry_sexp_canon_len (canon, 0, NULL, NULL);
168 0 : if (!n)
169 : {
170 0 : log_error (_("invalid canonical S-expression found\n"));
171 0 : err = gpg_error (GPG_ERR_INV_SEXP);
172 : }
173 0 : else if ((err = gcry_sexp_sscan (&sexp, NULL, canon, n)))
174 0 : log_error (_("converting S-expression failed: %s\n"), gcry_strerror (err));
175 : else
176 0 : *r_sexp = sexp;
177 0 : return err;
178 : }
179 :
180 :
181 : /* Return an allocated buffer with the formatted fingerprint as one
182 : large hexnumber */
183 : char *
184 0 : 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 0 : rc = gcry_md_open (&md, GCRY_MD_SHA1, 0);
193 0 : if (rc)
194 0 : log_fatal (_("gcry_md_open failed: %s\n"), gpg_strerror (rc));
195 :
196 0 : rc = ksba_cert_hash (cert, 0, HASH_FNC, md);
197 0 : if (rc)
198 : {
199 0 : log_error (_("oops: ksba_cert_hash failed: %s\n"), gpg_strerror (rc));
200 0 : memset (digest, 0xff, 20); /* Use a dummy value. */
201 : }
202 : else
203 : {
204 0 : gcry_md_final (md);
205 0 : memcpy (digest, gcry_md_read (md, GCRY_MD_SHA1), 20);
206 : }
207 0 : gcry_md_close (md);
208 0 : buf = xmalloc (41);
209 0 : *buf = 0;
210 0 : for (i=0; i < 20; i++ )
211 0 : sprintf (buf+strlen(buf), "%02X", digest[i]);
212 0 : 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 0 : 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 0 : rc = gcry_md_open (&md, GCRY_MD_SHA1, 0);
227 0 : if (rc)
228 0 : log_fatal (_("gcry_md_open failed: %s\n"), gpg_strerror (rc));
229 :
230 0 : rc = ksba_cert_hash (cert, 0, HASH_FNC, md);
231 0 : if (rc)
232 : {
233 0 : log_error (_("oops: ksba_cert_hash failed: %s\n"), gpg_strerror (rc));
234 0 : memset (digest, 0xff, 20); /* Use a dummy value. */
235 : }
236 : else
237 : {
238 0 : gcry_md_final (md);
239 0 : memcpy (digest, gcry_md_read (md, GCRY_MD_SHA1), 20);
240 : }
241 0 : gcry_md_close (md);
242 0 : buf = xmalloc (61);
243 0 : *buf = 0;
244 0 : for (i=0; i < 20; i++ )
245 0 : sprintf (buf+strlen(buf), "%02X:", digest[i]);
246 0 : buf[strlen(buf)-1] = 0; /* Remove railing colon. */
247 0 : return buf;
248 : }
249 :
250 :
251 : /* Dump the serial number SERIALNO to the log stream. */
252 : void
253 0 : dump_serial (ksba_sexp_t serialno)
254 : {
255 : char *p;
256 :
257 0 : p = serial_hex (serialno);
258 0 : log_printf ("%s", p?p:"?");
259 0 : xfree (p);
260 0 : }
261 :
262 :
263 : /* Dump STRING to the log file but choose the best readable
264 : format. */
265 : void
266 0 : dump_string (const char *string)
267 : {
268 :
269 0 : if (!string)
270 0 : log_printf ("[error]");
271 : else
272 : {
273 : const unsigned char *s;
274 :
275 0 : for (s=string; *s; s++)
276 : {
277 0 : if (*s < ' ' || (*s >= 0x7f && *s <= 0xa0))
278 : break;
279 : }
280 0 : if (!*s && *string != '[')
281 0 : log_printf ("%s", string);
282 : else
283 : {
284 0 : log_printf ( "[ ");
285 0 : log_printhex (NULL, string, strlen (string));
286 0 : log_printf ( " ]");
287 : }
288 : }
289 0 : }
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 0 : 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 0 : log_debug ("BEGIN Certificate '%s':\n", text? text:"");
301 0 : if (cert)
302 : {
303 0 : sexp = ksba_cert_get_serial (cert);
304 0 : p = serial_hex (sexp);
305 0 : log_debug (" serial: %s\n", p?p:"?");
306 0 : xfree (p);
307 0 : ksba_free (sexp);
308 :
309 0 : ksba_cert_get_validity (cert, 0, t);
310 0 : log_debug (" notBefore: ");
311 0 : dump_isotime (t);
312 0 : log_printf ("\n");
313 0 : ksba_cert_get_validity (cert, 1, t);
314 0 : log_debug (" notAfter: ");
315 0 : dump_isotime (t);
316 0 : log_printf ("\n");
317 :
318 0 : p = ksba_cert_get_issuer (cert, 0);
319 0 : log_debug (" issuer: ");
320 0 : dump_string (p);
321 0 : ksba_free (p);
322 0 : log_printf ("\n");
323 :
324 0 : p = ksba_cert_get_subject (cert, 0);
325 0 : log_debug (" subject: ");
326 0 : dump_string (p);
327 0 : ksba_free (p);
328 0 : log_printf ("\n");
329 :
330 0 : log_debug (" hash algo: %s\n", ksba_cert_get_digest_algo (cert));
331 :
332 0 : p = get_fingerprint_hexstring (cert);
333 0 : log_debug (" SHA1 fingerprint: %s\n", p);
334 0 : xfree (p);
335 : }
336 0 : log_debug ("END Certificate\n");
337 0 : }
338 :
339 :
340 :
341 : /* Log the certificate's name in "#SN/ISSUERDN" format along with
342 : TEXT. */
343 : void
344 0 : cert_log_name (const char *text, ksba_cert_t cert)
345 : {
346 0 : log_info ("%s", text? text:"certificate" );
347 0 : if (cert)
348 : {
349 : ksba_sexp_t sn;
350 : char *p;
351 :
352 0 : p = ksba_cert_get_issuer (cert, 0);
353 0 : sn = ksba_cert_get_serial (cert);
354 0 : if (p && sn)
355 : {
356 0 : log_printf (" #");
357 0 : dump_serial (sn);
358 0 : log_printf ("/");
359 0 : dump_string (p);
360 : }
361 : else
362 0 : log_printf (" [invalid]");
363 0 : ksba_free (sn);
364 0 : xfree (p);
365 : }
366 0 : log_printf ("\n");
367 0 : }
368 :
369 :
370 : /* Log the certificate's subject DN along with TEXT. */
371 : void
372 0 : cert_log_subject (const char *text, ksba_cert_t cert)
373 : {
374 0 : log_info ("%s", text? text:"subject" );
375 0 : if (cert)
376 : {
377 : char *p;
378 :
379 0 : p = ksba_cert_get_subject (cert, 0);
380 0 : if (p)
381 : {
382 0 : log_printf (" /");
383 0 : dump_string (p);
384 0 : xfree (p);
385 : }
386 : else
387 0 : log_printf (" [invalid]");
388 : }
389 0 : log_printf ("\n");
390 0 : }
391 :
392 :
393 : /* Callback to print infos about the TLS certificates. */
394 : void
395 0 : 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 0 : if (!err)
404 0 : return; /* No error - no need to log anything */
405 :
406 0 : log_debug ("expected hostname: %s\n", hostname);
407 0 : for (n=0; certs[n]; n++)
408 : {
409 0 : err = ksba_cert_new (&cert);
410 0 : if (!err)
411 0 : err = ksba_cert_init_from_mem (cert, certs[n], certlens[n]);
412 0 : if (err)
413 0 : log_error ("error parsing cert for logging: %s\n", gpg_strerror (err));
414 : else
415 : {
416 : char textbuf[20];
417 0 : snprintf (textbuf, sizeof textbuf, "server[%u]", (unsigned int)n);
418 0 : dump_cert (textbuf, cert);
419 : }
420 :
421 0 : 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 0 : remove_percent_escapes (unsigned char *string)
432 : {
433 0 : int n = 0;
434 : unsigned char *p, *s;
435 :
436 0 : for (p = s = string; *s; s++)
437 : {
438 0 : if (*s == '%')
439 : {
440 0 : if (s[1] && s[2] && hexdigitp (s+1) && hexdigitp (s+2))
441 : {
442 0 : s++;
443 0 : *p = xtoi_2 (s);
444 0 : s++;
445 0 : p++;
446 0 : n++;
447 : }
448 : else
449 : {
450 0 : *p++ = *s++;
451 0 : if (*s)
452 0 : *p++ = *s++;
453 0 : if (*s)
454 0 : *p++ = *s++;
455 0 : if (*s)
456 0 : *p = 0;
457 0 : return -1; /* Bad URI. */
458 : }
459 : }
460 : else
461 : {
462 0 : *p++ = *s;
463 0 : n++;
464 : }
465 : }
466 0 : *p = 0; /* Always keep a string terminator. */
467 0 : 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 0 : 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 0 : s = url;
482 :
483 0 : *port = 0;
484 :
485 : /* Find the scheme */
486 0 : if ( !(s2 = strchr (s, ':')) || s2 == s )
487 0 : return NULL; /* No scheme given. */
488 0 : s = s2+1;
489 :
490 : /* Find the hostname */
491 0 : if (*s != '/')
492 0 : return NULL; /* Does not start with a slash. */
493 :
494 0 : s++;
495 0 : if (*s != '/')
496 0 : return NULL; /* No host name. */
497 0 : s++;
498 :
499 0 : buf = xtrystrdup (s);
500 0 : if (!buf)
501 : {
502 0 : log_error (_("malloc failed: %s\n"), strerror (errno));
503 0 : return NULL;
504 : }
505 0 : if ((p = strchr (buf, '/')))
506 0 : *p++ = 0;
507 0 : strlwr (buf);
508 0 : if ((p = strchr (p, ':')))
509 : {
510 0 : *p++ = 0;
511 0 : *port = atoi (p);
512 : }
513 :
514 : /* Remove quotes and make sure that no Nul has been encoded. */
515 0 : if ((n = remove_percent_escapes (buf)) < 0
516 0 : || n != strlen (buf) )
517 : {
518 0 : log_error (_("bad URL encoding detected\n"));
519 0 : xfree (buf);
520 0 : return NULL;
521 : }
522 :
523 0 : return buf;
524 : }
525 :
526 :
527 : /* A KSBA reader callback to read from an estream. */
528 : static int
529 0 : my_estream_ksba_reader_cb (void *cb_value, char *buffer, size_t count,
530 : size_t *r_nread)
531 : {
532 0 : estream_t fp = cb_value;
533 :
534 0 : if (!fp)
535 0 : return gpg_error (GPG_ERR_INV_VALUE);
536 :
537 0 : if (!buffer && !count && !r_nread)
538 : {
539 0 : es_rewind (fp);
540 0 : return 0;
541 : }
542 :
543 0 : *r_nread = es_fread (buffer, 1, count, fp);
544 0 : if (!*r_nread)
545 0 : return -1; /* EOF or error. */
546 0 : return 0; /* Success. */
547 : }
548 :
549 :
550 : /* Create a KSBA reader object and connect it to the estream FP. */
551 : gpg_error_t
552 0 : 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 0 : *r_reader = NULL;
558 0 : err = ksba_reader_new (&reader);
559 0 : if (!err)
560 0 : err = ksba_reader_set_cb (reader, my_estream_ksba_reader_cb, fp);
561 0 : if (err)
562 : {
563 0 : log_error (_("error initializing reader object: %s\n"),
564 : gpg_strerror (err));
565 0 : ksba_reader_release (reader);
566 0 : return err;
567 : }
568 0 : *r_reader = reader;
569 0 : return 0;
570 : }
571 :
572 : gpg_error_t
573 0 : 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 0 : *r_string = NULL;
583 :
584 0 : fp = es_fopenmem (0, "rw,samethread");
585 0 : if (!fp)
586 0 : return gpg_error_from_syserror ();
587 :
588 0 : if ((err=b64enc_start_es (&b64state, fp, "PGP PUBLIC KEY BLOCK"))
589 0 : || (err=b64enc_write (&b64state, data, datalen))
590 0 : || (err = b64enc_finish (&b64state)))
591 : {
592 0 : es_fclose (fp);
593 0 : 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 0 : length = es_ftell (fp);
600 0 : if (length < 0)
601 : {
602 0 : err = gpg_error_from_syserror ();
603 0 : es_fclose (fp);
604 0 : return err;
605 : }
606 :
607 0 : buffer = xtrymalloc (length+1);
608 0 : if (!buffer)
609 : {
610 0 : err = gpg_error_from_syserror ();
611 0 : es_fclose (fp);
612 0 : return err;
613 : }
614 :
615 0 : es_rewind (fp);
616 0 : if (es_read (fp, buffer, length, &nread))
617 : {
618 0 : err = gpg_error_from_syserror ();
619 0 : es_fclose (fp);
620 0 : return err;
621 : }
622 0 : buffer[nread] = 0;
623 0 : es_fclose (fp);
624 :
625 0 : *r_string = buffer;
626 0 : return 0;
627 : }
628 :
629 : /* Copy all data from IN to OUT. */
630 : gpg_error_t
631 0 : copy_stream (estream_t in, estream_t out)
632 : {
633 : char buffer[512];
634 : size_t nread;
635 :
636 0 : while (!es_read (in, buffer, sizeof buffer, &nread))
637 : {
638 0 : if (!nread)
639 0 : return 0; /* EOF */
640 0 : if (es_write (out, buffer, nread, NULL))
641 0 : break;
642 :
643 : }
644 0 : return gpg_error_from_syserror ();
645 : }
|