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

          Line data    Source code
       1             : /* crlfetch.c - LDAP access
       2             :  *      Copyright (C) 2002 Klarälvdalens Datakonsult AB
       3             :  *      Copyright (C) 2003, 2004, 2005, 2006, 2007 g10 Code GmbH
       4             :  *
       5             :  * This file is part of DirMngr.
       6             :  *
       7             :  * DirMngr is free software; you can redistribute it and/or modify
       8             :  * it 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,
      13             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :  * GNU 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, see <http://www.gnu.org/licenses/>.
      19             :  */
      20             : 
      21             : #include <config.h>
      22             : 
      23             : #include <stdio.h>
      24             : #include <errno.h>
      25             : #include <npth.h>
      26             : 
      27             : #include "crlfetch.h"
      28             : #include "dirmngr.h"
      29             : #include "misc.h"
      30             : #include "http.h"
      31             : 
      32             : #if USE_LDAP
      33             : # include "ldap-wrapper.h"
      34             : #endif
      35             : 
      36             : /* For detecting armored CRLs received via HTTP (yes, such CRLS really
      37             :    exits, e.g. http://grid.fzk.de/ca/gridka-crl.pem at least in June
      38             :    2008) we need a context in the reader callback.  */
      39             : struct reader_cb_context_s
      40             : {
      41             :   estream_t fp;             /* The stream used with the ksba reader.  */
      42             :   int checked:1;            /* PEM/binary detection ahs been done.    */
      43             :   int is_pem:1;             /* The file stream is PEM encoded.        */
      44             :   struct b64state b64state; /* The state used for Base64 decoding.    */
      45             : };
      46             : 
      47             : 
      48             : /* We need to associate a reader object with the reader callback
      49             :    context.  This table is used for it. */
      50             : struct file_reader_map_s
      51             : {
      52             :   ksba_reader_t reader;
      53             :   struct reader_cb_context_s *cb_ctx;
      54             : };
      55             : #define MAX_FILE_READER 50
      56             : static struct file_reader_map_s file_reader_map[MAX_FILE_READER];
      57             : 
      58             : /* Associate FP with READER.  If the table is full wait until another
      59             :    thread has removed an entry.  */
      60             : static void
      61           0 : register_file_reader (ksba_reader_t reader, struct reader_cb_context_s *cb_ctx)
      62             : {
      63             :   int i;
      64             : 
      65             :   for (;;)
      66             :     {
      67           0 :       for (i=0; i < MAX_FILE_READER; i++)
      68           0 :         if (!file_reader_map[i].reader)
      69             :           {
      70           0 :             file_reader_map[i].reader = reader;
      71           0 :             file_reader_map[i].cb_ctx = cb_ctx;
      72           0 :             return;
      73             :           }
      74           0 :       log_info (_("reader to file mapping table full - waiting\n"));
      75           0 :       npth_sleep (2);
      76           0 :     }
      77             : }
      78             : 
      79             : /* Scan the table for an entry matching READER, remove that entry and
      80             :    return the associated file pointer. */
      81             : static struct reader_cb_context_s *
      82           0 : get_file_reader (ksba_reader_t reader)
      83             : {
      84           0 :   struct reader_cb_context_s *cb_ctx = NULL;
      85             :   int i;
      86             : 
      87           0 :   for (i=0; i < MAX_FILE_READER; i++)
      88           0 :     if (file_reader_map[i].reader == reader)
      89             :       {
      90           0 :         cb_ctx = file_reader_map[i].cb_ctx;
      91           0 :         file_reader_map[i].reader = NULL;
      92           0 :         file_reader_map[i].cb_ctx = NULL;
      93           0 :         break;
      94             :       }
      95           0 :   return cb_ctx;
      96             : }
      97             : 
      98             : 
      99             : 
     100             : static int
     101           0 : my_es_read (void *opaque, char *buffer, size_t nbytes, size_t *nread)
     102             : {
     103           0 :   struct reader_cb_context_s *cb_ctx = opaque;
     104             :   int result;
     105             : 
     106           0 :   result = es_read (cb_ctx->fp, buffer, nbytes, nread);
     107           0 :   if (result)
     108           0 :     return result;
     109             :   /* Fixme we should check whether the semantics of es_read are okay
     110             :      and well defined.  I have some doubts.  */
     111           0 :   if (nbytes && !*nread && es_feof (cb_ctx->fp))
     112           0 :     return gpg_error (GPG_ERR_EOF);
     113           0 :   if (!nread && es_ferror (cb_ctx->fp))
     114           0 :     return gpg_error (GPG_ERR_EIO);
     115             : 
     116           0 :   if (!cb_ctx->checked && *nread)
     117             :     {
     118           0 :       int c = *(unsigned char *)buffer;
     119             : 
     120           0 :       cb_ctx->checked = 1;
     121           0 :       if ( ((c & 0xc0) >> 6) == 0 /* class: universal */
     122           0 :            && (c & 0x1f) == 16    /* sequence */
     123           0 :            && (c & 0x20)          /* is constructed */ )
     124             :         ; /* Binary data.  */
     125             :       else
     126             :         {
     127           0 :           cb_ctx->is_pem = 1;
     128           0 :           b64dec_start (&cb_ctx->b64state, "");
     129             :         }
     130             :     }
     131           0 :   if (cb_ctx->is_pem && *nread)
     132             :     {
     133             :       size_t nread2;
     134             : 
     135           0 :       if (b64dec_proc (&cb_ctx->b64state, buffer, *nread, &nread2))
     136             :         {
     137             :           /* EOF from decoder. */
     138           0 :           *nread = 0;
     139           0 :           result = gpg_error (GPG_ERR_EOF);
     140             :         }
     141             :       else
     142           0 :         *nread = nread2;
     143             :     }
     144             : 
     145           0 :   return result;
     146             : }
     147             : 
     148             : 
     149             : /* Fetch CRL from URL and return the entire CRL using new ksba reader
     150             :    object in READER.  Note that this reader object should be closed
     151             :    only using ldap_close_reader. */
     152             : gpg_error_t
     153           0 : crl_fetch (ctrl_t ctrl, const char *url, ksba_reader_t *reader)
     154             : {
     155             :   gpg_error_t err;
     156             :   parsed_uri_t uri;
     157           0 :   char *free_this = NULL;
     158           0 :   int redirects_left = 2; /* We allow for 2 redirect levels.  */
     159             : 
     160           0 :   *reader = NULL;
     161             : 
     162           0 :   if (!url)
     163           0 :     return gpg_error (GPG_ERR_INV_ARG);
     164             : 
     165             :  once_more:
     166           0 :   err = http_parse_uri (&uri, url, 0);
     167           0 :   http_release_parsed_uri (uri);
     168           0 :   if (err && !strncmp (url, "https:", 6))
     169             :     {
     170             :       /* Our HTTP code does not support TLS, thus we can't use this
     171             :          scheme and it is frankly not useful for CRL retrieval anyway.
     172             :          We resort to using http, assuming that the server also
     173             :          provides plain http access. */
     174           0 :       free_this = xtrymalloc (strlen (url) + 1);
     175           0 :       if (free_this)
     176             :         {
     177           0 :           strcpy (stpcpy (free_this,"http:"), url+6);
     178           0 :           err = http_parse_uri (&uri, free_this, 0);
     179           0 :           http_release_parsed_uri (uri);
     180           0 :           if (!err)
     181             :             {
     182           0 :               log_info (_("using \"http\" instead of \"https\"\n"));
     183           0 :               url = free_this;
     184             :             }
     185             :         }
     186             :     }
     187           0 :   if (!err) /* Yes, our HTTP code groks that. */
     188             :     {
     189             :       http_t hd;
     190             : 
     191           0 :       if (opt.disable_http)
     192             :         {
     193           0 :           log_error (_("CRL access not possible due to disabled %s\n"),
     194             :                      "HTTP");
     195           0 :           err = gpg_error (GPG_ERR_NOT_SUPPORTED);
     196             :         }
     197             :       else
     198           0 :         err = http_open_document (&hd, url, NULL,
     199           0 :                                   ((opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0)
     200           0 :                                    |(DBG_LOOKUP? HTTP_FLAG_LOG_RESP:0)
     201           0 :                                    |(opt.use_tor? HTTP_FLAG_FORCE_TOR:0)),
     202           0 :                                   ctrl->http_proxy, NULL, NULL, NULL);
     203             : 
     204           0 :       switch ( err? 99999 : http_get_status_code (hd) )
     205             :         {
     206             :         case 200:
     207             :           {
     208           0 :             estream_t fp = http_get_read_ptr (hd);
     209             :             struct reader_cb_context_s *cb_ctx;
     210             : 
     211           0 :             cb_ctx = xtrycalloc (1, sizeof *cb_ctx);
     212           0 :             if (!cb_ctx)
     213           0 :               err = gpg_error_from_syserror ();
     214           0 :             if (!err)
     215           0 :               err = ksba_reader_new (reader);
     216           0 :             if (!err)
     217             :               {
     218           0 :                 cb_ctx->fp = fp;
     219           0 :                 err = ksba_reader_set_cb (*reader, &my_es_read, cb_ctx);
     220             :               }
     221           0 :             if (err)
     222             :               {
     223           0 :                 log_error (_("error initializing reader object: %s\n"),
     224             :                            gpg_strerror (err));
     225           0 :                 ksba_reader_release (*reader);
     226           0 :                 *reader = NULL;
     227           0 :                 http_close (hd, 0);
     228             :               }
     229             :             else
     230             :               {
     231             :                 /* The ksba reader misses a user pointer thus we need
     232             :                    to come up with our own way of associating a file
     233             :                    pointer (or well the callback context) with the
     234             :                    reader.  It is only required when closing the
     235             :                    reader thus there is no performance issue doing it
     236             :                    this way.  FIXME: We now have a close notification
     237             :                    which might be used here. */
     238           0 :                 register_file_reader (*reader, cb_ctx);
     239           0 :                 http_close (hd, 1);
     240             :               }
     241             :           }
     242           0 :           break;
     243             : 
     244             :         case 301: /* Redirection (perm.). */
     245             :         case 302: /* Redirection (temp.). */
     246             :           {
     247           0 :             const char *s = http_get_header (hd, "Location");
     248             : 
     249           0 :             log_info (_("URL '%s' redirected to '%s' (%u)\n"),
     250             :                       url, s?s:"[none]", http_get_status_code (hd));
     251           0 :             if (s && *s && redirects_left-- )
     252             :               {
     253           0 :                 xfree (free_this); url = NULL;
     254           0 :                 free_this = xtrystrdup (s);
     255           0 :                 if (!free_this)
     256           0 :                   err = gpg_error_from_errno (errno);
     257             :                 else
     258             :                   {
     259           0 :                     url = free_this;
     260           0 :                     http_close (hd, 0);
     261             :                     /* Note, that our implementation of redirection
     262             :                        actually handles a redirect to LDAP.  */
     263           0 :                     goto once_more;
     264             :                   }
     265             :               }
     266             :             else
     267           0 :               err = gpg_error (GPG_ERR_NO_DATA);
     268           0 :             log_error (_("too many redirections\n")); /* Or no "Location". */
     269           0 :             http_close (hd, 0);
     270             :           }
     271           0 :           break;
     272             : 
     273             :         case 99999: /* Made up status code for error reporting.  */
     274           0 :           log_error (_("error retrieving '%s': %s\n"),
     275             :                      url, gpg_strerror (err));
     276           0 :           break;
     277             : 
     278             :         default:
     279           0 :           log_error (_("error retrieving '%s': http status %u\n"),
     280             :                      url, http_get_status_code (hd));
     281           0 :           err = gpg_error (GPG_ERR_NO_DATA);
     282           0 :           http_close (hd, 0);
     283             :         }
     284             :     }
     285             :   else /* Let the LDAP code try other schemes. */
     286             :     {
     287           0 :       if (opt.disable_ldap)
     288             :         {
     289           0 :           log_error (_("CRL access not possible due to disabled %s\n"),
     290             :                      "LDAP");
     291           0 :           err = gpg_error (GPG_ERR_NOT_SUPPORTED);
     292             :         }
     293           0 :       else if (opt.use_tor)
     294             :         {
     295             :           /* For now we do not support LDAP over Tor.  */
     296           0 :           log_error (_("CRL access not possible due to Tor mode\n"));
     297           0 :           err = gpg_error (GPG_ERR_NOT_SUPPORTED);
     298             :         }
     299             :       else
     300             :         {
     301             : #       if USE_LDAP
     302           0 :           err = url_fetch_ldap (ctrl, url, NULL, 0, reader);
     303             : #       else /*!USE_LDAP*/
     304             :           err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
     305             : #       endif /*!USE_LDAP*/
     306             :         }
     307             :     }
     308             : 
     309           0 :   xfree (free_this);
     310           0 :   return err;
     311             : }
     312             : 
     313             : 
     314             : /* Fetch CRL for ISSUER using a default server. Return the entire CRL
     315             :    as a newly opened stream returned in R_FP. */
     316             : gpg_error_t
     317           0 : crl_fetch_default (ctrl_t ctrl, const char *issuer, ksba_reader_t *reader)
     318             : {
     319           0 :   if (opt.use_tor)
     320             :     {
     321             :       /* For now we do not support LDAP over Tor.  */
     322           0 :       log_error (_("CRL access not possible due to Tor mode\n"));
     323           0 :       return gpg_error (GPG_ERR_NOT_SUPPORTED);
     324             :     }
     325           0 :   if (opt.disable_ldap)
     326             :     {
     327           0 :       log_error (_("CRL access not possible due to disabled %s\n"),
     328             :                  "LDAP");
     329           0 :       return gpg_error (GPG_ERR_NOT_SUPPORTED);
     330             :     }
     331             : 
     332             : #if USE_LDAP
     333           0 :   return attr_fetch_ldap (ctrl, issuer, "certificateRevocationList",
     334             :                           reader);
     335             : #else
     336             :   (void)ctrl;
     337             :   (void)issuer;
     338             :   (void)reader;
     339             :   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
     340             : #endif
     341             : }
     342             : 
     343             : 
     344             : /* Fetch a CA certificate for DN using the default server. This
     345             :    function only initiates the fetch; fetch_next_cert must be used to
     346             :    actually read the certificate; end_cert_fetch to end the
     347             :    operation. */
     348             : gpg_error_t
     349           0 : ca_cert_fetch (ctrl_t ctrl, cert_fetch_context_t *context, const char *dn)
     350             : {
     351           0 :   if (opt.use_tor)
     352             :     {
     353             :       /* For now we do not support LDAP over Tor.  */
     354           0 :       log_error (_("CRL access not possible due to Tor mode\n"));
     355           0 :       return gpg_error (GPG_ERR_NOT_SUPPORTED);
     356             :     }
     357           0 :   if (opt.disable_ldap)
     358             :     {
     359           0 :       log_error (_("CRL access not possible due to disabled %s\n"),
     360             :                  "LDAP");
     361           0 :       return gpg_error (GPG_ERR_NOT_SUPPORTED);
     362             :     }
     363             : #if USE_LDAP
     364           0 :   return start_default_fetch_ldap (ctrl, context, dn, "cACertificate");
     365             : #else
     366             :   (void)ctrl;
     367             :   (void)context;
     368             :   (void)dn;
     369             :   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
     370             : #endif
     371             : }
     372             : 
     373             : 
     374             : gpg_error_t
     375           0 : start_cert_fetch (ctrl_t ctrl, cert_fetch_context_t *context,
     376             :                   strlist_t patterns, const ldap_server_t server)
     377             : {
     378           0 :   if (opt.use_tor)
     379             :     {
     380             :       /* For now we do not support LDAP over Tor.  */
     381           0 :       log_error (_("CRL access not possible due to Tor mode\n"));
     382           0 :       return gpg_error (GPG_ERR_NOT_SUPPORTED);
     383             :     }
     384           0 :   if (opt.disable_ldap)
     385             :     {
     386           0 :       log_error (_("certificate search not possible due to disabled %s\n"),
     387             :                  "LDAP");
     388           0 :       return gpg_error (GPG_ERR_NOT_SUPPORTED);
     389             :     }
     390             : #if USE_LDAP
     391           0 :   return start_cert_fetch_ldap (ctrl, context, patterns, server);
     392             : #else
     393             :   (void)ctrl;
     394             :   (void)context;
     395             :   (void)patterns;
     396             :   (void)server;
     397             :   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
     398             : #endif
     399             : }
     400             : 
     401             : 
     402             : gpg_error_t
     403           0 : fetch_next_cert (cert_fetch_context_t context,
     404             :                  unsigned char **value, size_t * valuelen)
     405             : {
     406             : #if USE_LDAP
     407           0 :   return fetch_next_cert_ldap (context, value, valuelen);
     408             : #else
     409             :   (void)context;
     410             :   (void)value;
     411             :   (void)valuelen;
     412             :   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
     413             : #endif
     414             : }
     415             : 
     416             : 
     417             : /* Fetch the next data from CONTEXT, assuming it is a certificate and return
     418             :    it as a cert object in R_CERT.  */
     419             : gpg_error_t
     420           0 : fetch_next_ksba_cert (cert_fetch_context_t context, ksba_cert_t *r_cert)
     421             : {
     422             :   gpg_error_t err;
     423             :   unsigned char *value;
     424             :   size_t valuelen;
     425             :   ksba_cert_t cert;
     426             : 
     427           0 :   *r_cert = NULL;
     428             : 
     429             : #if USE_LDAP
     430           0 :   err = fetch_next_cert_ldap (context, &value, &valuelen);
     431           0 :   if (!err && !value)
     432           0 :     err = gpg_error (GPG_ERR_BUG);
     433             : #else
     434             :   (void)context;
     435             :   err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
     436             : #endif
     437           0 :   if (err)
     438           0 :     return err;
     439             : 
     440           0 :   err = ksba_cert_new (&cert);
     441           0 :   if (err)
     442             :     {
     443           0 :       xfree (value);
     444           0 :       return err;
     445             :     }
     446             : 
     447           0 :   err = ksba_cert_init_from_mem (cert, value, valuelen);
     448           0 :   xfree (value);
     449           0 :   if (err)
     450             :     {
     451           0 :       ksba_cert_release (cert);
     452           0 :       return err;
     453             :     }
     454           0 :   *r_cert = cert;
     455           0 :   return 0;
     456             : }
     457             : 
     458             : 
     459             : void
     460           0 : end_cert_fetch (cert_fetch_context_t context)
     461             : {
     462             : #if USE_LDAP
     463           0 :   end_cert_fetch_ldap (context);
     464             : #else
     465             :   (void)context;
     466             : #endif
     467           0 : }
     468             : 
     469             : 
     470             : /* Lookup a cert by it's URL.  */
     471             : gpg_error_t
     472           0 : fetch_cert_by_url (ctrl_t ctrl, const char *url,
     473             :                    unsigned char **value, size_t *valuelen)
     474             : {
     475             :   const unsigned char *cert_image;
     476             :   size_t cert_image_n;
     477             :   ksba_reader_t reader;
     478             :   ksba_cert_t cert;
     479             :   gpg_error_t err;
     480             : 
     481           0 :   *value = NULL;
     482           0 :   *valuelen = 0;
     483           0 :   cert_image = NULL;
     484           0 :   reader = NULL;
     485           0 :   cert = NULL;
     486             : 
     487             : #if USE_LDAP
     488           0 :   err = url_fetch_ldap (ctrl, url, NULL, 0, &reader);
     489             : #else
     490             :   (void)ctrl;
     491             :   (void)url;
     492             :   err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
     493             : #endif /*USE_LDAP*/
     494           0 :   if (err)
     495           0 :     goto leave;
     496             : 
     497           0 :   err = ksba_cert_new (&cert);
     498           0 :   if (err)
     499           0 :     goto leave;
     500             : 
     501           0 :   err = ksba_cert_read_der (cert, reader);
     502           0 :   if (err)
     503           0 :     goto leave;
     504             : 
     505           0 :   cert_image = ksba_cert_get_image (cert, &cert_image_n);
     506           0 :   if (!cert_image || !cert_image_n)
     507             :     {
     508           0 :       err = gpg_error (GPG_ERR_INV_CERT_OBJ);
     509           0 :       goto leave;
     510             :     }
     511             : 
     512           0 :   *value = xtrymalloc (cert_image_n);
     513           0 :   if (!*value)
     514             :     {
     515           0 :       err = gpg_error_from_syserror ();
     516           0 :       goto leave;
     517             :     }
     518             : 
     519           0 :   memcpy (*value, cert_image, cert_image_n);
     520           0 :   *valuelen = cert_image_n;
     521             : 
     522             :  leave:
     523             : 
     524           0 :   ksba_cert_release (cert);
     525             : #if USE_LDAP
     526           0 :   ldap_wrapper_release_context (reader);
     527             : #endif /*USE_LDAP*/
     528             : 
     529           0 :   return err;
     530             : }
     531             : 
     532             : /* This function is to be used to close the reader object.  In
     533             :    addition to running ksba_reader_release it also releases the LDAP
     534             :    or HTTP contexts associated with that reader.  */
     535             : void
     536           0 : crl_close_reader (ksba_reader_t reader)
     537             : {
     538             :   struct reader_cb_context_s *cb_ctx;
     539             : 
     540           0 :   if (!reader)
     541           0 :     return;
     542             : 
     543             :   /* Check whether this is a HTTP one. */
     544           0 :   cb_ctx = get_file_reader (reader);
     545           0 :   if (cb_ctx)
     546             :     {
     547             :       /* This is an HTTP context. */
     548           0 :       if (cb_ctx->fp)
     549           0 :         es_fclose (cb_ctx->fp);
     550             :       /* Release the base64 decoder state.  */
     551           0 :       if (cb_ctx->is_pem)
     552           0 :         b64dec_finish (&cb_ctx->b64state);
     553             :       /* Release the callback context.  */
     554           0 :       xfree (cb_ctx);
     555             :     }
     556             :   else /* This is an ldap wrapper context (Currently not used). */
     557             :     {
     558             : #if USE_LDAP
     559           0 :       ldap_wrapper_release_context (reader);
     560             : #endif /*USE_LDAP*/
     561             :     }
     562             : 
     563             :   /* Now get rid of the reader object. */
     564           0 :   ksba_reader_release (reader);
     565             : }

Generated by: LCOV version 1.11