1 /* misc.c - miscellaneous
2 * Copyright (C) 2002 Klarälvdalens Datakonsult AB
3 * Copyright (C) 2002, 2003, 2004 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 "util.h"
30 #include "misc.h"
31 #include "dirmngr.h"
32
33 static unsigned long timewarp;
34 static enum { NORMAL = 0, FROZEN, FUTURE, PAST } timemode;
35
36 /* Wrapper for the time(3). We use this here so we can fake the time
37 for tests. */
38 time_t
get_time()39 get_time ()
40 {
41 time_t current = time (NULL);
42 if (timemode == NORMAL)
43 return current;
44 else if (timemode == FROZEN)
45 return timewarp;
46 else if (timemode == FUTURE)
47 return current + timewarp;
48 else
49 return current - timewarp;
50 }
51
52
53
54 /* Return the current time in ISO format. */
55 void
get_isotime(dirmngr_isotime_t timebuf)56 get_isotime (dirmngr_isotime_t timebuf)
57 {
58 time_t atime = get_time ();
59
60 if (atime < 0)
61 *timebuf = 0;
62 else
63 {
64 struct tm *tp;
65 #ifdef HAVE_GMTIME_R
66 struct tm tmbuf;
67
68 tp = gmtime_r (&atime, &tmbuf);
69 #else
70 tp = gmtime (&atime);
71 #endif
72 sprintf (timebuf,"%04d%02d%02dT%02d%02d%02d",
73 1900 + tp->tm_year, tp->tm_mon+1, tp->tm_mday,
74 tp->tm_hour, tp->tm_min, tp->tm_sec);
75 }
76 }
77
78
79 /* Set the time to NEWTIME so that get_time returns a time starting
80 with this one. With FREEZE set to 1 the returned time will never
81 change. Just for completeness, a value of (time_t)-1 for NEWTIME
82 gets you back to reality. Note that this is obviously not
83 thread-safe but this is not required. */
84 void
set_time(time_t newtime,int freeze)85 set_time (time_t newtime, int freeze)
86 {
87 time_t current = time (NULL);
88
89 if ( newtime == (time_t)-1 || current == newtime)
90 {
91 timemode = NORMAL;
92 timewarp = 0;
93 }
94 else if (freeze)
95 {
96 timemode = FROZEN;
97 timewarp = current;
98 }
99 else if (newtime > current)
100 {
101 timemode = FUTURE;
102 timewarp = newtime - current;
103 }
104 else
105 {
106 timemode = PAST;
107 timewarp = current - newtime;
108 }
109 }
110
111 /* Returns true when we are in timewarp mode. */
112 int
faked_time_p(void)113 faked_time_p (void)
114 {
115 return timemode;
116 }
117
118
119
120
121 /* Check that the 15 bytes in ATIME represent a valid ISO time. Note
122 that this function does not expect a string but a plain 15 byte
123 isotime buffer. */
124 gpg_error_t
check_isotime(const dirmngr_isotime_t atime)125 check_isotime (const dirmngr_isotime_t atime)
126 {
127 int i;
128 const char *s;
129
130 if (!*atime)
131 return gpg_error (GPG_ERR_NO_VALUE);
132
133 for (s=atime, i=0; i < 8; i++, s++)
134 if (!digitp (s))
135 return gpg_error (GPG_ERR_INV_TIME);
136 if (*s != 'T')
137 return gpg_error (GPG_ERR_INV_TIME);
138 for (s++, i=9; i < 15; i++, s++)
139 if (!digitp (s))
140 return gpg_error (GPG_ERR_INV_TIME);
141 return 0;
142 }
143
144
145 /* Correction used to map to real Julian days. */
146 #define JD_DIFF 1721060L
147
148 static int
days_per_year(int y)149 days_per_year (int y)
150 {
151 int s ;
152
153 s = !(y % 4);
154 if ( !(y % 100))
155 if ((y%400))
156 s = 0;
157 return s ? 366 : 365;
158 }
159
160 static int
days_per_month(int y,int m)161 days_per_month (int y, int m)
162 {
163 int s;
164
165 switch(m)
166 {
167 case 1: case 3: case 5: case 7: case 8: case 10: case 12:
168 return 31 ;
169 case 2:
170 s = !(y % 4);
171 if (!(y % 100))
172 if ((y % 400))
173 s = 0;
174 return s? 29 : 28 ;
175 case 4: case 6: case 9: case 11:
176 return 30;
177 }
178 BUG();
179 }
180
181
182 /* Convert YEAR, MONTH and DAY into the Julian date. We assume that
183 it is already noon; we dont; support dates before 1582-10-15. */
184 static unsigned long
date2jd(int year,int month,int day)185 date2jd (int year, int month, int day)
186 {
187 unsigned long jd;
188
189 jd = 365L * year + 31 * (month-1) + day + JD_DIFF;
190 if (month < 3)
191 year-- ;
192 else
193 jd -= (4 * month + 23) / 10;
194
195 jd += year / 4 - ((year / 100 + 1) *3) / 4;
196
197 return jd ;
198 }
199
200 /* Convert a Julian date back to YEAR, MONTH and DAY. Return day of
201 the year or 0 on error. This function uses some more or less
202 arbitrary limits, most important is that days before 1582 are not
203 supported. */
204 static int
jd2date(unsigned long jd,int * year,int * month,int * day)205 jd2date (unsigned long jd, int *year, int *month, int *day)
206 {
207 int y, m, d;
208 long delta;
209
210 if (!jd)
211 return 0 ;
212 if (jd < 1721425 || jd > 2843085)
213 return 0;
214
215 y = (jd - JD_DIFF) / 366;
216 d = m = 1;
217
218 while ((delta = jd - date2jd (y, m, d)) > days_per_year (y))
219 y++;
220
221 m = (delta / 31) + 1;
222 while( (delta = jd - date2jd (y, m, d)) > days_per_month (y,m))
223 if (++m > 12)
224 {
225 m = 1;
226 y++;
227 }
228
229 d = delta + 1 ;
230 if (d > days_per_month (y, m))
231 {
232 d = 1;
233 m++;
234 }
235 if (m > 12)
236 {
237 m = 1;
238 y++;
239 }
240
241 if (year)
242 *year = y;
243 if (month)
244 *month = m;
245 if (day)
246 *day = d ;
247
248 return (jd - date2jd (y, 1, 1)) + 1;
249 }
250
251
252
253
254 /* Add SECONDS to ATIME. SECONDS may not be negative and is limited
255 to about the equivalent of 62 years which should be more then
256 enough for our purposes. */
257 gpg_error_t
add_isotime(dirmngr_isotime_t atime,int seconds)258 add_isotime (dirmngr_isotime_t atime, int seconds )
259 {
260 gpg_error_t err;
261 int year, month, day, hour, minute, sec, ndays;
262 unsigned long jd;
263
264 err = check_isotime (atime);
265 if (err)
266 return err;
267
268 if (seconds < 0 || seconds >= (0x7fffffff - 61) )
269 return gpg_error (GPG_ERR_INV_VALUE);
270
271 year = atoi_4 (atime+0);
272 month = atoi_2 (atime+4);
273 day = atoi_2 (atime+6);
274 hour = atoi_2 (atime+9);
275 minute= atoi_2 (atime+11);
276 sec = atoi_2 (atime+13);
277
278 if (year <= 1582) /* The julian date functions don't support this. */
279 return gpg_error (GPG_ERR_INV_VALUE);
280
281 sec += seconds;
282 minute += sec/60;
283 sec %= 60;
284 hour += minute/60;
285 minute %= 60;
286 ndays = hour/24;
287 hour %= 24;
288
289 jd = date2jd (year, month, day) + ndays;
290 jd2date (jd, &year, &month, &day);
291
292 if (year > 9999 || month > 12 || day > 31
293 || year < 0 || month < 1 || day < 1)
294 return gpg_error (GPG_ERR_INV_VALUE);
295
296 sprintf (atime, "%04d%02d%02dT%02d%02d%02d",
297 year, month, day, hour, minute, sec);
298 return 0;
299 }
300
301
302
303
304 /* Convert the hex encoded STRING back into binary and store the
305 result into the provided buffer RESULT. The actual size of that
306 buffer will be returned. The caller should provide RESULT of at
307 least strlen(STRING)/2 bytes. There is no error detection, the
308 parsing stops at the first non hex character. With RESULT given as
309 NULL, the fucntion does only return the size of the buffer which
310 would be needed. */
311 size_t
unhexify(unsigned char * result,const char * string)312 unhexify (unsigned char *result, const char *string)
313 {
314 const char *s;
315 size_t n;
316
317 for (s=string,n=0; hexdigitp (s) && hexdigitp(s+1); s += 2)
318 {
319 if (result)
320 result[n] = xtoi_2 (s);
321 n++;
322 }
323 return n;
324 }
325
326
327 char*
hashify_data(const char * data,size_t len)328 hashify_data( const char* data, size_t len )
329 {
330 unsigned char buf[20];
331 gcry_md_hash_buffer (GCRY_MD_SHA1, buf, data, len);
332 return hexify_data( buf, 20 );
333 }
334
335 char*
hexify_data(const unsigned char * data,size_t len)336 hexify_data( const unsigned char* data, size_t len )
337 {
338 int i;
339 char* result = xmalloc( sizeof( char ) * (2*len+1));
340
341 for( i = 0; i < 2*len; i+=2 )
342 sprintf( result+i, "%02X", *data++);
343 return result;
344 }
345
346 char *
serial_hex(ksba_sexp_t serial)347 serial_hex (ksba_sexp_t serial )
348 {
349 unsigned char* p = serial;
350 char *endp;
351 unsigned long n;
352 char *certid;
353
354 if (!p)
355 return NULL;
356 else {
357 p++; /* ignore initial '(' */
358 n = strtoul (p, (char**)&endp, 10);
359 p = endp;
360 if (*p!=':')
361 return NULL;
362 else {
363 int i = 0;
364 certid = xmalloc( sizeof( char )*(2*n + 1 ) );
365 for (p++; n; n--, p++) {
366 sprintf ( certid+i , "%02X", *p);
367 i += 2;
368 }
369 }
370 }
371 return certid;
372 }
373
374
375 /* Take an S-Expression encoded blob and return a pointer to the
376 actual data as well as its length. Return NULL for an invalid
377 S-Expression.*/
378 const unsigned char *
serial_to_buffer(const ksba_sexp_t serial,size_t * length)379 serial_to_buffer (const ksba_sexp_t serial, size_t *length)
380 {
381 unsigned char *p = serial;
382 char *endp;
383 unsigned long n;
384
385 if (!p || *p != '(')
386 return NULL;
387 p++;
388 n = strtoul (p, &endp, 10);
389 p = endp;
390 if (*p != ':')
391 return NULL;
392 p++;
393 *length = n;
394 return p;
395 }
396
397
398 /* Do an in-place percent unescaping of STRING. Returns STRING. Noet
399 that this function does not do a '+'-to-space unescaping.*/
400 char *
unpercent_string(char * string)401 unpercent_string (char *string)
402 {
403 char *s = string;
404 char *d = string;
405
406 while (*s)
407 {
408 if (*s == '%' && s[1] && s[2])
409 {
410 s++;
411 *d++ = xtoi_2 ( s);
412 s += 2;
413 }
414 else
415 *d++ = *s++;
416 }
417 *d = 0;
418 return string;
419 }
420
421 /* Convert a canonical encoded S-expression in CANON into the GCRY
422 type. */
423 gpg_error_t
canon_sexp_to_gcry(const unsigned char * canon,gcry_sexp_t * r_sexp)424 canon_sexp_to_gcry (const unsigned char *canon, gcry_sexp_t *r_sexp)
425 {
426 gpg_error_t err;
427 size_t n;
428 gcry_sexp_t sexp;
429
430 *r_sexp = NULL;
431 n = gcry_sexp_canon_len (canon, 0, NULL, NULL);
432 if (!n)
433 {
434 log_error (_("invalid canonical S-expression found\n"));
435 err = gpg_error (GPG_ERR_INV_SEXP);
436 }
437 else if ((err = gcry_sexp_sscan (&sexp, NULL, canon, n)))
438 log_error (_("converting S-expression failed: %s\n"), gcry_strerror (err));
439 else
440 *r_sexp = sexp;
441 return err;
442 }
443
444
445 /* Return an allocated buffer with the formatted fingerprint as one
446 large hexnumber */
447 char *
get_fingerprint_hexstring(ksba_cert_t cert)448 get_fingerprint_hexstring (ksba_cert_t cert)
449 {
450 unsigned char digest[20];
451 gcry_md_hd_t md;
452 int rc;
453 char *buf;
454 int i;
455
456 rc = gcry_md_open (&md, GCRY_MD_SHA1, 0);
457 if (rc)
458 log_fatal (_("gcry_md_open failed: %s\n"), gpg_strerror (rc));
459
460 rc = ksba_cert_hash (cert, 0, HASH_FNC, md);
461 if (rc)
462 {
463 log_error (_("oops: ksba_cert_hash failed: %s\n"), gpg_strerror (rc));
464 memset (digest, 0xff, 20); /* Use a dummy value. */
465 }
466 else
467 {
468 gcry_md_final (md);
469 memcpy (digest, gcry_md_read (md, GCRY_MD_SHA1), 20);
470 }
471 gcry_md_close (md);
472 buf = xmalloc (41);
473 *buf = 0;
474 for (i=0; i < 20; i++ )
475 sprintf (buf+strlen(buf), "%02X", digest[i]);
476 return buf;
477 }
478
479 /* Return an allocated buffer with the formatted fingerprint as one
480 large hexnumber. This version inserts the usual colons. */
481 char *
get_fingerprint_hexstring_colon(ksba_cert_t cert)482 get_fingerprint_hexstring_colon (ksba_cert_t cert)
483 {
484 unsigned char digest[20];
485 gcry_md_hd_t md;
486 int rc;
487 char *buf;
488 int i;
489
490 rc = gcry_md_open (&md, GCRY_MD_SHA1, 0);
491 if (rc)
492 log_fatal (_("gcry_md_open failed: %s\n"), gpg_strerror (rc));
493
494 rc = ksba_cert_hash (cert, 0, HASH_FNC, md);
495 if (rc)
496 {
497 log_error (_("oops: ksba_cert_hash failed: %s\n"), gpg_strerror (rc));
498 memset (digest, 0xff, 20); /* Use a dummy value. */
499 }
500 else
501 {
502 gcry_md_final (md);
503 memcpy (digest, gcry_md_read (md, GCRY_MD_SHA1), 20);
504 }
505 gcry_md_close (md);
506 buf = xmalloc (61);
507 *buf = 0;
508 for (i=0; i < 20; i++ )
509 sprintf (buf+strlen(buf), "%02X:", digest[i]);
510 buf[strlen(buf)-1] = 0; /* Remove railing colon. */
511 return buf;
512 }
513
514
515 /* Dump the serial number SERIALNO to the log stream. */
516 void
dump_serial(ksba_sexp_t serialno)517 dump_serial (ksba_sexp_t serialno)
518 {
519 char *p;
520
521 p = serial_hex (serialno);
522 log_printf ("%s", p?p:"?");
523 xfree (p);
524 }
525
526
527 /* Dump the ISO time T to the log stream without a LF. */
528 void
dump_isotime(dirmngr_isotime_t t)529 dump_isotime (dirmngr_isotime_t t)
530 {
531 if (!t || !*t)
532 log_printf (_("[none]"));
533 else
534 log_printf ("%.4s-%.2s-%.2s %.2s:%.2s:%s",
535 t, t+4, t+6, t+9, t+11, t+13);
536 }
537
538
539 /* Dump STRING to the log file but choose the best readable
540 format. */
541 void
dump_string(const char * string)542 dump_string (const char *string)
543 {
544
545 if (!string)
546 log_printf ("[error]");
547 else
548 {
549 const unsigned char *s;
550
551 for (s=string; *s; s++)
552 {
553 if (*s < ' ' || (*s >= 0x7f && *s <= 0xa0))
554 break;
555 }
556 if (!*s && *string != '[')
557 log_printf ("%s", string);
558 else
559 {
560 log_printf ( "[ ");
561 log_printhex (NULL, string, strlen (string));
562 log_printf ( " ]");
563 }
564 }
565 }
566
567 /* Dump an KSBA cert object to the log stream. Prefix the output with
568 TEXT. This is used for debugging. */
569 void
dump_cert(const char * text,ksba_cert_t cert)570 dump_cert (const char *text, ksba_cert_t cert)
571 {
572 ksba_sexp_t sexp;
573 char *p;
574 ksba_isotime_t t;
575
576 log_debug ("BEGIN Certificate `%s':\n", text? text:"");
577 if (cert)
578 {
579 sexp = ksba_cert_get_serial (cert);
580 p = serial_hex (sexp);
581 log_debug (" serial: %s\n", p?p:"?");
582 xfree (p);
583 ksba_free (sexp);
584
585 ksba_cert_get_validity (cert, 0, t);
586 log_debug (" notBefore: ");
587 dump_isotime (t);
588 log_printf ("\n");
589 ksba_cert_get_validity (cert, 1, t);
590 log_debug (" notAfter: ");
591 dump_isotime (t);
592 log_printf ("\n");
593
594 p = ksba_cert_get_issuer (cert, 0);
595 log_debug (" issuer: ");
596 dump_string (p);
597 ksba_free (p);
598 log_printf ("\n");
599
600 p = ksba_cert_get_subject (cert, 0);
601 log_debug (" subject: ");
602 dump_string (p);
603 ksba_free (p);
604 log_printf ("\n");
605
606 log_debug (" hash algo: %s\n", ksba_cert_get_digest_algo (cert));
607
608 p = get_fingerprint_hexstring (cert);
609 log_debug (" SHA1 fingerprint: %s\n", p);
610 xfree (p);
611 }
612 log_debug ("END Certificate\n");
613 }
614
615
616
617 /* Log the certificate's name in "#SN/ISSUERDN" format along with
618 TEXT. */
619 void
cert_log_name(const char * text,ksba_cert_t cert)620 cert_log_name (const char *text, ksba_cert_t cert)
621 {
622 log_info ("%s", text? text:"certificate" );
623 if (cert)
624 {
625 ksba_sexp_t sn;
626 char *p;
627
628 p = ksba_cert_get_issuer (cert, 0);
629 sn = ksba_cert_get_serial (cert);
630 if (p && sn)
631 {
632 log_printf (" #");
633 dump_serial (sn);
634 log_printf ("/");
635 dump_string (p);
636 }
637 else
638 log_printf (" [invalid]");
639 ksba_free (sn);
640 xfree (p);
641 }
642 log_printf ("\n");
643 }
644
645
646 /* Log the certificate's subject DN along with TEXT. */
647 void
cert_log_subject(const char * text,ksba_cert_t cert)648 cert_log_subject (const char *text, ksba_cert_t cert)
649 {
650 log_info ("%s", text? text:"subject" );
651 if (cert)
652 {
653 char *p;
654
655 p = ksba_cert_get_subject (cert, 0);
656 if (p)
657 {
658 log_printf (" /");
659 dump_string (p);
660 xfree (p);
661 }
662 else
663 log_printf (" [invalid]");
664 }
665 log_printf ("\n");
666 }
667
668
669 /****************
670 * Remove all %xx escapes; this is done inplace.
671 * Returns: New length of the string.
672 */
673 static int
remove_percent_escapes(unsigned char * string)674 remove_percent_escapes (unsigned char *string)
675 {
676 int n = 0;
677 unsigned char *p, *s;
678
679 for (p = s = string; *s; s++)
680 {
681 if (*s == '%')
682 {
683 if (s[1] && s[2] && hexdigitp (s+1) && hexdigitp (s+2))
684 {
685 s++;
686 *p = xtoi_2 (s);
687 s++;
688 p++;
689 n++;
690 }
691 else
692 {
693 *p++ = *s++;
694 if (*s)
695 *p++ = *s++;
696 if (*s)
697 *p++ = *s++;
698 if (*s)
699 *p = 0;
700 return -1; /* Bad URI. */
701 }
702 }
703 else
704 {
705 *p++ = *s;
706 n++;
707 }
708 }
709 *p = 0; /* Always keep a string terminator. */
710 return n;
711 }
712
713
714 /* Return the host name and the port (0 if none was given) from the
715 URL. Return NULL on error or if host is not included in the
716 URL. */
717 char *
host_and_port_from_url(const char * url,int * port)718 host_and_port_from_url (const char *url, int *port)
719 {
720 const char *s, *s2;
721 char *buf, *p;
722 int n;
723
724 s = url;
725
726 *port = 0;
727
728 /* Find the scheme */
729 if ( !(s2 = strchr (s, ':')) || s2 == s )
730 return NULL; /* No scheme given. */
731 s = s2+1;
732
733 /* Find the hostname */
734 if (*s != '/')
735 return NULL; /* Does not start with a slash. */
736
737 s++;
738 if (*s != '/')
739 return NULL; /* No host name. */
740 s++;
741
742 buf = xtrystrdup (s);
743 if (!buf)
744 {
745 log_error (_("malloc failed: %s\n"), strerror (errno));
746 return NULL;
747 }
748 if ((p = strchr (buf, '/')))
749 *p++ = 0;
750 strlwr (buf);
751 if ((p = strchr (p, ':')))
752 {
753 *p++ = 0;
754 *port = atoi (p);
755 }
756
757 /* Remove quotes and make sure that no Nul has been encoded. */
758 if ((n = remove_percent_escapes (buf)) < 0
759 || n != strlen (buf) )
760 {
761 log_error (_("bad URL encoding detected\n"));
762 xfree (buf);
763 return NULL;
764 }
765
766 return buf;
767 }
768
769