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