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 ret = fcntl (fd, F_SETFL, flags | O_NONBLOCK);
148 /* XXX: Assume it was blocking before. */
150 ret = ioctl (fd, FIONBIO, &one);
154 timer = ptimer_new ();
161 double timeout = timeout - ptimer_measure (timer);
165 ret = GNUTLS_E_AGAIN;
166 if (timeout == 0 || gnutls_record_check_pending (ctx->session)
167 || select_fd (fd, timeout, WAIT_FOR_READ))
168 ret = gnutls_record_recv (ctx->session, buf, bufsize);
170 timed_out = timeout && ptimer_measure (timer) >= timeout;
172 while (ret == GNUTLS_E_INTERRUPTED || (ret == GNUTLS_E_AGAIN && !timed_out));
177 ptimer_destroy (timer);
179 status = fcntl (fd, F_SETFL, flags);
184 status = ioctl (fd, FIONBIO, &zero);
194 wgnutls_read (int fd, char *buf, int bufsize, void *arg)
200 struct ptimer *timer;
201 struct wgnutls_transport_context *ctx = arg;
205 /* If we have any peek data, simply return that. */
206 int copysize = MIN (bufsize, ctx->peeklen);
207 memcpy (buf, ctx->peekbuf, copysize);
208 ctx->peeklen -= copysize;
209 if (ctx->peeklen != 0)
210 memmove (ctx->peekbuf, ctx->peekbuf + copysize, ctx->peeklen);
215 ret = wgnutls_read_timeout (fd, buf, bufsize, arg, opt.read_timeout);
217 ctx->last_error = ret;
223 wgnutls_write (int fd, char *buf, int bufsize, void *arg)
226 struct wgnutls_transport_context *ctx = arg;
228 ret = gnutls_record_send (ctx->session, buf, bufsize);
229 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
231 ctx->last_error = ret;
236 wgnutls_poll (int fd, double timeout, int wait_for, void *arg)
238 struct wgnutls_transport_context *ctx = arg;
239 return ctx->peeklen || gnutls_record_check_pending (ctx->session)
240 || select_fd (fd, timeout, wait_for);
244 wgnutls_peek (int fd, char *buf, int bufsize, void *arg)
247 struct wgnutls_transport_context *ctx = arg;
248 int offset = MIN (bufsize, ctx->peeklen);
249 if (bufsize > sizeof ctx->peekbuf)
250 bufsize = sizeof ctx->peekbuf;
253 memcpy (buf, ctx->peekbuf, offset);
255 if (bufsize > offset)
257 if (gnutls_record_check_pending (ctx->session) <= 0
258 && select_fd (fd, 0.0, WAIT_FOR_READ) <= 0)
261 read = wgnutls_read_timeout (fd, buf + offset, bufsize - offset,
262 ctx->session, opt.read_timeout);
273 memcpy (ctx->peekbuf + offset, buf + offset,
275 ctx->peeklen += read;
279 return offset + read;
283 wgnutls_errstr (int fd, void *arg)
285 struct wgnutls_transport_context *ctx = arg;
286 return gnutls_strerror (ctx->last_error);
290 wgnutls_close (int fd, void *arg)
292 struct wgnutls_transport_context *ctx = arg;
293 /*gnutls_bye (ctx->session, GNUTLS_SHUT_RDWR);*/
294 gnutls_deinit (ctx->session);
299 /* gnutls_transport is the singleton that describes the SSL transport
300 methods provided by this file. */
302 static struct transport_implementation wgnutls_transport =
304 wgnutls_read, wgnutls_write, wgnutls_poll,
305 wgnutls_peek, wgnutls_errstr, wgnutls_close
309 ssl_connect_wget (int fd)
311 struct wgnutls_transport_context *ctx;
312 gnutls_session session;
314 gnutls_init (&session, GNUTLS_CLIENT);
315 gnutls_set_default_priority (session);
316 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, credentials);
318 # define FD_TO_SOCKET(X) (X)
320 gnutls_transport_set_ptr (session, (gnutls_transport_ptr) FD_TO_SOCKET (fd));
323 #if HAVE_GNUTLS_PRIORITY_SET_DIRECT
324 switch (opt.secure_protocol)
326 case secure_protocol_auto:
328 case secure_protocol_sslv2:
329 case secure_protocol_sslv3:
330 err = gnutls_priority_set_direct (session, "NORMAL:-VERS-TLS-ALL", NULL);
332 case secure_protocol_tlsv1:
333 err = gnutls_priority_set_direct (session, "NORMAL:-VERS-SSL3.0", NULL);
339 int allowed_protocols[4] = {0, 0, 0, 0};
340 switch (opt.secure_protocol)
342 case secure_protocol_auto:
344 case secure_protocol_sslv2:
345 case secure_protocol_sslv3:
346 allowed_protocols[0] = GNUTLS_SSL3;
347 err = gnutls_protocol_set_priority (session, allowed_protocols);
350 case secure_protocol_tlsv1:
351 allowed_protocols[0] = GNUTLS_TLS1_0;
352 allowed_protocols[1] = GNUTLS_TLS1_1;
353 allowed_protocols[2] = GNUTLS_TLS1_2;
354 err = gnutls_protocol_set_priority (session, allowed_protocols);
364 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
365 gnutls_deinit (session);
369 err = gnutls_handshake (session);
372 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
373 gnutls_deinit (session);
377 ctx = xnew0 (struct wgnutls_transport_context);
378 ctx->session = session;
379 fd_register_transport (fd, &wgnutls_transport, ctx);
384 ssl_check_certificate (int fd, const char *host)
386 struct wgnutls_transport_context *ctx = fd_transport_context (fd);
391 /* If the user has specified --no-check-cert, we still want to warn
392 him about problems with the server's certificate. */
393 const char *severity = opt.check_cert ? _("ERROR") : _("WARNING");
396 err = gnutls_certificate_verify_peers2 (ctx->session, &status);
399 logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
400 severity, quotearg_style (escape_quoting_style, host));
405 if (status & GNUTLS_CERT_INVALID)
407 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s is not trusted.\n"),
408 severity, quote (host));
411 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
413 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s hasn't got a known issuer.\n"),
414 severity, quote (host));
417 if (status & GNUTLS_CERT_REVOKED)
419 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s has been revoked.\n"),
420 severity, quote (host));
424 if (gnutls_certificate_type_get (ctx->session) == GNUTLS_CRT_X509)
426 time_t now = time (NULL);
427 gnutls_x509_crt cert;
428 const gnutls_datum *cert_list;
429 unsigned int cert_list_size;
431 if ((err = gnutls_x509_crt_init (&cert)) < 0)
433 logprintf (LOG_NOTQUIET, _("Error initializing X509 certificate: %s\n"),
434 gnutls_strerror (err));
439 cert_list = gnutls_certificate_get_peers (ctx->session, &cert_list_size);
442 logprintf (LOG_NOTQUIET, _("No certificate found\n"));
446 err = gnutls_x509_crt_import (cert, cert_list, GNUTLS_X509_FMT_DER);
449 logprintf (LOG_NOTQUIET, _("Error parsing certificate: %s\n"),
450 gnutls_strerror (err));
454 if (now < gnutls_x509_crt_get_activation_time (cert))
456 logprintf (LOG_NOTQUIET, _("The certificate has not yet been activated\n"));
459 if (now >= gnutls_x509_crt_get_expiration_time (cert))
461 logprintf (LOG_NOTQUIET, _("The certificate has expired\n"));
464 if (!gnutls_x509_crt_check_hostname (cert, host))
466 logprintf (LOG_NOTQUIET,
467 _("The certificate's owner does not match hostname %s\n"),
471 gnutls_x509_crt_deinit (cert);
475 return opt.check_cert ? success : true;