1 /* SSL support via GnuTLS library.
2 Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 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 /* Becomes true if GnuTLS is initialized. */
67 static bool ssl_initialized = false;
69 /* GnuTLS should be initialized only once. */
73 const char *ca_directory;
76 gnutls_global_init ();
77 gnutls_certificate_allocate_credentials (&credentials);
78 gnutls_certificate_set_verify_flags(credentials,
79 GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
81 ca_directory = opt.ca_directory ? opt.ca_directory : "/etc/ssl/certs";
83 dir = opendir (ca_directory);
87 logprintf (LOG_NOTQUIET, _("ERROR: Cannot open directory %s.\n"),
93 while ((dent = readdir (dir)) != NULL)
97 asprintf (&ca_file, "%s/%s", ca_directory, dent->d_name);
101 if (S_ISREG (st.st_mode))
102 gnutls_certificate_set_x509_trust_file (credentials, ca_file,
103 GNUTLS_X509_FMT_PEM);
112 gnutls_certificate_set_x509_trust_file (credentials, opt.ca_cert,
113 GNUTLS_X509_FMT_PEM);
115 ssl_initialized = true;
120 struct wgnutls_transport_context
122 gnutls_session session; /* GnuTLS session handle */
123 int last_error; /* last error returned by read/write/... */
125 /* Since GnuTLS doesn't support the equivalent to recv(...,
126 MSG_PEEK) or SSL_peek(), we have to do it ourselves. Peeked data
127 is stored to PEEKBUF, and wgnutls_read checks that buffer before
134 # define MIN(i, j) ((i) <= (j) ? (i) : (j))
139 wgnutls_read_timeout (int fd, char *buf, int bufsize, void *arg, double timeout)
145 struct ptimer *timer;
146 struct wgnutls_transport_context *ctx = arg;
152 flags = fcntl (fd, F_GETFL, 0);
156 timer = ptimer_new ();
166 next_timeout = timeout - ptimer_measure (timer);
167 if (next_timeout < 0.0)
171 ret = GNUTLS_E_AGAIN;
172 if (timeout == 0 || gnutls_record_check_pending (ctx->session)
173 || select_fd (fd, next_timeout, WAIT_FOR_READ))
178 if (fcntl (fd, F_SETFL, flags | O_NONBLOCK))
181 /* XXX: Assume it was blocking before. */
183 if (ioctl (fd, FIONBIO, &one) < 0)
188 ret = gnutls_record_recv (ctx->session, buf, bufsize);
193 if (fcntl (fd, F_SETFL, flags) < 0)
197 if (ioctl (fd, FIONBIO, &zero) < 0)
203 timed_out = timeout && ptimer_measure (timer) >= timeout;
205 while (ret == GNUTLS_E_INTERRUPTED || (ret == GNUTLS_E_AGAIN && !timed_out));
208 ptimer_destroy (timer);
210 if (timeout && timed_out && ret == GNUTLS_E_AGAIN)
217 wgnutls_read (int fd, char *buf, int bufsize, void *arg)
220 struct wgnutls_transport_context *ctx = arg;
224 /* If we have any peek data, simply return that. */
225 int copysize = MIN (bufsize, ctx->peeklen);
226 memcpy (buf, ctx->peekbuf, copysize);
227 ctx->peeklen -= copysize;
228 if (ctx->peeklen != 0)
229 memmove (ctx->peekbuf, ctx->peekbuf + copysize, ctx->peeklen);
234 ret = wgnutls_read_timeout (fd, buf, bufsize, arg, opt.read_timeout);
236 ctx->last_error = ret;
242 wgnutls_write (int fd, char *buf, int bufsize, void *arg)
245 struct wgnutls_transport_context *ctx = arg;
247 ret = gnutls_record_send (ctx->session, buf, bufsize);
248 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
250 ctx->last_error = ret;
255 wgnutls_poll (int fd, double timeout, int wait_for, void *arg)
257 struct wgnutls_transport_context *ctx = arg;
258 return ctx->peeklen || gnutls_record_check_pending (ctx->session)
259 || select_fd (fd, timeout, wait_for);
263 wgnutls_peek (int fd, char *buf, int bufsize, void *arg)
266 struct wgnutls_transport_context *ctx = arg;
267 int offset = MIN (bufsize, ctx->peeklen);
268 if (bufsize > sizeof ctx->peekbuf)
269 bufsize = sizeof ctx->peekbuf;
272 memcpy (buf, ctx->peekbuf, offset);
274 if (bufsize > offset)
276 if (gnutls_record_check_pending (ctx->session) <= 0
277 && select_fd (fd, 0.0, WAIT_FOR_READ) <= 0)
280 read = wgnutls_read_timeout (fd, buf + offset, bufsize - offset,
281 ctx, opt.read_timeout);
292 memcpy (ctx->peekbuf + offset, buf + offset,
294 ctx->peeklen += read;
298 return offset + read;
302 wgnutls_errstr (int fd, void *arg)
304 struct wgnutls_transport_context *ctx = arg;
305 return gnutls_strerror (ctx->last_error);
309 wgnutls_close (int fd, void *arg)
311 struct wgnutls_transport_context *ctx = arg;
312 /*gnutls_bye (ctx->session, GNUTLS_SHUT_RDWR);*/
313 gnutls_deinit (ctx->session);
318 /* gnutls_transport is the singleton that describes the SSL transport
319 methods provided by this file. */
321 static struct transport_implementation wgnutls_transport =
323 wgnutls_read, wgnutls_write, wgnutls_poll,
324 wgnutls_peek, wgnutls_errstr, wgnutls_close
328 ssl_connect_wget (int fd)
330 struct wgnutls_transport_context *ctx;
331 gnutls_session session;
333 gnutls_init (&session, GNUTLS_CLIENT);
334 gnutls_set_default_priority (session);
335 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, credentials);
337 # define FD_TO_SOCKET(X) (X)
339 gnutls_transport_set_ptr (session, (gnutls_transport_ptr) FD_TO_SOCKET (fd));
342 #if HAVE_GNUTLS_PRIORITY_SET_DIRECT
343 switch (opt.secure_protocol)
345 case secure_protocol_auto:
347 case secure_protocol_sslv2:
348 case secure_protocol_sslv3:
349 err = gnutls_priority_set_direct (session, "NORMAL:-VERS-TLS-ALL", NULL);
351 case secure_protocol_tlsv1:
352 err = gnutls_priority_set_direct (session, "NORMAL:-VERS-SSL3.0", NULL);
358 int allowed_protocols[4] = {0, 0, 0, 0};
359 switch (opt.secure_protocol)
361 case secure_protocol_auto:
363 case secure_protocol_sslv2:
364 case secure_protocol_sslv3:
365 allowed_protocols[0] = GNUTLS_SSL3;
366 err = gnutls_protocol_set_priority (session, allowed_protocols);
369 case secure_protocol_tlsv1:
370 allowed_protocols[0] = GNUTLS_TLS1_0;
371 allowed_protocols[1] = GNUTLS_TLS1_1;
372 allowed_protocols[2] = GNUTLS_TLS1_2;
373 err = gnutls_protocol_set_priority (session, allowed_protocols);
383 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
384 gnutls_deinit (session);
388 err = gnutls_handshake (session);
391 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
392 gnutls_deinit (session);
396 ctx = xnew0 (struct wgnutls_transport_context);
397 ctx->session = session;
398 fd_register_transport (fd, &wgnutls_transport, ctx);
403 ssl_check_certificate (int fd, const char *host)
405 struct wgnutls_transport_context *ctx = fd_transport_context (fd);
410 /* If the user has specified --no-check-cert, we still want to warn
411 him about problems with the server's certificate. */
412 const char *severity = opt.check_cert ? _("ERROR") : _("WARNING");
415 err = gnutls_certificate_verify_peers2 (ctx->session, &status);
418 logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
419 severity, quotearg_style (escape_quoting_style, host));
424 if (status & GNUTLS_CERT_INVALID)
426 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s is not trusted.\n"),
427 severity, quote (host));
430 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
432 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s hasn't got a known issuer.\n"),
433 severity, quote (host));
436 if (status & GNUTLS_CERT_REVOKED)
438 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s has been revoked.\n"),
439 severity, quote (host));
443 if (gnutls_certificate_type_get (ctx->session) == GNUTLS_CRT_X509)
445 time_t now = time (NULL);
446 gnutls_x509_crt cert;
447 const gnutls_datum *cert_list;
448 unsigned int cert_list_size;
450 if ((err = gnutls_x509_crt_init (&cert)) < 0)
452 logprintf (LOG_NOTQUIET, _("Error initializing X509 certificate: %s\n"),
453 gnutls_strerror (err));
458 cert_list = gnutls_certificate_get_peers (ctx->session, &cert_list_size);
461 logprintf (LOG_NOTQUIET, _("No certificate found\n"));
465 err = gnutls_x509_crt_import (cert, cert_list, GNUTLS_X509_FMT_DER);
468 logprintf (LOG_NOTQUIET, _("Error parsing certificate: %s\n"),
469 gnutls_strerror (err));
473 if (now < gnutls_x509_crt_get_activation_time (cert))
475 logprintf (LOG_NOTQUIET, _("The certificate has not yet been activated\n"));
478 if (now >= gnutls_x509_crt_get_expiration_time (cert))
480 logprintf (LOG_NOTQUIET, _("The certificate has expired\n"));
483 if (!gnutls_x509_crt_check_hostname (cert, host))
485 logprintf (LOG_NOTQUIET,
486 _("The certificate's owner does not match hostname %s\n"),
490 gnutls_x509_crt_deinit (cert);
494 return opt.check_cert ? success : true;