]> sjero.net Git - wget/blob - src/gnutls.c
gnutls: Prevent CA files from being loaded twice if possible
[wget] / src / gnutls.c
1 /* SSL support via GnuTLS library.
2    Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software
3    Foundation, Inc.
4
5 This file is part of GNU Wget.
6
7 GNU Wget 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 3 of the License, or
10 (at your option) any later version.
11
12 GNU Wget 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 Wget.  If not, see <http://www.gnu.org/licenses/>.
19
20 Additional permission under GNU GPL version 3 section 7
21
22 If you modify this program, or any covered work, by linking or
23 combining it with the OpenSSL project's OpenSSL library (or a
24 modified version of that library), containing parts covered by the
25 terms of the OpenSSL or SSLeay licenses, the Free Software Foundation
26 grants you additional permission to convey the resulting work.
27 Corresponding Source for a non-source form of such a combination
28 shall include the source code for the parts of OpenSSL used as well
29 as that of the covered work.  */
30
31 #include "wget.h"
32
33 #include <assert.h>
34 #include <errno.h>
35 #include <unistd.h>
36 #include <string.h>
37 #include <stdio.h>
38 #include <dirent.h>
39 #include <stdlib.h>
40
41 #include <gnutls/gnutls.h>
42 #include <gnutls/x509.h>
43 #include <sys/ioctl.h>
44
45 #include "utils.h"
46 #include "connect.h"
47 #include "url.h"
48 #include "ptimer.h"
49 #include "hash.h"
50 #include "ssl.h"
51
52 #include <sys/fcntl.h>
53
54 #ifdef WIN32
55 # include "w32sock.h"
56 #endif
57
58 #include "host.h"
59
60 static int
61 key_type_to_gnutls_type (enum keyfile_type type)
62 {
63   switch (type)
64     {
65     case keyfile_pem:
66       return GNUTLS_X509_FMT_PEM;
67     case keyfile_asn1:
68       return GNUTLS_X509_FMT_DER;
69     default:
70       abort ();
71     }
72 }
73
74 /* Note: some of the functions private to this file have names that
75    begin with "wgnutls_" (e.g. wgnutls_read) so that they wouldn't be
76    confused with actual gnutls functions -- such as the gnutls_read
77    preprocessor macro.  */
78
79 static gnutls_certificate_credentials_t credentials;
80 bool
81 ssl_init (void)
82 {
83   /* Becomes true if GnuTLS is initialized. */
84   static bool ssl_initialized = false;
85   const char *ca_directory;
86   DIR *dir;
87   int ncerts = -1;
88
89   /* GnuTLS should be initialized only once. */
90   if (ssl_initialized)
91     return true;
92
93   gnutls_global_init ();
94   gnutls_certificate_allocate_credentials (&credentials);
95   gnutls_certificate_set_verify_flags (credentials,
96                                        GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
97
98 #if GNUTLS_VERSION_MAJOR >= 3
99   if (!opt.ca_directory)
100     ncerts = gnutls_certificate_set_x509_system_trust (credentials);
101 #endif
102
103   /* If GnuTLS version is too old or CA loading failed, fallback to old behaviour.
104    * Also use old behaviour if the CA directory is user-provided.  */
105   if (ncerts <= 0)
106     {
107       ca_directory = opt.ca_directory ? opt.ca_directory : "/etc/ssl/certs";
108       if ((dir = opendir (ca_directory)) == NULL)
109         {
110           if (opt.ca_directory && *opt.ca_directory)
111             logprintf (LOG_NOTQUIET, _("ERROR: Cannot open directory %s.\n"),
112                        opt.ca_directory);
113         }
114       else
115         {
116           struct hash_table *inode_map = hash_table_new (196, NULL, NULL);
117           struct dirent *dent;
118           size_t dirlen = strlen(ca_directory);
119           int rc;
120
121           ncerts = 0;
122
123           while ((dent = readdir (dir)) != NULL)
124             {
125               struct stat st;
126               char ca_file[dirlen + strlen(dent->d_name) + 2];
127
128               snprintf (ca_file, sizeof(ca_file), "%s/%s", ca_directory, dent->d_name);
129               if (stat (ca_file, &st) != 0)
130                 continue;
131
132               if (! S_ISREG (st.st_mode))
133                 continue;
134
135               /* avoid loading the same file twice by checking the inode.  */
136               if (hash_table_contains (inode_map, (void *)(intptr_t) st.st_ino))
137                 continue;
138
139               hash_table_put (inode_map, (void *)(intptr_t) st.st_ino, NULL);
140               if ((rc = gnutls_certificate_set_x509_trust_file (credentials, ca_file,
141                                                                 GNUTLS_X509_FMT_PEM)) <= 0)
142                 logprintf (LOG_NOTQUIET, _("ERROR: Failed to open cert %s: (%d).\n"),
143                            ca_file, rc);
144               else
145                 ncerts += rc;
146             }
147
148           hash_table_destroy (inode_map);
149           closedir (dir);
150         }
151     }
152
153   DEBUGP (("Certificates loaded: %d\n", ncerts));
154
155   /* Use the private key from the cert file unless otherwise specified. */
156   if (opt.cert_file && !opt.private_key)
157     {
158       opt.private_key = opt.cert_file;
159       opt.private_key_type = opt.cert_type;
160     }
161   /* Use the cert from the private key file unless otherwise specified. */
162   if (!opt.cert_file && opt.private_key)
163     {
164       opt.cert_file = opt.private_key;
165       opt.cert_type = opt.private_key_type;
166     }
167
168   if (opt.cert_file && opt.private_key)
169     {
170       int type;
171       if (opt.private_key_type != opt.cert_type)
172         {
173           /* GnuTLS can't handle this */
174           logprintf (LOG_NOTQUIET, _("ERROR: GnuTLS requires the key and the \
175 cert to be of the same type.\n"));
176         }
177
178       type = key_type_to_gnutls_type (opt.private_key_type);
179
180       gnutls_certificate_set_x509_key_file (credentials, opt.cert_file,
181                                             opt.private_key,
182                                             type);
183     }
184
185   if (opt.ca_cert)
186     gnutls_certificate_set_x509_trust_file (credentials, opt.ca_cert,
187                                             GNUTLS_X509_FMT_PEM);
188
189   ssl_initialized = true;
190
191   return true;
192 }
193
194 struct wgnutls_transport_context
195 {
196   gnutls_session_t session;       /* GnuTLS session handle */
197   int last_error;               /* last error returned by read/write/... */
198
199   /* Since GnuTLS doesn't support the equivalent to recv(...,
200      MSG_PEEK) or SSL_peek(), we have to do it ourselves.  Peeked data
201      is stored to PEEKBUF, and wgnutls_read checks that buffer before
202      actually reading.  */
203   char peekbuf[512];
204   int peeklen;
205 };
206
207 #ifndef MIN
208 # define MIN(i, j) ((i) <= (j) ? (i) : (j))
209 #endif
210
211
212 static int
213 wgnutls_read_timeout (int fd, char *buf, int bufsize, void *arg, double timeout)
214 {
215 #ifdef F_GETFL
216   int flags = 0;
217 #endif
218   int ret = 0;
219   struct ptimer *timer = NULL;
220   struct wgnutls_transport_context *ctx = arg;
221   int timed_out = 0;
222
223   if (timeout)
224     {
225 #ifdef F_GETFL
226       flags = fcntl (fd, F_GETFL, 0);
227       if (flags < 0)
228         return flags;
229       if (fcntl (fd, F_SETFL, flags | O_NONBLOCK))
230         return -1;
231 #else
232       /* XXX: Assume it was blocking before.  */
233       const int one = 1;
234       if (ioctl (fd, FIONBIO, &one) < 0)
235         return -1;
236 #endif
237
238       timer = ptimer_new ();
239       if (timer == NULL)
240         return -1;
241     }
242
243   do
244     {
245       double next_timeout = 0;
246       if (timeout)
247         {
248           next_timeout = timeout - ptimer_measure (timer);
249           if (next_timeout < 0)
250             break;
251         }
252
253       ret = GNUTLS_E_AGAIN;
254       if (timeout == 0 || gnutls_record_check_pending (ctx->session)
255           || select_fd (fd, next_timeout, WAIT_FOR_READ))
256         {
257           ret = gnutls_record_recv (ctx->session, buf, bufsize);
258           timed_out = timeout && ptimer_measure (timer) >= timeout;
259         }
260     }
261   while (ret == GNUTLS_E_INTERRUPTED || (ret == GNUTLS_E_AGAIN && !timed_out));
262
263   if (timeout)
264     {
265       ptimer_destroy (timer);
266
267 #ifdef F_GETFL
268       if (fcntl (fd, F_SETFL, flags) < 0)
269         return -1;
270 #else
271       const int zero = 0;
272       if (ioctl (fd, FIONBIO, &zero) < 0)
273         return -1;
274 #endif
275
276       if (timed_out && ret == GNUTLS_E_AGAIN)
277         errno = ETIMEDOUT;
278     }
279
280   return ret;
281 }
282
283 static int
284 wgnutls_read (int fd, char *buf, int bufsize, void *arg)
285 {
286   int ret = 0;
287   struct wgnutls_transport_context *ctx = arg;
288
289   if (ctx->peeklen)
290     {
291       /* If we have any peek data, simply return that. */
292       int copysize = MIN (bufsize, ctx->peeklen);
293       memcpy (buf, ctx->peekbuf, copysize);
294       ctx->peeklen -= copysize;
295       if (ctx->peeklen != 0)
296         memmove (ctx->peekbuf, ctx->peekbuf + copysize, ctx->peeklen);
297
298       return copysize;
299     }
300
301   ret = wgnutls_read_timeout (fd, buf, bufsize, arg, opt.read_timeout);
302   if (ret < 0)
303     ctx->last_error = ret;
304
305   return ret;
306 }
307
308 static int
309 wgnutls_write (int fd _GL_UNUSED, char *buf, int bufsize, void *arg)
310 {
311   int ret;
312   struct wgnutls_transport_context *ctx = arg;
313   do
314     ret = gnutls_record_send (ctx->session, buf, bufsize);
315   while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
316   if (ret < 0)
317     ctx->last_error = ret;
318   return ret;
319 }
320
321 static int
322 wgnutls_poll (int fd, double timeout, int wait_for, void *arg)
323 {
324   struct wgnutls_transport_context *ctx = arg;
325
326   if (timeout)
327     return ctx->peeklen || gnutls_record_check_pending (ctx->session)
328       || select_fd (fd, timeout, wait_for);
329   else
330     return ctx->peeklen || gnutls_record_check_pending (ctx->session);
331 }
332
333 static int
334 wgnutls_peek (int fd, char *buf, int bufsize, void *arg)
335 {
336   int read = 0;
337   struct wgnutls_transport_context *ctx = arg;
338   int offset = MIN (bufsize, ctx->peeklen);
339
340   if (ctx->peeklen)
341     {
342       memcpy (buf, ctx->peekbuf, offset);
343       return offset;
344     }
345
346   if (bufsize > (int) sizeof ctx->peekbuf)
347     bufsize = sizeof ctx->peekbuf;
348
349   if (bufsize > offset)
350     {
351       if (opt.read_timeout && gnutls_record_check_pending (ctx->session) == 0
352           && select_fd (fd, 0.0, WAIT_FOR_READ) <= 0)
353         read = 0;
354       else
355         read = wgnutls_read_timeout (fd, buf + offset, bufsize - offset,
356                                      ctx, opt.read_timeout);
357       if (read < 0)
358         {
359           if (offset)
360             read = 0;
361           else
362             return read;
363         }
364
365       if (read > 0)
366         {
367           memcpy (ctx->peekbuf + offset, buf + offset,
368                   read);
369           ctx->peeklen += read;
370         }
371     }
372
373   return offset + read;
374 }
375
376 static const char *
377 wgnutls_errstr (int fd _GL_UNUSED, void *arg)
378 {
379   struct wgnutls_transport_context *ctx = arg;
380   return gnutls_strerror (ctx->last_error);
381 }
382
383 static void
384 wgnutls_close (int fd, void *arg)
385 {
386   struct wgnutls_transport_context *ctx = arg;
387   /*gnutls_bye (ctx->session, GNUTLS_SHUT_RDWR);*/
388   gnutls_deinit (ctx->session);
389   xfree (ctx);
390   close (fd);
391 }
392
393 /* gnutls_transport is the singleton that describes the SSL transport
394    methods provided by this file.  */
395
396 static struct transport_implementation wgnutls_transport =
397 {
398   wgnutls_read, wgnutls_write, wgnutls_poll,
399   wgnutls_peek, wgnutls_errstr, wgnutls_close
400 };
401
402 bool
403 ssl_connect_wget (int fd, const char *hostname)
404 {
405 #ifdef F_GETFL
406   int flags = 0;
407 #endif
408   struct wgnutls_transport_context *ctx;
409   gnutls_session_t session;
410   int err,alert;
411   gnutls_init (&session, GNUTLS_CLIENT);
412   const char *str;
413
414   /* We set the server name but only if it's not an IP address. */
415   if (! is_valid_ip_address (hostname))
416     {
417       gnutls_server_name_set (session, GNUTLS_NAME_DNS, hostname,
418                               strlen (hostname));
419     }
420
421   gnutls_set_default_priority (session);
422   gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, credentials);
423 #ifndef FD_TO_SOCKET
424 # define FD_TO_SOCKET(X) (X)
425 #endif
426 #ifdef HAVE_INTPTR_T
427   gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) (intptr_t) FD_TO_SOCKET (fd));
428 #else
429   gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) FD_TO_SOCKET (fd));
430 #endif
431
432   err = 0;
433 #if HAVE_GNUTLS_PRIORITY_SET_DIRECT
434   switch (opt.secure_protocol)
435     {
436     case secure_protocol_auto:
437       break;
438     case secure_protocol_sslv2:
439     case secure_protocol_sslv3:
440       err = gnutls_priority_set_direct (session, "NORMAL:-VERS-TLS-ALL:+VERS-SSL3.0", NULL);
441       break;
442     case secure_protocol_tlsv1:
443       err = gnutls_priority_set_direct (session, "NORMAL:-VERS-SSL3.0", NULL);
444       break;
445     default:
446       abort ();
447     }
448 #else
449   int allowed_protocols[4] = {0, 0, 0, 0};
450   switch (opt.secure_protocol)
451     {
452     case secure_protocol_auto:
453       break;
454     case secure_protocol_sslv2:
455     case secure_protocol_sslv3:
456       allowed_protocols[0] = GNUTLS_SSL3;
457       err = gnutls_protocol_set_priority (session, allowed_protocols);
458       break;
459
460     case secure_protocol_tlsv1:
461       allowed_protocols[0] = GNUTLS_TLS1_0;
462       allowed_protocols[1] = GNUTLS_TLS1_1;
463       allowed_protocols[2] = GNUTLS_TLS1_2;
464       err = gnutls_protocol_set_priority (session, allowed_protocols);
465       break;
466
467     default:
468       abort ();
469     }
470 #endif
471
472   if (err < 0)
473     {
474       logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
475       gnutls_deinit (session);
476       return false;
477     }
478
479   if (opt.connect_timeout)
480     {
481 #ifdef F_GETFL
482       flags = fcntl (fd, F_GETFL, 0);
483       if (flags < 0)
484         return flags;
485       if (fcntl (fd, F_SETFL, flags | O_NONBLOCK))
486         return -1;
487 #else
488       /* XXX: Assume it was blocking before.  */
489       const int one = 1;
490       if (ioctl (fd, FIONBIO, &one) < 0)
491         return -1;
492 #endif
493     }
494
495   /* We don't stop the handshake process for non-fatal errors */
496   do
497     {
498       err = gnutls_handshake (session);
499
500       if (opt.connect_timeout && err == GNUTLS_E_AGAIN)
501         {
502           if (gnutls_record_get_direction (session))
503             {
504               /* wait for writeability */
505               err = select_fd (fd, opt.connect_timeout, WAIT_FOR_WRITE);
506             }
507           else
508             {
509               /* wait for readability */
510               err = select_fd (fd, opt.connect_timeout, WAIT_FOR_READ);
511             }
512
513           if (err <= 0)
514             {
515               if (err == 0)
516                 {
517                   errno = ETIMEDOUT;
518                   err = -1;
519                 }
520               break;
521             }
522
523           if (err <= 0)
524             break;
525         }
526       else if (err < 0)
527         {
528           logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
529           if (err == GNUTLS_E_WARNING_ALERT_RECEIVED ||
530               err == GNUTLS_E_FATAL_ALERT_RECEIVED)
531             {
532               alert = gnutls_alert_get (session);
533               str = gnutls_alert_get_name (alert);
534               if (str == NULL)
535                 str = "(unknown)";
536               logprintf (LOG_NOTQUIET, "GnuTLS: received alert [%d]: %s\n", alert, str);
537             }
538         }
539     }
540   while (err == GNUTLS_E_WARNING_ALERT_RECEIVED && gnutls_error_is_fatal (err) == 0);
541
542   if (opt.connect_timeout)
543     {
544 #ifdef F_GETFL
545       if (fcntl (fd, F_SETFL, flags) < 0)
546         return -1;
547 #else
548       const int zero = 0;
549       if (ioctl (fd, FIONBIO, &zero) < 0)
550         return -1;
551 #endif
552     }
553
554   if (err < 0)
555     {
556       gnutls_deinit (session);
557       return false;
558     }
559
560   ctx = xnew0 (struct wgnutls_transport_context);
561   ctx->session = session;
562   fd_register_transport (fd, &wgnutls_transport, ctx);
563   return true;
564 }
565
566 #define _CHECK_CERT(flag,msg) \
567   if (status & (flag))\
568     {\
569       logprintf (LOG_NOTQUIET, (msg),\
570                  severity, quote (host));\
571       success = false;\
572     }
573
574 bool
575 ssl_check_certificate (int fd, const char *host)
576 {
577   struct wgnutls_transport_context *ctx = fd_transport_context (fd);
578
579   unsigned int status;
580   int err;
581
582   /* If the user has specified --no-check-cert, we still want to warn
583      him about problems with the server's certificate.  */
584   const char *severity = opt.check_cert ? _("ERROR") : _("WARNING");
585   bool success = true;
586
587   err = gnutls_certificate_verify_peers2 (ctx->session, &status);
588   if (err < 0)
589     {
590       logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
591                  severity, quotearg_style (escape_quoting_style, host));
592       success = false;
593       goto out;
594     }
595
596   _CHECK_CERT (GNUTLS_CERT_INVALID, _("%s: The certificate of %s is not trusted.\n"));
597   _CHECK_CERT (GNUTLS_CERT_SIGNER_NOT_FOUND, _("%s: The certificate of %s hasn't got a known issuer.\n"));
598   _CHECK_CERT (GNUTLS_CERT_REVOKED, _("%s: The certificate of %s has been revoked.\n"));
599   _CHECK_CERT (GNUTLS_CERT_SIGNER_NOT_CA, _("%s: The certificate signer of %s was not a CA.\n"));
600   _CHECK_CERT (GNUTLS_CERT_INSECURE_ALGORITHM, _("%s: The certificate of %s was signed using an insecure algorithm.\n"));
601   _CHECK_CERT (GNUTLS_CERT_NOT_ACTIVATED, _("%s: The certificate of %s is not yet activated.\n"));
602   _CHECK_CERT (GNUTLS_CERT_EXPIRED, _("%s: The certificate of %s has expired.\n"));
603
604   if (gnutls_certificate_type_get (ctx->session) == GNUTLS_CRT_X509)
605     {
606       time_t now = time (NULL);
607       gnutls_x509_crt_t cert;
608       const gnutls_datum_t *cert_list;
609       unsigned int cert_list_size;
610
611       if ((err = gnutls_x509_crt_init (&cert)) < 0)
612         {
613           logprintf (LOG_NOTQUIET, _("Error initializing X509 certificate: %s\n"),
614                      gnutls_strerror (err));
615           success = false;
616           goto out;
617         }
618
619       cert_list = gnutls_certificate_get_peers (ctx->session, &cert_list_size);
620       if (!cert_list)
621         {
622           logprintf (LOG_NOTQUIET, _("No certificate found\n"));
623           success = false;
624           goto crt_deinit;
625         }
626       err = gnutls_x509_crt_import (cert, cert_list, GNUTLS_X509_FMT_DER);
627       if (err < 0)
628         {
629           logprintf (LOG_NOTQUIET, _("Error parsing certificate: %s\n"),
630                      gnutls_strerror (err));
631           success = false;
632           goto crt_deinit;
633         }
634       if (now < gnutls_x509_crt_get_activation_time (cert))
635         {
636           logprintf (LOG_NOTQUIET, _("The certificate has not yet been activated\n"));
637           success = false;
638         }
639       if (now >= gnutls_x509_crt_get_expiration_time (cert))
640         {
641           logprintf (LOG_NOTQUIET, _("The certificate has expired\n"));
642           success = false;
643         }
644       if (!gnutls_x509_crt_check_hostname (cert, host))
645         {
646           logprintf (LOG_NOTQUIET,
647                      _("The certificate's owner does not match hostname %s\n"),
648                      quote (host));
649           success = false;
650         }
651  crt_deinit:
652       gnutls_x509_crt_deinit (cert);
653     }
654   else
655     {
656       logprintf (LOG_NOTQUIET, _("Certificate must be X.509\n"));
657       success = false;
658     }
659
660  out:
661   return opt.check_cert ? success : true;
662 }