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>
58 key_type_to_gnutls_type (enum keyfile_type type)
63 return GNUTLS_X509_FMT_PEM;
65 return GNUTLS_X509_FMT_DER;
71 /* Note: some of the functions private to this file have names that
72 begin with "wgnutls_" (e.g. wgnutls_read) so that they wouldn't be
73 confused with actual gnutls functions -- such as the gnutls_read
74 preprocessor macro. */
76 static gnutls_certificate_credentials credentials;
80 /* Becomes true if GnuTLS is initialized. */
81 static bool ssl_initialized = false;
83 /* GnuTLS should be initialized only once. */
87 const char *ca_directory;
90 gnutls_global_init ();
91 gnutls_certificate_allocate_credentials (&credentials);
92 gnutls_certificate_set_verify_flags(credentials,
93 GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
95 ca_directory = opt.ca_directory ? opt.ca_directory : "/etc/ssl/certs";
97 dir = opendir (ca_directory);
100 if (opt.ca_directory)
101 logprintf (LOG_NOTQUIET, _("ERROR: Cannot open directory %s.\n"),
107 while ((dent = readdir (dir)) != NULL)
111 asprintf (&ca_file, "%s/%s", ca_directory, dent->d_name);
115 if (S_ISREG (st.st_mode))
116 gnutls_certificate_set_x509_trust_file (credentials, ca_file,
117 GNUTLS_X509_FMT_PEM);
125 /* Use the private key from the cert file unless otherwise specified. */
126 if (opt.cert_file && !opt.private_key)
128 opt.private_key = opt.cert_file;
129 opt.private_key_type = opt.cert_type;
131 /* Use the cert from the private key file unless otherwise specified. */
132 if (!opt.cert_file && opt.private_key)
134 opt.cert_file = opt.private_key;
135 opt.cert_type = opt.private_key_type;
138 if (opt.cert_file && opt.private_key)
141 if (opt.private_key_type != opt.cert_type)
143 /* GnuTLS can't handle this */
144 logprintf (LOG_NOTQUIET, _("ERROR: GnuTLS requires the key and the \
145 cert to be of the same type.\n"));
148 type = key_type_to_gnutls_type (opt.private_key_type);
150 gnutls_certificate_set_x509_key_file (credentials, opt.cert_file,
156 gnutls_certificate_set_x509_trust_file (credentials, opt.ca_cert,
157 GNUTLS_X509_FMT_PEM);
159 ssl_initialized = true;
164 struct wgnutls_transport_context
166 gnutls_session session; /* GnuTLS session handle */
167 int last_error; /* last error returned by read/write/... */
169 /* Since GnuTLS doesn't support the equivalent to recv(...,
170 MSG_PEEK) or SSL_peek(), we have to do it ourselves. Peeked data
171 is stored to PEEKBUF, and wgnutls_read checks that buffer before
178 # define MIN(i, j) ((i) <= (j) ? (i) : (j))
183 wgnutls_read_timeout (int fd, char *buf, int bufsize, void *arg, double timeout)
189 struct ptimer *timer;
190 struct wgnutls_transport_context *ctx = arg;
196 flags = fcntl (fd, F_GETFL, 0);
200 timer = ptimer_new ();
210 next_timeout = timeout - ptimer_measure (timer);
211 if (next_timeout < 0.0)
215 ret = GNUTLS_E_AGAIN;
216 if (timeout == 0 || gnutls_record_check_pending (ctx->session)
217 || select_fd (fd, next_timeout, WAIT_FOR_READ))
222 if (fcntl (fd, F_SETFL, flags | O_NONBLOCK))
225 /* XXX: Assume it was blocking before. */
227 if (ioctl (fd, FIONBIO, &one) < 0)
232 ret = gnutls_record_recv (ctx->session, buf, bufsize);
237 if (fcntl (fd, F_SETFL, flags) < 0)
241 if (ioctl (fd, FIONBIO, &zero) < 0)
247 timed_out = timeout && ptimer_measure (timer) >= timeout;
249 while (ret == GNUTLS_E_INTERRUPTED || (ret == GNUTLS_E_AGAIN && !timed_out));
252 ptimer_destroy (timer);
254 if (timeout && timed_out && ret == GNUTLS_E_AGAIN)
261 wgnutls_read (int fd, char *buf, int bufsize, void *arg)
264 struct wgnutls_transport_context *ctx = arg;
268 /* If we have any peek data, simply return that. */
269 int copysize = MIN (bufsize, ctx->peeklen);
270 memcpy (buf, ctx->peekbuf, copysize);
271 ctx->peeklen -= copysize;
272 if (ctx->peeklen != 0)
273 memmove (ctx->peekbuf, ctx->peekbuf + copysize, ctx->peeklen);
278 ret = wgnutls_read_timeout (fd, buf, bufsize, arg, opt.read_timeout);
280 ctx->last_error = ret;
286 wgnutls_write (int fd, char *buf, int bufsize, void *arg)
289 struct wgnutls_transport_context *ctx = arg;
291 ret = gnutls_record_send (ctx->session, buf, bufsize);
292 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
294 ctx->last_error = ret;
299 wgnutls_poll (int fd, double timeout, int wait_for, void *arg)
301 struct wgnutls_transport_context *ctx = arg;
302 return ctx->peeklen || gnutls_record_check_pending (ctx->session)
303 || select_fd (fd, timeout, wait_for);
307 wgnutls_peek (int fd, char *buf, int bufsize, void *arg)
310 struct wgnutls_transport_context *ctx = arg;
311 int offset = MIN (bufsize, ctx->peeklen);
312 if (bufsize > sizeof ctx->peekbuf)
313 bufsize = sizeof ctx->peekbuf;
316 memcpy (buf, ctx->peekbuf, offset);
318 if (bufsize > offset)
320 if (gnutls_record_check_pending (ctx->session) <= 0
321 && select_fd (fd, 0.0, WAIT_FOR_READ) <= 0)
324 read = wgnutls_read_timeout (fd, buf + offset, bufsize - offset,
325 ctx, opt.read_timeout);
336 memcpy (ctx->peekbuf + offset, buf + offset,
338 ctx->peeklen += read;
342 return offset + read;
346 wgnutls_errstr (int fd, void *arg)
348 struct wgnutls_transport_context *ctx = arg;
349 return gnutls_strerror (ctx->last_error);
353 wgnutls_close (int fd, void *arg)
355 struct wgnutls_transport_context *ctx = arg;
356 /*gnutls_bye (ctx->session, GNUTLS_SHUT_RDWR);*/
357 gnutls_deinit (ctx->session);
362 /* gnutls_transport is the singleton that describes the SSL transport
363 methods provided by this file. */
365 static struct transport_implementation wgnutls_transport =
367 wgnutls_read, wgnutls_write, wgnutls_poll,
368 wgnutls_peek, wgnutls_errstr, wgnutls_close
372 ssl_connect_wget (int fd)
374 struct wgnutls_transport_context *ctx;
375 gnutls_session session;
377 gnutls_init (&session, GNUTLS_CLIENT);
378 gnutls_set_default_priority (session);
379 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, credentials);
381 # define FD_TO_SOCKET(X) (X)
383 gnutls_transport_set_ptr (session, (gnutls_transport_ptr) FD_TO_SOCKET (fd));
386 #if HAVE_GNUTLS_PRIORITY_SET_DIRECT
387 switch (opt.secure_protocol)
389 case secure_protocol_auto:
391 case secure_protocol_sslv2:
392 case secure_protocol_sslv3:
393 err = gnutls_priority_set_direct (session, "NORMAL:-VERS-TLS-ALL", NULL);
395 case secure_protocol_tlsv1:
396 err = gnutls_priority_set_direct (session, "NORMAL:-VERS-SSL3.0", NULL);
402 int allowed_protocols[4] = {0, 0, 0, 0};
403 switch (opt.secure_protocol)
405 case secure_protocol_auto:
407 case secure_protocol_sslv2:
408 case secure_protocol_sslv3:
409 allowed_protocols[0] = GNUTLS_SSL3;
410 err = gnutls_protocol_set_priority (session, allowed_protocols);
413 case secure_protocol_tlsv1:
414 allowed_protocols[0] = GNUTLS_TLS1_0;
415 allowed_protocols[1] = GNUTLS_TLS1_1;
416 allowed_protocols[2] = GNUTLS_TLS1_2;
417 err = gnutls_protocol_set_priority (session, allowed_protocols);
427 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
428 gnutls_deinit (session);
432 err = gnutls_handshake (session);
435 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
436 gnutls_deinit (session);
440 ctx = xnew0 (struct wgnutls_transport_context);
441 ctx->session = session;
442 fd_register_transport (fd, &wgnutls_transport, ctx);
447 ssl_check_certificate (int fd, const char *host)
449 struct wgnutls_transport_context *ctx = fd_transport_context (fd);
454 /* If the user has specified --no-check-cert, we still want to warn
455 him about problems with the server's certificate. */
456 const char *severity = opt.check_cert ? _("ERROR") : _("WARNING");
459 err = gnutls_certificate_verify_peers2 (ctx->session, &status);
462 logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
463 severity, quotearg_style (escape_quoting_style, host));
468 if (status & GNUTLS_CERT_INVALID)
470 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s is not trusted.\n"),
471 severity, quote (host));
474 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
476 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s hasn't got a known issuer.\n"),
477 severity, quote (host));
480 if (status & GNUTLS_CERT_REVOKED)
482 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s has been revoked.\n"),
483 severity, quote (host));
487 if (gnutls_certificate_type_get (ctx->session) == GNUTLS_CRT_X509)
489 time_t now = time (NULL);
490 gnutls_x509_crt cert;
491 const gnutls_datum *cert_list;
492 unsigned int cert_list_size;
494 if ((err = gnutls_x509_crt_init (&cert)) < 0)
496 logprintf (LOG_NOTQUIET, _("Error initializing X509 certificate: %s\n"),
497 gnutls_strerror (err));
502 cert_list = gnutls_certificate_get_peers (ctx->session, &cert_list_size);
505 logprintf (LOG_NOTQUIET, _("No certificate found\n"));
509 err = gnutls_x509_crt_import (cert, cert_list, GNUTLS_X509_FMT_DER);
512 logprintf (LOG_NOTQUIET, _("Error parsing certificate: %s\n"),
513 gnutls_strerror (err));
517 if (now < gnutls_x509_crt_get_activation_time (cert))
519 logprintf (LOG_NOTQUIET, _("The certificate has not yet been activated\n"));
522 if (now >= gnutls_x509_crt_get_expiration_time (cert))
524 logprintf (LOG_NOTQUIET, _("The certificate has expired\n"));
527 if (!gnutls_x509_crt_check_hostname (cert, host))
529 logprintf (LOG_NOTQUIET,
530 _("The certificate's owner does not match hostname %s\n"),
534 gnutls_x509_crt_deinit (cert);
538 return opt.check_cert ? success : true;