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