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