]> sjero.net Git - wget/blob - src/gnutls.c
7cc2e7187f4e6d0b2827ebf3c87c89e82aaecb9b
[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 "ssl.h"
50
51 #include <sys/fcntl.h>
52
53 #ifdef WIN32
54 # include "w32sock.h"
55 #endif
56
57 #include "host.h"
58
59 static int
60 key_type_to_gnutls_type (enum keyfile_type type)
61 {
62   switch (type)
63     {
64     case keyfile_pem:
65       return GNUTLS_X509_FMT_PEM;
66     case keyfile_asn1:
67       return GNUTLS_X509_FMT_DER;
68     default:
69       abort ();
70     }
71 }
72
73 /* Note: some of the functions private to this file have names that
74    begin with "wgnutls_" (e.g. wgnutls_read) so that they wouldn't be
75    confused with actual gnutls functions -- such as the gnutls_read
76    preprocessor macro.  */
77
78 static gnutls_certificate_credentials credentials;
79 bool
80 ssl_init (void)
81 {
82   /* Becomes true if GnuTLS is initialized. */
83   static bool ssl_initialized = false;
84
85   /* GnuTLS should be initialized only once. */
86   if (ssl_initialized)
87     return true;
88
89   const char *ca_directory;
90   DIR *dir;
91
92   gnutls_global_init ();
93   gnutls_certificate_allocate_credentials (&credentials);
94   gnutls_certificate_set_verify_flags(credentials,
95                                       GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
96
97   ca_directory = opt.ca_directory ? opt.ca_directory : "/etc/ssl/certs";
98
99   dir = opendir (ca_directory);
100   if (dir == NULL)
101     {
102       if (opt.ca_directory)
103         logprintf (LOG_NOTQUIET, _("ERROR: Cannot open directory %s.\n"),
104                    opt.ca_directory);
105     }
106   else
107     {
108       struct dirent *dent;
109       while ((dent = readdir (dir)) != NULL)
110         {
111           struct stat st;
112           char *ca_file;
113           asprintf (&ca_file, "%s/%s", ca_directory, dent->d_name);
114
115           stat (ca_file, &st);
116
117           if (S_ISREG (st.st_mode))
118             gnutls_certificate_set_x509_trust_file (credentials, ca_file,
119                                                     GNUTLS_X509_FMT_PEM);
120
121           free (ca_file);
122         }
123
124       closedir (dir);
125     }
126
127   /* Use the private key from the cert file unless otherwise specified. */
128   if (opt.cert_file && !opt.private_key)
129     {
130       opt.private_key = opt.cert_file;
131       opt.private_key_type = opt.cert_type;
132     }
133   /* Use the cert from the private key file unless otherwise specified. */
134   if (!opt.cert_file && opt.private_key)
135     {
136       opt.cert_file = opt.private_key;
137       opt.cert_type = opt.private_key_type;
138     }
139
140   if (opt.cert_file && opt.private_key)
141     {
142       int type;
143       if (opt.private_key_type != opt.cert_type)
144         {
145           /* GnuTLS can't handle this */
146           logprintf (LOG_NOTQUIET, _("ERROR: GnuTLS requires the key and the \
147 cert to be of the same type.\n"));
148         }
149
150       type = key_type_to_gnutls_type (opt.private_key_type);
151
152       gnutls_certificate_set_x509_key_file (credentials, opt.cert_file,
153                                             opt.private_key,
154                                             type);
155     }
156
157   if (opt.ca_cert)
158     gnutls_certificate_set_x509_trust_file (credentials, opt.ca_cert,
159                                             GNUTLS_X509_FMT_PEM);
160
161   ssl_initialized = true;
162
163   return true;
164 }
165
166 struct wgnutls_transport_context
167 {
168   gnutls_session session;       /* GnuTLS session handle */
169   int last_error;               /* last error returned by read/write/... */
170
171   /* Since GnuTLS doesn't support the equivalent to recv(...,
172      MSG_PEEK) or SSL_peek(), we have to do it ourselves.  Peeked data
173      is stored to PEEKBUF, and wgnutls_read checks that buffer before
174      actually reading.  */
175   char peekbuf[512];
176   int peeklen;
177 };
178
179 #ifndef MIN
180 # define MIN(i, j) ((i) <= (j) ? (i) : (j))
181 #endif
182
183
184 static int
185 wgnutls_read_timeout (int fd, char *buf, int bufsize, void *arg, double timeout)
186 {
187 #ifdef F_GETFL
188   int flags = 0;
189 #endif
190   int ret = 0;
191   struct ptimer *timer;
192   struct wgnutls_transport_context *ctx = arg;
193   int timed_out = 0;
194
195   if (timeout)
196     {
197 #ifdef F_GETFL
198       flags = fcntl (fd, F_GETFL, 0);
199       if (flags < 0)
200         return flags;
201 #endif
202       timer = ptimer_new ();
203       if (timer == 0)
204         return -1;
205     }
206
207   do
208     {
209       double next_timeout;
210       if (timeout > 0.0)
211         {
212           next_timeout = timeout - ptimer_measure (timer);
213           if (next_timeout < 0.0)
214             break;
215         }
216
217       ret = GNUTLS_E_AGAIN;
218       if (timeout == 0 || gnutls_record_check_pending (ctx->session)
219           || select_fd (fd, next_timeout, WAIT_FOR_READ))
220         {
221           if (timeout)
222             {
223 #ifdef F_GETFL
224               if (fcntl (fd, F_SETFL, flags | O_NONBLOCK))
225                 break;
226 #else
227               /* XXX: Assume it was blocking before.  */
228               const int one = 1;
229               if (ioctl (fd, FIONBIO, &one) < 0)
230                 break;
231 #endif
232             }
233
234           ret = gnutls_record_recv (ctx->session, buf, bufsize);
235
236           if (timeout)
237             {
238 #ifdef F_GETFL
239               if (fcntl (fd, F_SETFL, flags) < 0)
240                 break;
241 #else
242               const int zero = 0;
243               if (ioctl (fd, FIONBIO, &zero) < 0)
244                 break;
245 #endif
246             }
247         }
248
249       timed_out = timeout && ptimer_measure (timer) >= timeout;
250     }
251   while (ret == GNUTLS_E_INTERRUPTED || (ret == GNUTLS_E_AGAIN && !timed_out));
252
253   if (timeout)
254     ptimer_destroy (timer);
255
256   if (timeout && timed_out && ret == GNUTLS_E_AGAIN)
257     errno = ETIMEDOUT;
258
259   return ret;
260 }
261
262 static int
263 wgnutls_read (int fd, char *buf, int bufsize, void *arg)
264 {
265   int ret = 0;
266   struct wgnutls_transport_context *ctx = arg;
267
268   if (ctx->peeklen)
269     {
270       /* If we have any peek data, simply return that. */
271       int copysize = MIN (bufsize, ctx->peeklen);
272       memcpy (buf, ctx->peekbuf, copysize);
273       ctx->peeklen -= copysize;
274       if (ctx->peeklen != 0)
275         memmove (ctx->peekbuf, ctx->peekbuf + copysize, ctx->peeklen);
276
277       return copysize;
278     }
279
280   ret = wgnutls_read_timeout (fd, buf, bufsize, arg, opt.read_timeout);
281   if (ret < 0)
282     ctx->last_error = ret;
283
284   return ret;
285 }
286
287 static int
288 wgnutls_write (int fd, char *buf, int bufsize, void *arg)
289 {
290   int ret;
291   struct wgnutls_transport_context *ctx = arg;
292   do
293     ret = gnutls_record_send (ctx->session, buf, bufsize);
294   while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
295   if (ret < 0)
296     ctx->last_error = ret;
297   return ret;
298 }
299
300 static int
301 wgnutls_poll (int fd, double timeout, int wait_for, void *arg)
302 {
303   struct wgnutls_transport_context *ctx = arg;
304   return ctx->peeklen || gnutls_record_check_pending (ctx->session)
305     || select_fd (fd, timeout, wait_for);
306 }
307
308 static int
309 wgnutls_peek (int fd, char *buf, int bufsize, void *arg)
310 {
311   int read = 0;
312   struct wgnutls_transport_context *ctx = arg;
313   int offset = MIN (bufsize, ctx->peeklen);
314   if (bufsize > sizeof ctx->peekbuf)
315     bufsize = sizeof ctx->peekbuf;
316
317   if (ctx->peeklen)
318     memcpy (buf, ctx->peekbuf, offset);
319
320   if (bufsize > offset)
321     {
322       if (gnutls_record_check_pending (ctx->session) <= 0
323           && select_fd (fd, 0.0, WAIT_FOR_READ) <= 0)
324         read = 0;
325       else
326         read = wgnutls_read_timeout (fd, buf + offset, bufsize - offset,
327                                      ctx, opt.read_timeout);
328       if (read < 0)
329         {
330           if (offset)
331             read = 0;
332           else
333             return read;
334         }
335
336       if (read > 0)
337         {
338           memcpy (ctx->peekbuf + offset, buf + offset,
339                   read);
340           ctx->peeklen += read;
341         }
342     }
343
344   return offset + read;
345 }
346
347 static const char *
348 wgnutls_errstr (int fd, void *arg)
349 {
350   struct wgnutls_transport_context *ctx = arg;
351   return gnutls_strerror (ctx->last_error);
352 }
353
354 static void
355 wgnutls_close (int fd, void *arg)
356 {
357   struct wgnutls_transport_context *ctx = arg;
358   /*gnutls_bye (ctx->session, GNUTLS_SHUT_RDWR);*/
359   gnutls_deinit (ctx->session);
360   xfree (ctx);
361   close (fd);
362 }
363
364 /* gnutls_transport is the singleton that describes the SSL transport
365    methods provided by this file.  */
366
367 static struct transport_implementation wgnutls_transport =
368 {
369   wgnutls_read, wgnutls_write, wgnutls_poll,
370   wgnutls_peek, wgnutls_errstr, wgnutls_close
371 };
372
373 bool
374 ssl_connect_wget (int fd, const char *hostname)
375 {
376   struct wgnutls_transport_context *ctx;
377   gnutls_session session;
378   int err;
379   gnutls_init (&session, GNUTLS_CLIENT);
380
381   /* We set the server name but only if it's not an IP address. */
382   if (! is_valid_ip_address (hostname))
383     {
384       gnutls_server_name_set (session, GNUTLS_NAME_DNS, hostname,
385                               strlen (hostname));
386     }
387
388   gnutls_set_default_priority (session);
389   gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, credentials);
390 #ifndef FD_TO_SOCKET
391 # define FD_TO_SOCKET(X) (X)
392 #endif
393   gnutls_transport_set_ptr (session, (gnutls_transport_ptr) FD_TO_SOCKET (fd));
394
395   err = 0;
396 #if HAVE_GNUTLS_PRIORITY_SET_DIRECT
397   switch (opt.secure_protocol)
398     {
399     case secure_protocol_auto:
400       break;
401     case secure_protocol_sslv2:
402     case secure_protocol_sslv3:
403       err = gnutls_priority_set_direct (session, "NORMAL:-VERS-TLS-ALL", NULL);
404       break;
405     case secure_protocol_tlsv1:
406       err = gnutls_priority_set_direct (session, "NORMAL:-VERS-SSL3.0", NULL);
407       break;
408     default:
409       abort ();
410     }
411 #else
412   int allowed_protocols[4] = {0, 0, 0, 0};
413   switch (opt.secure_protocol)
414     {
415     case secure_protocol_auto:
416       break;
417     case secure_protocol_sslv2:
418     case secure_protocol_sslv3:
419       allowed_protocols[0] = GNUTLS_SSL3;
420       err = gnutls_protocol_set_priority (session, allowed_protocols);
421       break;
422
423     case secure_protocol_tlsv1:
424       allowed_protocols[0] = GNUTLS_TLS1_0;
425       allowed_protocols[1] = GNUTLS_TLS1_1;
426       allowed_protocols[2] = GNUTLS_TLS1_2;
427       err = gnutls_protocol_set_priority (session, allowed_protocols);
428       break;
429
430     default:
431       abort ();
432     }
433 #endif
434
435   if (err < 0)
436     {
437       logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
438       gnutls_deinit (session);
439       return false;
440     }
441
442   err = gnutls_handshake (session);
443   if (err < 0)
444     {
445       logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
446       gnutls_deinit (session);
447       return false;
448     }
449
450   ctx = xnew0 (struct wgnutls_transport_context);
451   ctx->session = session;
452   fd_register_transport (fd, &wgnutls_transport, ctx);
453   return true;
454 }
455
456 bool
457 ssl_check_certificate (int fd, const char *host)
458 {
459   struct wgnutls_transport_context *ctx = fd_transport_context (fd);
460
461   unsigned int status;
462   int err;
463
464   /* If the user has specified --no-check-cert, we still want to warn
465      him about problems with the server's certificate.  */
466   const char *severity = opt.check_cert ? _("ERROR") : _("WARNING");
467   bool success = true;
468
469   err = gnutls_certificate_verify_peers2 (ctx->session, &status);
470   if (err < 0)
471     {
472       logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
473                  severity, quotearg_style (escape_quoting_style, host));
474       success = false;
475       goto out;
476     }
477
478   if (status & GNUTLS_CERT_INVALID)
479     {
480       logprintf (LOG_NOTQUIET, _("%s: The certificate of %s is not trusted.\n"),
481                  severity, quote (host));
482       success = false;
483     }
484   if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
485     {
486       logprintf (LOG_NOTQUIET, _("%s: The certificate of %s hasn't got a known issuer.\n"),
487                  severity, quote (host));
488       success = false;
489     }
490   if (status & GNUTLS_CERT_REVOKED)
491     {
492       logprintf (LOG_NOTQUIET, _("%s: The certificate of %s has been revoked.\n"),
493                  severity, quote (host));
494       success = false;
495     }
496
497   if (gnutls_certificate_type_get (ctx->session) == GNUTLS_CRT_X509)
498     {
499       time_t now = time (NULL);
500       gnutls_x509_crt cert;
501       const gnutls_datum *cert_list;
502       unsigned int cert_list_size;
503
504       if ((err = gnutls_x509_crt_init (&cert)) < 0)
505         {
506           logprintf (LOG_NOTQUIET, _("Error initializing X509 certificate: %s\n"),
507                      gnutls_strerror (err));
508           success = false;
509           goto out;
510         }
511
512       cert_list = gnutls_certificate_get_peers (ctx->session, &cert_list_size);
513       if (!cert_list)
514         {
515           logprintf (LOG_NOTQUIET, _("No certificate found\n"));
516           success = false;
517           goto out;
518         }
519       err = gnutls_x509_crt_import (cert, cert_list, GNUTLS_X509_FMT_DER);
520       if (err < 0)
521         {
522           logprintf (LOG_NOTQUIET, _("Error parsing certificate: %s\n"),
523                      gnutls_strerror (err));
524           success = false;
525           goto out;
526         }
527       if (now < gnutls_x509_crt_get_activation_time (cert))
528         {
529           logprintf (LOG_NOTQUIET, _("The certificate has not yet been activated\n"));
530           success = false;
531         }
532       if (now >= gnutls_x509_crt_get_expiration_time (cert))
533         {
534           logprintf (LOG_NOTQUIET, _("The certificate has expired\n"));
535           success = false;
536         }
537       if (!gnutls_x509_crt_check_hostname (cert, host))
538         {
539           logprintf (LOG_NOTQUIET,
540                      _("The certificate's owner does not match hostname %s\n"),
541                      quote (host));
542           success = false;
543         }
544       gnutls_x509_crt_deinit (cert);
545    }
546
547  out:
548   return opt.check_cert ? success : true;
549 }