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>
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. */
60 static gnutls_certificate_credentials credentials;
64 const char *ca_directory;
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);
72 ca_directory = opt.ca_directory ? opt.ca_directory : "/etc/ssl/certs";
74 dir = opendir (ca_directory);
78 logprintf (LOG_NOTQUIET, _("ERROR: Cannot open directory %s.\n"),
84 while ((dent = readdir (dir)) != NULL)
88 asprintf (&ca_file, "%s/%s", ca_directory, dent->d_name);
92 if (S_ISREG (st.st_mode))
93 gnutls_certificate_set_x509_trust_file (credentials, ca_file,
103 gnutls_certificate_set_x509_trust_file (credentials, opt.ca_cert,
104 GNUTLS_X509_FMT_PEM);
108 struct wgnutls_transport_context
110 gnutls_session session; /* GnuTLS session handle */
111 int last_error; /* last error returned by read/write/... */
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
122 # define MIN(i, j) ((i) <= (j) ? (i) : (j))
127 wgnutls_read_timeout (int fd, char *buf, int bufsize, void *arg, double timeout)
133 struct ptimer *timer;
134 struct wgnutls_transport_context *ctx = arg;
140 flags = fcntl (fd, F_GETFL, 0);
144 timer = ptimer_new ();
151 double next_timeout = timeout - ptimer_measure (timer);
152 if (timeout && next_timeout < 0)
155 ret = GNUTLS_E_AGAIN;
156 if (timeout == 0 || gnutls_record_check_pending (ctx->session)
157 || select_fd (fd, next_timeout, WAIT_FOR_READ))
162 ret = fcntl (fd, F_SETFL, flags | O_NONBLOCK);
166 /* XXX: Assume it was blocking before. */
168 ret = ioctl (fd, FIONBIO, &one);
174 ret = gnutls_record_recv (ctx->session, buf, bufsize);
180 status = fcntl (fd, F_SETFL, flags);
185 status = ioctl (fd, FIONBIO, &zero);
192 timed_out = timeout && ptimer_measure (timer) >= timeout;
194 while (ret == GNUTLS_E_INTERRUPTED || (ret == GNUTLS_E_AGAIN && !timed_out));
197 ptimer_destroy (timer);
199 if (timeout && timed_out && ret == GNUTLS_E_AGAIN)
206 wgnutls_read (int fd, char *buf, int bufsize, void *arg)
212 struct ptimer *timer;
213 struct wgnutls_transport_context *ctx = arg;
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);
227 ret = wgnutls_read_timeout (fd, buf, bufsize, arg, opt.read_timeout);
229 ctx->last_error = ret;
235 wgnutls_write (int fd, char *buf, int bufsize, void *arg)
238 struct wgnutls_transport_context *ctx = arg;
240 ret = gnutls_record_send (ctx->session, buf, bufsize);
241 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
243 ctx->last_error = ret;
248 wgnutls_poll (int fd, double timeout, int wait_for, void *arg)
250 struct wgnutls_transport_context *ctx = arg;
251 return ctx->peeklen || gnutls_record_check_pending (ctx->session)
252 || select_fd (fd, timeout, wait_for);
256 wgnutls_peek (int fd, char *buf, int bufsize, void *arg)
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;
265 memcpy (buf, ctx->peekbuf, offset);
267 if (bufsize > offset)
269 if (gnutls_record_check_pending (ctx->session) <= 0
270 && select_fd (fd, 0.0, WAIT_FOR_READ) <= 0)
273 read = wgnutls_read_timeout (fd, buf + offset, bufsize - offset,
274 ctx, opt.read_timeout);
285 memcpy (ctx->peekbuf + offset, buf + offset,
287 ctx->peeklen += read;
291 return offset + read;
295 wgnutls_errstr (int fd, void *arg)
297 struct wgnutls_transport_context *ctx = arg;
298 return gnutls_strerror (ctx->last_error);
302 wgnutls_close (int fd, void *arg)
304 struct wgnutls_transport_context *ctx = arg;
305 /*gnutls_bye (ctx->session, GNUTLS_SHUT_RDWR);*/
306 gnutls_deinit (ctx->session);
311 /* gnutls_transport is the singleton that describes the SSL transport
312 methods provided by this file. */
314 static struct transport_implementation wgnutls_transport =
316 wgnutls_read, wgnutls_write, wgnutls_poll,
317 wgnutls_peek, wgnutls_errstr, wgnutls_close
321 ssl_connect_wget (int fd)
323 struct wgnutls_transport_context *ctx;
324 gnutls_session session;
326 gnutls_init (&session, GNUTLS_CLIENT);
327 gnutls_set_default_priority (session);
328 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, credentials);
330 # define FD_TO_SOCKET(X) (X)
332 gnutls_transport_set_ptr (session, (gnutls_transport_ptr) FD_TO_SOCKET (fd));
335 #if HAVE_GNUTLS_PRIORITY_SET_DIRECT
336 switch (opt.secure_protocol)
338 case secure_protocol_auto:
340 case secure_protocol_sslv2:
341 case secure_protocol_sslv3:
342 err = gnutls_priority_set_direct (session, "NORMAL:-VERS-TLS-ALL", NULL);
344 case secure_protocol_tlsv1:
345 err = gnutls_priority_set_direct (session, "NORMAL:-VERS-SSL3.0", NULL);
351 int allowed_protocols[4] = {0, 0, 0, 0};
352 switch (opt.secure_protocol)
354 case secure_protocol_auto:
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);
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);
376 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
377 gnutls_deinit (session);
381 err = gnutls_handshake (session);
384 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
385 gnutls_deinit (session);
389 ctx = xnew0 (struct wgnutls_transport_context);
390 ctx->session = session;
391 fd_register_transport (fd, &wgnutls_transport, ctx);
396 ssl_check_certificate (int fd, const char *host)
398 struct wgnutls_transport_context *ctx = fd_transport_context (fd);
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");
408 err = gnutls_certificate_verify_peers2 (ctx->session, &status);
411 logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
412 severity, quotearg_style (escape_quoting_style, host));
417 if (status & GNUTLS_CERT_INVALID)
419 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s is not trusted.\n"),
420 severity, quote (host));
423 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
425 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s hasn't got a known issuer.\n"),
426 severity, quote (host));
429 if (status & GNUTLS_CERT_REVOKED)
431 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s has been revoked.\n"),
432 severity, quote (host));
436 if (gnutls_certificate_type_get (ctx->session) == GNUTLS_CRT_X509)
438 time_t now = time (NULL);
439 gnutls_x509_crt cert;
440 const gnutls_datum *cert_list;
441 unsigned int cert_list_size;
443 if ((err = gnutls_x509_crt_init (&cert)) < 0)
445 logprintf (LOG_NOTQUIET, _("Error initializing X509 certificate: %s\n"),
446 gnutls_strerror (err));
451 cert_list = gnutls_certificate_get_peers (ctx->session, &cert_list_size);
454 logprintf (LOG_NOTQUIET, _("No certificate found\n"));
458 err = gnutls_x509_crt_import (cert, cert_list, GNUTLS_X509_FMT_DER);
461 logprintf (LOG_NOTQUIET, _("Error parsing certificate: %s\n"),
462 gnutls_strerror (err));
466 if (now < gnutls_x509_crt_get_activation_time (cert))
468 logprintf (LOG_NOTQUIET, _("The certificate has not yet been activated\n"));
471 if (now >= gnutls_x509_crt_get_expiration_time (cert))
473 logprintf (LOG_NOTQUIET, _("The certificate has expired\n"));
476 if (!gnutls_x509_crt_check_hostname (cert, host))
478 logprintf (LOG_NOTQUIET,
479 _("The certificate's owner does not match hostname %s\n"),
483 gnutls_x509_crt_deinit (cert);
487 return opt.check_cert ? success : true;