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 /* 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 ();
163 double next_timeout = timeout - ptimer_measure (timer);
164 if (timeout && next_timeout < 0)
167 ret = GNUTLS_E_AGAIN;
168 if (timeout == 0 || gnutls_record_check_pending (ctx->session)
169 || select_fd (fd, next_timeout, WAIT_FOR_READ))
174 ret = fcntl (fd, F_SETFL, flags | O_NONBLOCK);
178 /* XXX: Assume it was blocking before. */
180 ret = ioctl (fd, FIONBIO, &one);
186 ret = gnutls_record_recv (ctx->session, buf, bufsize);
192 status = fcntl (fd, F_SETFL, flags);
197 status = ioctl (fd, FIONBIO, &zero);
204 timed_out = timeout && ptimer_measure (timer) >= timeout;
206 while (ret == GNUTLS_E_INTERRUPTED || (ret == GNUTLS_E_AGAIN && !timed_out));
209 ptimer_destroy (timer);
211 if (timeout && timed_out && ret == GNUTLS_E_AGAIN)
218 wgnutls_read (int fd, char *buf, int bufsize, void *arg)
224 struct ptimer *timer;
225 struct wgnutls_transport_context *ctx = arg;
229 /* If we have any peek data, simply return that. */
230 int copysize = MIN (bufsize, ctx->peeklen);
231 memcpy (buf, ctx->peekbuf, copysize);
232 ctx->peeklen -= copysize;
233 if (ctx->peeklen != 0)
234 memmove (ctx->peekbuf, ctx->peekbuf + copysize, ctx->peeklen);
239 ret = wgnutls_read_timeout (fd, buf, bufsize, arg, opt.read_timeout);
241 ctx->last_error = ret;
247 wgnutls_write (int fd, char *buf, int bufsize, void *arg)
250 struct wgnutls_transport_context *ctx = arg;
252 ret = gnutls_record_send (ctx->session, buf, bufsize);
253 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
255 ctx->last_error = ret;
260 wgnutls_poll (int fd, double timeout, int wait_for, void *arg)
262 struct wgnutls_transport_context *ctx = arg;
263 return ctx->peeklen || gnutls_record_check_pending (ctx->session)
264 || select_fd (fd, timeout, wait_for);
268 wgnutls_peek (int fd, char *buf, int bufsize, void *arg)
271 struct wgnutls_transport_context *ctx = arg;
272 int offset = MIN (bufsize, ctx->peeklen);
273 if (bufsize > sizeof ctx->peekbuf)
274 bufsize = sizeof ctx->peekbuf;
277 memcpy (buf, ctx->peekbuf, offset);
279 if (bufsize > offset)
281 if (gnutls_record_check_pending (ctx->session) <= 0
282 && select_fd (fd, 0.0, WAIT_FOR_READ) <= 0)
285 read = wgnutls_read_timeout (fd, buf + offset, bufsize - offset,
286 ctx, opt.read_timeout);
297 memcpy (ctx->peekbuf + offset, buf + offset,
299 ctx->peeklen += read;
303 return offset + read;
307 wgnutls_errstr (int fd, void *arg)
309 struct wgnutls_transport_context *ctx = arg;
310 return gnutls_strerror (ctx->last_error);
314 wgnutls_close (int fd, void *arg)
316 struct wgnutls_transport_context *ctx = arg;
317 /*gnutls_bye (ctx->session, GNUTLS_SHUT_RDWR);*/
318 gnutls_deinit (ctx->session);
323 /* gnutls_transport is the singleton that describes the SSL transport
324 methods provided by this file. */
326 static struct transport_implementation wgnutls_transport =
328 wgnutls_read, wgnutls_write, wgnutls_poll,
329 wgnutls_peek, wgnutls_errstr, wgnutls_close
333 ssl_connect_wget (int fd)
335 struct wgnutls_transport_context *ctx;
336 gnutls_session session;
338 gnutls_init (&session, GNUTLS_CLIENT);
339 gnutls_set_default_priority (session);
340 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, credentials);
342 # define FD_TO_SOCKET(X) (X)
344 gnutls_transport_set_ptr (session, (gnutls_transport_ptr) FD_TO_SOCKET (fd));
347 #if HAVE_GNUTLS_PRIORITY_SET_DIRECT
348 switch (opt.secure_protocol)
350 case secure_protocol_auto:
352 case secure_protocol_sslv2:
353 case secure_protocol_sslv3:
354 err = gnutls_priority_set_direct (session, "NORMAL:-VERS-TLS-ALL", NULL);
356 case secure_protocol_tlsv1:
357 err = gnutls_priority_set_direct (session, "NORMAL:-VERS-SSL3.0", NULL);
363 int allowed_protocols[4] = {0, 0, 0, 0};
364 switch (opt.secure_protocol)
366 case secure_protocol_auto:
368 case secure_protocol_sslv2:
369 case secure_protocol_sslv3:
370 allowed_protocols[0] = GNUTLS_SSL3;
371 err = gnutls_protocol_set_priority (session, allowed_protocols);
374 case secure_protocol_tlsv1:
375 allowed_protocols[0] = GNUTLS_TLS1_0;
376 allowed_protocols[1] = GNUTLS_TLS1_1;
377 allowed_protocols[2] = GNUTLS_TLS1_2;
378 err = gnutls_protocol_set_priority (session, allowed_protocols);
388 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
389 gnutls_deinit (session);
393 err = gnutls_handshake (session);
396 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
397 gnutls_deinit (session);
401 ctx = xnew0 (struct wgnutls_transport_context);
402 ctx->session = session;
403 fd_register_transport (fd, &wgnutls_transport, ctx);
408 ssl_check_certificate (int fd, const char *host)
410 struct wgnutls_transport_context *ctx = fd_transport_context (fd);
415 /* If the user has specified --no-check-cert, we still want to warn
416 him about problems with the server's certificate. */
417 const char *severity = opt.check_cert ? _("ERROR") : _("WARNING");
420 err = gnutls_certificate_verify_peers2 (ctx->session, &status);
423 logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
424 severity, quotearg_style (escape_quoting_style, host));
429 if (status & GNUTLS_CERT_INVALID)
431 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s is not trusted.\n"),
432 severity, quote (host));
435 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
437 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s hasn't got a known issuer.\n"),
438 severity, quote (host));
441 if (status & GNUTLS_CERT_REVOKED)
443 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s has been revoked.\n"),
444 severity, quote (host));
448 if (gnutls_certificate_type_get (ctx->session) == GNUTLS_CRT_X509)
450 time_t now = time (NULL);
451 gnutls_x509_crt cert;
452 const gnutls_datum *cert_list;
453 unsigned int cert_list_size;
455 if ((err = gnutls_x509_crt_init (&cert)) < 0)
457 logprintf (LOG_NOTQUIET, _("Error initializing X509 certificate: %s\n"),
458 gnutls_strerror (err));
463 cert_list = gnutls_certificate_get_peers (ctx->session, &cert_list_size);
466 logprintf (LOG_NOTQUIET, _("No certificate found\n"));
470 err = gnutls_x509_crt_import (cert, cert_list, GNUTLS_X509_FMT_DER);
473 logprintf (LOG_NOTQUIET, _("Error parsing certificate: %s\n"),
474 gnutls_strerror (err));
478 if (now < gnutls_x509_crt_get_activation_time (cert))
480 logprintf (LOG_NOTQUIET, _("The certificate has not yet been activated\n"));
483 if (now >= gnutls_x509_crt_get_expiration_time (cert))
485 logprintf (LOG_NOTQUIET, _("The certificate has expired\n"));
488 if (!gnutls_x509_crt_check_hostname (cert, host))
490 logprintf (LOG_NOTQUIET,
491 _("The certificate's owner does not match hostname %s\n"),
495 gnutls_x509_crt_deinit (cert);
499 return opt.check_cert ? success : true;