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;
297 return ctx->peeklen || gnutls_record_check_pending (ctx->session)
298 || select_fd (fd, timeout, wait_for);
302 wgnutls_peek (int fd, char *buf, int bufsize, void *arg)
305 struct wgnutls_transport_context *ctx = arg;
306 int offset = MIN (bufsize, ctx->peeklen);
307 if (bufsize > sizeof ctx->peekbuf)
308 bufsize = sizeof ctx->peekbuf;
311 memcpy (buf, ctx->peekbuf, offset);
313 if (bufsize > offset)
315 if (gnutls_record_check_pending (ctx->session) <= 0
316 && select_fd (fd, 0.0, WAIT_FOR_READ) <= 0)
319 read = wgnutls_read_timeout (fd, buf + offset, bufsize - offset,
320 ctx, opt.read_timeout);
331 memcpy (ctx->peekbuf + offset, buf + offset,
333 ctx->peeklen += read;
337 return offset + read;
341 wgnutls_errstr (int fd, void *arg)
343 struct wgnutls_transport_context *ctx = arg;
344 return gnutls_strerror (ctx->last_error);
348 wgnutls_close (int fd, void *arg)
350 struct wgnutls_transport_context *ctx = arg;
351 /*gnutls_bye (ctx->session, GNUTLS_SHUT_RDWR);*/
352 gnutls_deinit (ctx->session);
357 /* gnutls_transport is the singleton that describes the SSL transport
358 methods provided by this file. */
360 static struct transport_implementation wgnutls_transport =
362 wgnutls_read, wgnutls_write, wgnutls_poll,
363 wgnutls_peek, wgnutls_errstr, wgnutls_close
367 ssl_connect_wget (int fd, const char *hostname)
369 struct wgnutls_transport_context *ctx;
370 gnutls_session_t session;
372 gnutls_init (&session, GNUTLS_CLIENT);
374 /* We set the server name but only if it's not an IP address. */
375 if (! is_valid_ip_address (hostname))
377 gnutls_server_name_set (session, GNUTLS_NAME_DNS, hostname,
381 gnutls_set_default_priority (session);
382 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, credentials);
384 # define FD_TO_SOCKET(X) (X)
386 gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) FD_TO_SOCKET (fd));
389 #if HAVE_GNUTLS_PRIORITY_SET_DIRECT
390 switch (opt.secure_protocol)
392 case secure_protocol_auto:
394 case secure_protocol_sslv2:
395 case secure_protocol_sslv3:
396 err = gnutls_priority_set_direct (session, "NORMAL:-VERS-TLS-ALL", NULL);
398 case secure_protocol_tlsv1:
399 err = gnutls_priority_set_direct (session, "NORMAL:-VERS-SSL3.0", NULL);
405 int allowed_protocols[4] = {0, 0, 0, 0};
406 switch (opt.secure_protocol)
408 case secure_protocol_auto:
410 case secure_protocol_sslv2:
411 case secure_protocol_sslv3:
412 allowed_protocols[0] = GNUTLS_SSL3;
413 err = gnutls_protocol_set_priority (session, allowed_protocols);
416 case secure_protocol_tlsv1:
417 allowed_protocols[0] = GNUTLS_TLS1_0;
418 allowed_protocols[1] = GNUTLS_TLS1_1;
419 allowed_protocols[2] = GNUTLS_TLS1_2;
420 err = gnutls_protocol_set_priority (session, allowed_protocols);
430 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
431 gnutls_deinit (session);
435 err = gnutls_handshake (session);
438 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
439 gnutls_deinit (session);
443 ctx = xnew0 (struct wgnutls_transport_context);
444 ctx->session = session;
445 fd_register_transport (fd, &wgnutls_transport, ctx);
450 ssl_check_certificate (int fd, const char *host)
452 struct wgnutls_transport_context *ctx = fd_transport_context (fd);
457 /* If the user has specified --no-check-cert, we still want to warn
458 him about problems with the server's certificate. */
459 const char *severity = opt.check_cert ? _("ERROR") : _("WARNING");
462 err = gnutls_certificate_verify_peers2 (ctx->session, &status);
465 logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
466 severity, quotearg_style (escape_quoting_style, host));
471 if (status & GNUTLS_CERT_INVALID)
473 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s is not trusted.\n"),
474 severity, quote (host));
477 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
479 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s hasn't got a known issuer.\n"),
480 severity, quote (host));
483 if (status & GNUTLS_CERT_REVOKED)
485 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s has been revoked.\n"),
486 severity, quote (host));
490 if (gnutls_certificate_type_get (ctx->session) == GNUTLS_CRT_X509)
492 time_t now = time (NULL);
493 gnutls_x509_crt_t cert;
494 const gnutls_datum_t *cert_list;
495 unsigned int cert_list_size;
497 if ((err = gnutls_x509_crt_init (&cert)) < 0)
499 logprintf (LOG_NOTQUIET, _("Error initializing X509 certificate: %s\n"),
500 gnutls_strerror (err));
505 cert_list = gnutls_certificate_get_peers (ctx->session, &cert_list_size);
508 logprintf (LOG_NOTQUIET, _("No certificate found\n"));
512 err = gnutls_x509_crt_import (cert, cert_list, GNUTLS_X509_FMT_DER);
515 logprintf (LOG_NOTQUIET, _("Error parsing certificate: %s\n"),
516 gnutls_strerror (err));
520 if (now < gnutls_x509_crt_get_activation_time (cert))
522 logprintf (LOG_NOTQUIET, _("The certificate has not yet been activated\n"));
525 if (now >= gnutls_x509_crt_get_expiration_time (cert))
527 logprintf (LOG_NOTQUIET, _("The certificate has expired\n"));
530 if (!gnutls_x509_crt_check_hostname (cert, host))
532 logprintf (LOG_NOTQUIET,
533 _("The certificate's owner does not match hostname %s\n"),
537 gnutls_x509_crt_deinit (cert);
541 return opt.check_cert ? success : true;