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>
60 key_type_to_gnutls_type (enum keyfile_type type)
65 return GNUTLS_X509_FMT_PEM;
67 return GNUTLS_X509_FMT_DER;
73 /* Note: some of the functions private to this file have names that
74 begin with "wgnutls_" (e.g. wgnutls_read) so that they wouldn't be
75 confused with actual gnutls functions -- such as the gnutls_read
76 preprocessor macro. */
78 static gnutls_certificate_credentials_t credentials;
82 /* Becomes true if GnuTLS is initialized. */
83 static bool ssl_initialized = false;
85 /* GnuTLS should be initialized only once. */
89 const char *ca_directory;
92 gnutls_global_init ();
93 gnutls_certificate_allocate_credentials (&credentials);
94 gnutls_certificate_set_verify_flags(credentials,
95 GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
97 ca_directory = opt.ca_directory ? opt.ca_directory : "/etc/ssl/certs";
99 dir = opendir (ca_directory);
102 if (opt.ca_directory)
103 logprintf (LOG_NOTQUIET, _("ERROR: Cannot open directory %s.\n"),
109 while ((dent = readdir (dir)) != NULL)
113 asprintf (&ca_file, "%s/%s", ca_directory, dent->d_name);
117 if (S_ISREG (st.st_mode))
118 gnutls_certificate_set_x509_trust_file (credentials, ca_file,
119 GNUTLS_X509_FMT_PEM);
127 /* Use the private key from the cert file unless otherwise specified. */
128 if (opt.cert_file && !opt.private_key)
130 opt.private_key = opt.cert_file;
131 opt.private_key_type = opt.cert_type;
133 /* Use the cert from the private key file unless otherwise specified. */
134 if (!opt.cert_file && opt.private_key)
136 opt.cert_file = opt.private_key;
137 opt.cert_type = opt.private_key_type;
140 if (opt.cert_file && opt.private_key)
143 if (opt.private_key_type != opt.cert_type)
145 /* GnuTLS can't handle this */
146 logprintf (LOG_NOTQUIET, _("ERROR: GnuTLS requires the key and the \
147 cert to be of the same type.\n"));
150 type = key_type_to_gnutls_type (opt.private_key_type);
152 gnutls_certificate_set_x509_key_file (credentials, opt.cert_file,
158 gnutls_certificate_set_x509_trust_file (credentials, opt.ca_cert,
159 GNUTLS_X509_FMT_PEM);
161 ssl_initialized = true;
166 struct wgnutls_transport_context
168 gnutls_session_t session; /* GnuTLS session handle */
169 int last_error; /* last error returned by read/write/... */
171 /* Since GnuTLS doesn't support the equivalent to recv(...,
172 MSG_PEEK) or SSL_peek(), we have to do it ourselves. Peeked data
173 is stored to PEEKBUF, and wgnutls_read checks that buffer before
180 # define MIN(i, j) ((i) <= (j) ? (i) : (j))
185 wgnutls_read_timeout (int fd, char *buf, int bufsize, void *arg, double timeout)
191 struct ptimer *timer = NULL;
192 struct wgnutls_transport_context *ctx = arg;
198 flags = fcntl (fd, F_GETFL, 0);
201 if (fcntl (fd, F_SETFL, flags | O_NONBLOCK))
204 /* XXX: Assume it was blocking before. */
206 if (ioctl (fd, FIONBIO, &one) < 0)
210 timer = ptimer_new ();
217 double next_timeout = 0;
220 next_timeout = timeout - ptimer_measure (timer);
221 if (next_timeout < 0)
225 ret = GNUTLS_E_AGAIN;
226 if (timeout == 0 || gnutls_record_check_pending (ctx->session)
227 || select_fd (fd, next_timeout, WAIT_FOR_READ))
229 ret = gnutls_record_recv (ctx->session, buf, bufsize);
230 timed_out = timeout && ptimer_measure (timer) >= timeout;
233 while (ret == GNUTLS_E_INTERRUPTED || (ret == GNUTLS_E_AGAIN && !timed_out));
237 ptimer_destroy (timer);
240 if (fcntl (fd, F_SETFL, flags) < 0)
244 if (ioctl (fd, FIONBIO, &zero) < 0)
248 if (timed_out && ret == GNUTLS_E_AGAIN)
256 wgnutls_read (int fd, char *buf, int bufsize, void *arg)
259 struct wgnutls_transport_context *ctx = arg;
263 /* If we have any peek data, simply return that. */
264 int copysize = MIN (bufsize, ctx->peeklen);
265 memcpy (buf, ctx->peekbuf, copysize);
266 ctx->peeklen -= copysize;
267 if (ctx->peeklen != 0)
268 memmove (ctx->peekbuf, ctx->peekbuf + copysize, ctx->peeklen);
273 ret = wgnutls_read_timeout (fd, buf, bufsize, arg, opt.read_timeout);
275 ctx->last_error = ret;
281 wgnutls_write (int fd, char *buf, int bufsize, void *arg)
284 struct wgnutls_transport_context *ctx = arg;
286 ret = gnutls_record_send (ctx->session, buf, bufsize);
287 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
289 ctx->last_error = ret;
294 wgnutls_poll (int fd, double timeout, int wait_for, void *arg)
296 struct wgnutls_transport_context *ctx = arg;
299 return ctx->peeklen || gnutls_record_check_pending (ctx->session)
300 || select_fd (fd, timeout, wait_for);
302 return ctx->peeklen || gnutls_record_check_pending (ctx->session);
306 wgnutls_peek (int fd, char *buf, int bufsize, void *arg)
309 struct wgnutls_transport_context *ctx = arg;
310 int offset = MIN (bufsize, ctx->peeklen);
314 memcpy (buf, ctx->peekbuf, offset);
318 if (bufsize > sizeof ctx->peekbuf)
319 bufsize = sizeof ctx->peekbuf;
321 if (bufsize > offset)
323 if (opt.read_timeout && gnutls_record_check_pending (ctx->session) == 0
324 && select_fd (fd, 0.0, WAIT_FOR_READ) <= 0)
327 read = wgnutls_read_timeout (fd, buf + offset, bufsize - offset,
328 ctx, opt.read_timeout);
339 memcpy (ctx->peekbuf + offset, buf + offset,
341 ctx->peeklen += read;
345 return offset + read;
349 wgnutls_errstr (int fd, void *arg)
351 struct wgnutls_transport_context *ctx = arg;
352 return gnutls_strerror (ctx->last_error);
356 wgnutls_close (int fd, void *arg)
358 struct wgnutls_transport_context *ctx = arg;
359 /*gnutls_bye (ctx->session, GNUTLS_SHUT_RDWR);*/
360 gnutls_deinit (ctx->session);
365 /* gnutls_transport is the singleton that describes the SSL transport
366 methods provided by this file. */
368 static struct transport_implementation wgnutls_transport =
370 wgnutls_read, wgnutls_write, wgnutls_poll,
371 wgnutls_peek, wgnutls_errstr, wgnutls_close
375 ssl_connect_wget (int fd, const char *hostname)
377 struct wgnutls_transport_context *ctx;
378 gnutls_session_t session;
380 gnutls_init (&session, GNUTLS_CLIENT);
382 /* We set the server name but only if it's not an IP address. */
383 if (! is_valid_ip_address (hostname))
385 gnutls_server_name_set (session, GNUTLS_NAME_DNS, hostname,
389 gnutls_set_default_priority (session);
390 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, credentials);
392 # define FD_TO_SOCKET(X) (X)
394 gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) FD_TO_SOCKET (fd));
397 #if HAVE_GNUTLS_PRIORITY_SET_DIRECT
398 switch (opt.secure_protocol)
400 case secure_protocol_auto:
402 case secure_protocol_sslv2:
403 case secure_protocol_sslv3:
404 err = gnutls_priority_set_direct (session, "NORMAL:-VERS-TLS-ALL", NULL);
406 case secure_protocol_tlsv1:
407 err = gnutls_priority_set_direct (session, "NORMAL:-VERS-SSL3.0", NULL);
413 int allowed_protocols[4] = {0, 0, 0, 0};
414 switch (opt.secure_protocol)
416 case secure_protocol_auto:
418 case secure_protocol_sslv2:
419 case secure_protocol_sslv3:
420 allowed_protocols[0] = GNUTLS_SSL3;
421 err = gnutls_protocol_set_priority (session, allowed_protocols);
424 case secure_protocol_tlsv1:
425 allowed_protocols[0] = GNUTLS_TLS1_0;
426 allowed_protocols[1] = GNUTLS_TLS1_1;
427 allowed_protocols[2] = GNUTLS_TLS1_2;
428 err = gnutls_protocol_set_priority (session, allowed_protocols);
438 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
439 gnutls_deinit (session);
443 err = gnutls_handshake (session);
446 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
447 gnutls_deinit (session);
451 ctx = xnew0 (struct wgnutls_transport_context);
452 ctx->session = session;
453 fd_register_transport (fd, &wgnutls_transport, ctx);
458 ssl_check_certificate (int fd, const char *host)
460 struct wgnutls_transport_context *ctx = fd_transport_context (fd);
465 /* If the user has specified --no-check-cert, we still want to warn
466 him about problems with the server's certificate. */
467 const char *severity = opt.check_cert ? _("ERROR") : _("WARNING");
470 err = gnutls_certificate_verify_peers2 (ctx->session, &status);
473 logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
474 severity, quotearg_style (escape_quoting_style, host));
479 if (status & GNUTLS_CERT_INVALID)
481 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s is not trusted.\n"),
482 severity, quote (host));
485 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
487 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s hasn't got a known issuer.\n"),
488 severity, quote (host));
491 if (status & GNUTLS_CERT_REVOKED)
493 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s has been revoked.\n"),
494 severity, quote (host));
498 if (gnutls_certificate_type_get (ctx->session) == GNUTLS_CRT_X509)
500 time_t now = time (NULL);
501 gnutls_x509_crt_t cert;
502 const gnutls_datum_t *cert_list;
503 unsigned int cert_list_size;
505 if ((err = gnutls_x509_crt_init (&cert)) < 0)
507 logprintf (LOG_NOTQUIET, _("Error initializing X509 certificate: %s\n"),
508 gnutls_strerror (err));
513 cert_list = gnutls_certificate_get_peers (ctx->session, &cert_list_size);
516 logprintf (LOG_NOTQUIET, _("No certificate found\n"));
520 err = gnutls_x509_crt_import (cert, cert_list, GNUTLS_X509_FMT_DER);
523 logprintf (LOG_NOTQUIET, _("Error parsing certificate: %s\n"),
524 gnutls_strerror (err));
528 if (now < gnutls_x509_crt_get_activation_time (cert))
530 logprintf (LOG_NOTQUIET, _("The certificate has not yet been activated\n"));
533 if (now >= gnutls_x509_crt_get_expiration_time (cert))
535 logprintf (LOG_NOTQUIET, _("The certificate has expired\n"));
538 if (!gnutls_x509_crt_check_hostname (cert, host))
540 logprintf (LOG_NOTQUIET,
541 _("The certificate's owner does not match hostname %s\n"),
545 gnutls_x509_crt_deinit (cert);
549 return opt.check_cert ? success : true;