]> sjero.net Git - wget/blob - src/gnutls.c
warc: fix format string for off_t in CDX function.
[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_t 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 && *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_t 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 = NULL;
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       if (fcntl (fd, F_SETFL, flags | O_NONBLOCK))
202         return -1;
203 #else
204       /* XXX: Assume it was blocking before.  */
205       const int one = 1;
206       if (ioctl (fd, FIONBIO, &one) < 0)
207         return -1;
208 #endif
209
210       timer = ptimer_new ();
211       if (timer == NULL)
212         return -1;
213     }
214
215   do
216     {
217       double next_timeout = 0;
218       if (timeout)
219         {
220           next_timeout = timeout - ptimer_measure (timer);
221           if (next_timeout < 0)
222             break;
223         }
224
225       ret = GNUTLS_E_AGAIN;
226       if (timeout == 0 || gnutls_record_check_pending (ctx->session)
227           || select_fd (fd, next_timeout, WAIT_FOR_READ))
228         {
229           ret = gnutls_record_recv (ctx->session, buf, bufsize);
230           timed_out = timeout && ptimer_measure (timer) >= timeout;
231         }
232     }
233   while (ret == GNUTLS_E_INTERRUPTED || (ret == GNUTLS_E_AGAIN && !timed_out));
234
235   if (timeout)
236     {
237       ptimer_destroy (timer);
238
239 #ifdef F_GETFL
240       if (fcntl (fd, F_SETFL, flags) < 0)
241         return -1;
242 #else
243       const int zero = 0;
244       if (ioctl (fd, FIONBIO, &zero) < 0)
245         return -1;
246 #endif
247
248       if (timed_out && ret == GNUTLS_E_AGAIN)
249         errno = ETIMEDOUT;
250     }
251
252   return ret;
253 }
254
255 static int
256 wgnutls_read (int fd, char *buf, int bufsize, void *arg)
257 {
258   int ret = 0;
259   struct wgnutls_transport_context *ctx = arg;
260
261   if (ctx->peeklen)
262     {
263       /* If we have any peek data, simply return that. */
264       int copysize = MIN (bufsize, ctx->peeklen);
265       memcpy (buf, ctx->peekbuf, copysize);
266       ctx->peeklen -= copysize;
267       if (ctx->peeklen != 0)
268         memmove (ctx->peekbuf, ctx->peekbuf + copysize, ctx->peeklen);
269
270       return copysize;
271     }
272
273   ret = wgnutls_read_timeout (fd, buf, bufsize, arg, opt.read_timeout);
274   if (ret < 0)
275     ctx->last_error = ret;
276
277   return ret;
278 }
279
280 static int
281 wgnutls_write (int fd, char *buf, int bufsize, void *arg)
282 {
283   int ret;
284   struct wgnutls_transport_context *ctx = arg;
285   do
286     ret = gnutls_record_send (ctx->session, buf, bufsize);
287   while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
288   if (ret < 0)
289     ctx->last_error = ret;
290   return ret;
291 }
292
293 static int
294 wgnutls_poll (int fd, double timeout, int wait_for, void *arg)
295 {
296   struct wgnutls_transport_context *ctx = arg;
297
298   if (timeout)
299     return ctx->peeklen || gnutls_record_check_pending (ctx->session)
300       || select_fd (fd, timeout, wait_for);
301   else
302     return ctx->peeklen || gnutls_record_check_pending (ctx->session);
303 }
304
305 static int
306 wgnutls_peek (int fd, char *buf, int bufsize, void *arg)
307 {
308   int read = 0;
309   struct wgnutls_transport_context *ctx = arg;
310   int offset = MIN (bufsize, ctx->peeklen);
311
312   if (ctx->peeklen)
313     {
314       memcpy (buf, ctx->peekbuf, offset);
315       return offset;
316     }
317
318   if (bufsize > sizeof ctx->peekbuf)
319     bufsize = sizeof ctx->peekbuf;
320
321   if (bufsize > offset)
322     {
323       if (opt.read_timeout && gnutls_record_check_pending (ctx->session) == 0
324           && select_fd (fd, 0.0, WAIT_FOR_READ) <= 0)
325         read = 0;
326       else
327         read = wgnutls_read_timeout (fd, buf + offset, bufsize - offset,
328                                      ctx, opt.read_timeout);
329       if (read < 0)
330         {
331           if (offset)
332             read = 0;
333           else
334             return read;
335         }
336
337       if (read > 0)
338         {
339           memcpy (ctx->peekbuf + offset, buf + offset,
340                   read);
341           ctx->peeklen += read;
342         }
343     }
344
345   return offset + read;
346 }
347
348 static const char *
349 wgnutls_errstr (int fd, void *arg)
350 {
351   struct wgnutls_transport_context *ctx = arg;
352   return gnutls_strerror (ctx->last_error);
353 }
354
355 static void
356 wgnutls_close (int fd, void *arg)
357 {
358   struct wgnutls_transport_context *ctx = arg;
359   /*gnutls_bye (ctx->session, GNUTLS_SHUT_RDWR);*/
360   gnutls_deinit (ctx->session);
361   xfree (ctx);
362   close (fd);
363 }
364
365 /* gnutls_transport is the singleton that describes the SSL transport
366    methods provided by this file.  */
367
368 static struct transport_implementation wgnutls_transport =
369 {
370   wgnutls_read, wgnutls_write, wgnutls_poll,
371   wgnutls_peek, wgnutls_errstr, wgnutls_close
372 };
373
374 bool
375 ssl_connect_wget (int fd, const char *hostname)
376 {
377   struct wgnutls_transport_context *ctx;
378   gnutls_session_t session;
379   int err;
380   gnutls_init (&session, GNUTLS_CLIENT);
381
382   /* We set the server name but only if it's not an IP address. */
383   if (! is_valid_ip_address (hostname))
384     {
385       gnutls_server_name_set (session, GNUTLS_NAME_DNS, hostname,
386                               strlen (hostname));
387     }
388
389   gnutls_set_default_priority (session);
390   gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, credentials);
391 #ifndef FD_TO_SOCKET
392 # define FD_TO_SOCKET(X) (X)
393 #endif
394   gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) FD_TO_SOCKET (fd));
395
396   err = 0;
397 #if HAVE_GNUTLS_PRIORITY_SET_DIRECT
398   switch (opt.secure_protocol)
399     {
400     case secure_protocol_auto:
401       break;
402     case secure_protocol_sslv2:
403     case secure_protocol_sslv3:
404       err = gnutls_priority_set_direct (session, "NORMAL:-VERS-TLS-ALL", NULL);
405       break;
406     case secure_protocol_tlsv1:
407       err = gnutls_priority_set_direct (session, "NORMAL:-VERS-SSL3.0", NULL);
408       break;
409     default:
410       abort ();
411     }
412 #else
413   int allowed_protocols[4] = {0, 0, 0, 0};
414   switch (opt.secure_protocol)
415     {
416     case secure_protocol_auto:
417       break;
418     case secure_protocol_sslv2:
419     case secure_protocol_sslv3:
420       allowed_protocols[0] = GNUTLS_SSL3;
421       err = gnutls_protocol_set_priority (session, allowed_protocols);
422       break;
423
424     case secure_protocol_tlsv1:
425       allowed_protocols[0] = GNUTLS_TLS1_0;
426       allowed_protocols[1] = GNUTLS_TLS1_1;
427       allowed_protocols[2] = GNUTLS_TLS1_2;
428       err = gnutls_protocol_set_priority (session, allowed_protocols);
429       break;
430
431     default:
432       abort ();
433     }
434 #endif
435
436   if (err < 0)
437     {
438       logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
439       gnutls_deinit (session);
440       return false;
441     }
442
443   err = gnutls_handshake (session);
444   if (err < 0)
445     {
446       logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
447       gnutls_deinit (session);
448       return false;
449     }
450
451   ctx = xnew0 (struct wgnutls_transport_context);
452   ctx->session = session;
453   fd_register_transport (fd, &wgnutls_transport, ctx);
454   return true;
455 }
456
457 bool
458 ssl_check_certificate (int fd, const char *host)
459 {
460   struct wgnutls_transport_context *ctx = fd_transport_context (fd);
461
462   unsigned int status;
463   int err;
464
465   /* If the user has specified --no-check-cert, we still want to warn
466      him about problems with the server's certificate.  */
467   const char *severity = opt.check_cert ? _("ERROR") : _("WARNING");
468   bool success = true;
469
470   err = gnutls_certificate_verify_peers2 (ctx->session, &status);
471   if (err < 0)
472     {
473       logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
474                  severity, quotearg_style (escape_quoting_style, host));
475       success = false;
476       goto out;
477     }
478
479   if (status & GNUTLS_CERT_INVALID)
480     {
481       logprintf (LOG_NOTQUIET, _("%s: The certificate of %s is not trusted.\n"),
482                  severity, quote (host));
483       success = false;
484     }
485   if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
486     {
487       logprintf (LOG_NOTQUIET, _("%s: The certificate of %s hasn't got a known issuer.\n"),
488                  severity, quote (host));
489       success = false;
490     }
491   if (status & GNUTLS_CERT_REVOKED)
492     {
493       logprintf (LOG_NOTQUIET, _("%s: The certificate of %s has been revoked.\n"),
494                  severity, quote (host));
495       success = false;
496     }
497
498   if (gnutls_certificate_type_get (ctx->session) == GNUTLS_CRT_X509)
499     {
500       time_t now = time (NULL);
501       gnutls_x509_crt_t cert;
502       const gnutls_datum_t *cert_list;
503       unsigned int cert_list_size;
504
505       if ((err = gnutls_x509_crt_init (&cert)) < 0)
506         {
507           logprintf (LOG_NOTQUIET, _("Error initializing X509 certificate: %s\n"),
508                      gnutls_strerror (err));
509           success = false;
510           goto out;
511         }
512
513       cert_list = gnutls_certificate_get_peers (ctx->session, &cert_list_size);
514       if (!cert_list)
515         {
516           logprintf (LOG_NOTQUIET, _("No certificate found\n"));
517           success = false;
518           goto crt_deinit;
519         }
520       err = gnutls_x509_crt_import (cert, cert_list, GNUTLS_X509_FMT_DER);
521       if (err < 0)
522         {
523           logprintf (LOG_NOTQUIET, _("Error parsing certificate: %s\n"),
524                      gnutls_strerror (err));
525           success = false;
526           goto crt_deinit;
527         }
528       if (now < gnutls_x509_crt_get_activation_time (cert))
529         {
530           logprintf (LOG_NOTQUIET, _("The certificate has not yet been activated\n"));
531           success = false;
532         }
533       if (now >= gnutls_x509_crt_get_expiration_time (cert))
534         {
535           logprintf (LOG_NOTQUIET, _("The certificate has expired\n"));
536           success = false;
537         }
538       if (!gnutls_x509_crt_check_hostname (cert, host))
539         {
540           logprintf (LOG_NOTQUIET,
541                      _("The certificate's owner does not match hostname %s\n"),
542                      quote (host));
543           success = false;
544         }
545  crt_deinit:
546       gnutls_x509_crt_deinit (cert);
547    }
548
549  out:
550   return opt.check_cert ? success : true;
551 }