LCOV - code coverage report
Current view: top level - dirmngr - misc.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 293 0.0 %
Date: 2016-11-29 15:00:56 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 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             : }

Generated by: LCOV version 1.11