dirmngr: Allow redirection from https to http for CRLs
[gnupg.git] / dirmngr / crlfetch.c
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
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       npth_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 *
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
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
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, NULL, 0, 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
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
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_default_fetch_ldap (ctrl, context, dn, "cACertificate");
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
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
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
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
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 /* Lookup a cert by it's URL.  */
412 gpg_error_t
413 fetch_cert_by_url (ctrl_t ctrl, const char *url,
414                    unsigned char **value, size_t *valuelen)
415 {
416   const unsigned char *cert_image;
417   size_t cert_image_n;
418   ksba_reader_t reader;
419   ksba_cert_t cert;
420   gpg_error_t err;
421
422   *value = NULL;
423   *valuelen = 0;
424   cert_image = NULL;
425   reader = NULL;
426   cert = NULL;
427
428 #if USE_LDAP
429   err = url_fetch_ldap (ctrl, url, NULL, 0, &reader);
430 #else
431   (void)ctrl;
432   (void)url;
433   err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
434 #endif /*USE_LDAP*/
435   if (err)
436     goto leave;
437
438   err = ksba_cert_new (&cert);
439   if (err)
440     goto leave;
441
442   err = ksba_cert_read_der (cert, reader);
443   if (err)
444     goto leave;
445
446   cert_image = ksba_cert_get_image (cert, &cert_image_n);
447   if (!cert_image || !cert_image_n)
448     {
449       err = gpg_error (GPG_ERR_INV_CERT_OBJ);
450       goto leave;
451     }
452
453   *value = xtrymalloc (cert_image_n);
454   if (!*value)
455     {
456       err = gpg_error_from_syserror ();
457       goto leave;
458     }
459
460   memcpy (*value, cert_image, cert_image_n);
461   *valuelen = cert_image_n;
462
463  leave:
464
465   ksba_cert_release (cert);
466 #if USE_LDAP
467   ldap_wrapper_release_context (reader);
468 #endif /*USE_LDAP*/
469
470   return err;
471 }
472
473 /* This function is to be used to close the reader object.  In
474    addition to running ksba_reader_release it also releases the LDAP
475    or HTTP contexts associated with that reader.  */
476 void
477 crl_close_reader (ksba_reader_t reader)
478 {
479   struct reader_cb_context_s *cb_ctx;
480
481   if (!reader)
482     return;
483
484   /* Check whether this is a HTTP one. */
485   cb_ctx = get_file_reader (reader);
486   if (cb_ctx)
487     {
488       /* This is an HTTP context. */
489       if (cb_ctx->fp)
490         es_fclose (cb_ctx->fp);
491       /* Release the base64 decoder state.  */
492       if (cb_ctx->is_pem)
493         b64dec_finish (&cb_ctx->b64state);
494       /* Release the callback context.  */
495       xfree (cb_ctx);
496     }
497   else /* This is an ldap wrapper context (Currently not used). */
498     {
499 #if USE_LDAP
500       ldap_wrapper_release_context (reader);
501 #endif /*USE_LDAP*/
502     }
503
504   /* Now get rid of the reader object. */
505   ksba_reader_release (reader);
506 }