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