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