1 /* SSL support via GnuTLS library.
2 Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
5 This file is part of GNU Wget.
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.
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.
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/>.
20 Additional permission under GNU GPL version 3 section 7
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. */
41 #include <gnutls/gnutls.h>
42 #include <gnutls/x509.h>
43 #include <sys/ioctl.h>
51 #include <sys/fcntl.h>
57 /* Note: some of the functions private to this file have names that
58 begin with "wgnutls_" (e.g. wgnutls_read) so that they wouldn't be
59 confused with actual gnutls functions -- such as the gnutls_read
60 preprocessor macro. */
62 static gnutls_certificate_credentials credentials;
66 const char *ca_directory;
69 gnutls_global_init ();
70 gnutls_certificate_allocate_credentials (&credentials);
71 gnutls_certificate_set_verify_flags(credentials,
72 GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
74 ca_directory = opt.ca_directory ? opt.ca_directory : "/etc/ssl/certs";
76 dir = opendir (ca_directory);
80 logprintf (LOG_NOTQUIET, _("ERROR: Cannot open directory %s.\n"),
86 while ((dent = readdir (dir)) != NULL)
90 asprintf (&ca_file, "%s/%s", ca_directory, dent->d_name);
94 if (S_ISREG (st.st_mode))
95 gnutls_certificate_set_x509_trust_file (credentials, ca_file,
105 gnutls_certificate_set_x509_trust_file (credentials, opt.ca_cert,
106 GNUTLS_X509_FMT_PEM);
110 struct wgnutls_transport_context
112 gnutls_session session; /* GnuTLS session handle */
113 int last_error; /* last error returned by read/write/... */
115 /* Since GnuTLS doesn't support the equivalent to recv(...,
116 MSG_PEEK) or SSL_peek(), we have to do it ourselves. Peeked data
117 is stored to PEEKBUF, and wgnutls_read checks that buffer before
124 # define MIN(i, j) ((i) <= (j) ? (i) : (j))
129 wgnutls_read_timeout (int fd, char *buf, int bufsize, void *arg, double timeout)
135 struct ptimer *timer;
136 struct wgnutls_transport_context *ctx = arg;
142 flags = fcntl (fd, F_GETFL, 0);
146 timer = ptimer_new ();
153 double next_timeout = timeout - ptimer_measure (timer);
154 if (timeout && next_timeout < 0)
157 ret = GNUTLS_E_AGAIN;
158 if (timeout == 0 || gnutls_record_check_pending (ctx->session)
159 || select_fd (fd, next_timeout, WAIT_FOR_READ))
164 ret = fcntl (fd, F_SETFL, flags | O_NONBLOCK);
168 /* XXX: Assume it was blocking before. */
170 ret = ioctl (fd, FIONBIO, &one);
176 ret = gnutls_record_recv (ctx->session, buf, bufsize);
182 status = fcntl (fd, F_SETFL, flags);
187 status = ioctl (fd, FIONBIO, &zero);
194 timed_out = timeout && ptimer_measure (timer) >= timeout;
196 while (ret == GNUTLS_E_INTERRUPTED || (ret == GNUTLS_E_AGAIN && !timed_out));
199 ptimer_destroy (timer);
201 if (timeout && timed_out && ret == GNUTLS_E_AGAIN)
208 wgnutls_read (int fd, char *buf, int bufsize, void *arg)
214 struct ptimer *timer;
215 struct wgnutls_transport_context *ctx = arg;
219 /* If we have any peek data, simply return that. */
220 int copysize = MIN (bufsize, ctx->peeklen);
221 memcpy (buf, ctx->peekbuf, copysize);
222 ctx->peeklen -= copysize;
223 if (ctx->peeklen != 0)
224 memmove (ctx->peekbuf, ctx->peekbuf + copysize, ctx->peeklen);
229 ret = wgnutls_read_timeout (fd, buf, bufsize, arg, opt.read_timeout);
231 ctx->last_error = ret;
237 wgnutls_write (int fd, char *buf, int bufsize, void *arg)
240 struct wgnutls_transport_context *ctx = arg;
242 ret = gnutls_record_send (ctx->session, buf, bufsize);
243 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
245 ctx->last_error = ret;
250 wgnutls_poll (int fd, double timeout, int wait_for, void *arg)
252 struct wgnutls_transport_context *ctx = arg;
253 return ctx->peeklen || gnutls_record_check_pending (ctx->session)
254 || select_fd (fd, timeout, wait_for);
258 wgnutls_peek (int fd, char *buf, int bufsize, void *arg)
261 struct wgnutls_transport_context *ctx = arg;
262 int offset = MIN (bufsize, ctx->peeklen);
263 if (bufsize > sizeof ctx->peekbuf)
264 bufsize = sizeof ctx->peekbuf;
267 memcpy (buf, ctx->peekbuf, offset);
269 if (bufsize > offset)
271 if (gnutls_record_check_pending (ctx->session) <= 0
272 && select_fd (fd, 0.0, WAIT_FOR_READ) <= 0)
275 read = wgnutls_read_timeout (fd, buf + offset, bufsize - offset,
276 ctx, opt.read_timeout);
287 memcpy (ctx->peekbuf + offset, buf + offset,
289 ctx->peeklen += read;
293 return offset + read;
297 wgnutls_errstr (int fd, void *arg)
299 struct wgnutls_transport_context *ctx = arg;
300 return gnutls_strerror (ctx->last_error);
304 wgnutls_close (int fd, void *arg)
306 struct wgnutls_transport_context *ctx = arg;
307 /*gnutls_bye (ctx->session, GNUTLS_SHUT_RDWR);*/
308 gnutls_deinit (ctx->session);
313 /* gnutls_transport is the singleton that describes the SSL transport
314 methods provided by this file. */
316 static struct transport_implementation wgnutls_transport =
318 wgnutls_read, wgnutls_write, wgnutls_poll,
319 wgnutls_peek, wgnutls_errstr, wgnutls_close
323 ssl_connect_wget (int fd)
325 struct wgnutls_transport_context *ctx;
326 gnutls_session session;
328 gnutls_init (&session, GNUTLS_CLIENT);
329 gnutls_set_default_priority (session);
330 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, credentials);
332 # define FD_TO_SOCKET(X) (X)
334 gnutls_transport_set_ptr (session, (gnutls_transport_ptr) FD_TO_SOCKET (fd));
337 #if HAVE_GNUTLS_PRIORITY_SET_DIRECT
338 switch (opt.secure_protocol)
340 case secure_protocol_auto:
342 case secure_protocol_sslv2:
343 case secure_protocol_sslv3:
344 err = gnutls_priority_set_direct (session, "NORMAL:-VERS-TLS-ALL", NULL);
346 case secure_protocol_tlsv1:
347 err = gnutls_priority_set_direct (session, "NORMAL:-VERS-SSL3.0", NULL);
353 int allowed_protocols[4] = {0, 0, 0, 0};
354 switch (opt.secure_protocol)
356 case secure_protocol_auto:
358 case secure_protocol_sslv2:
359 case secure_protocol_sslv3:
360 allowed_protocols[0] = GNUTLS_SSL3;
361 err = gnutls_protocol_set_priority (session, allowed_protocols);
364 case secure_protocol_tlsv1:
365 allowed_protocols[0] = GNUTLS_TLS1_0;
366 allowed_protocols[1] = GNUTLS_TLS1_1;
367 allowed_protocols[2] = GNUTLS_TLS1_2;
368 err = gnutls_protocol_set_priority (session, allowed_protocols);
378 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
379 gnutls_deinit (session);
383 err = gnutls_handshake (session);
386 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
387 gnutls_deinit (session);
391 ctx = xnew0 (struct wgnutls_transport_context);
392 ctx->session = session;
393 fd_register_transport (fd, &wgnutls_transport, ctx);
398 ssl_check_certificate (int fd, const char *host)
400 struct wgnutls_transport_context *ctx = fd_transport_context (fd);
405 /* If the user has specified --no-check-cert, we still want to warn
406 him about problems with the server's certificate. */
407 const char *severity = opt.check_cert ? _("ERROR") : _("WARNING");
410 err = gnutls_certificate_verify_peers2 (ctx->session, &status);
413 logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
414 severity, quotearg_style (escape_quoting_style, host));
419 if (status & GNUTLS_CERT_INVALID)
421 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s is not trusted.\n"),
422 severity, quote (host));
425 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
427 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s hasn't got a known issuer.\n"),
428 severity, quote (host));
431 if (status & GNUTLS_CERT_REVOKED)
433 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s has been revoked.\n"),
434 severity, quote (host));
438 if (gnutls_certificate_type_get (ctx->session) == GNUTLS_CRT_X509)
440 time_t now = time (NULL);
441 gnutls_x509_crt cert;
442 const gnutls_datum *cert_list;
443 unsigned int cert_list_size;
445 if ((err = gnutls_x509_crt_init (&cert)) < 0)
447 logprintf (LOG_NOTQUIET, _("Error initializing X509 certificate: %s\n"),
448 gnutls_strerror (err));
453 cert_list = gnutls_certificate_get_peers (ctx->session, &cert_list_size);
456 logprintf (LOG_NOTQUIET, _("No certificate found\n"));
460 err = gnutls_x509_crt_import (cert, cert_list, GNUTLS_X509_FMT_DER);
463 logprintf (LOG_NOTQUIET, _("Error parsing certificate: %s\n"),
464 gnutls_strerror (err));
468 if (now < gnutls_x509_crt_get_activation_time (cert))
470 logprintf (LOG_NOTQUIET, _("The certificate has not yet been activated\n"));
473 if (now >= gnutls_x509_crt_get_expiration_time (cert))
475 logprintf (LOG_NOTQUIET, _("The certificate has expired\n"));
478 if (!gnutls_x509_crt_check_hostname (cert, host))
480 logprintf (LOG_NOTQUIET,
481 _("The certificate's owner does not match hostname %s\n"),
485 gnutls_x509_crt_deinit (cert);
489 return opt.check_cert ? success : true;