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