LCOV - code coverage report
Current view: top level - dirmngr - misc.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 290 0.0 %
Date: 2015-11-05 17:10:59 Functions: 0 21 0.0 %

          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             : }

Generated by: LCOV version 1.11