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;
192 struct wgnutls_transport_context *ctx = arg;
198 flags = fcntl (fd, F_GETFL, 0);
202 timer = ptimer_new ();
212 next_timeout = timeout - ptimer_measure (timer);
213 if (next_timeout < 0.0)
217 ret = GNUTLS_E_AGAIN;
218 if (timeout == 0 || gnutls_record_check_pending (ctx->session)
219 || select_fd (fd, next_timeout, WAIT_FOR_READ))
224 if (fcntl (fd, F_SETFL, flags | O_NONBLOCK))
227 /* XXX: Assume it was blocking before. */
229 if (ioctl (fd, FIONBIO, &one) < 0)
234 ret = gnutls_record_recv (ctx->session, buf, bufsize);
239 if (fcntl (fd, F_SETFL, flags) < 0)
243 if (ioctl (fd, FIONBIO, &zero) < 0)
249 timed_out = timeout && ptimer_measure (timer) >= timeout;
251 while (ret == GNUTLS_E_INTERRUPTED || (ret == GNUTLS_E_AGAIN && !timed_out));
254 ptimer_destroy (timer);
256 if (timeout && timed_out && ret == GNUTLS_E_AGAIN)
263 wgnutls_read (int fd, char *buf, int bufsize, void *arg)
266 struct wgnutls_transport_context *ctx = arg;
270 /* If we have any peek data, simply return that. */
271 int copysize = MIN (bufsize, ctx->peeklen);
272 memcpy (buf, ctx->peekbuf, copysize);
273 ctx->peeklen -= copysize;
274 if (ctx->peeklen != 0)
275 memmove (ctx->peekbuf, ctx->peekbuf + copysize, ctx->peeklen);
280 ret = wgnutls_read_timeout (fd, buf, bufsize, arg, opt.read_timeout);
282 ctx->last_error = ret;
288 wgnutls_write (int fd, char *buf, int bufsize, void *arg)
291 struct wgnutls_transport_context *ctx = arg;
293 ret = gnutls_record_send (ctx->session, buf, bufsize);
294 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
296 ctx->last_error = ret;
301 wgnutls_poll (int fd, double timeout, int wait_for, void *arg)
303 struct wgnutls_transport_context *ctx = arg;
304 return ctx->peeklen || gnutls_record_check_pending (ctx->session)
305 || select_fd (fd, timeout, wait_for);
309 wgnutls_peek (int fd, char *buf, int bufsize, void *arg)
312 struct wgnutls_transport_context *ctx = arg;
313 int offset = MIN (bufsize, ctx->peeklen);
314 if (bufsize > sizeof ctx->peekbuf)
315 bufsize = sizeof ctx->peekbuf;
318 memcpy (buf, ctx->peekbuf, offset);
320 if (bufsize > offset)
322 if (gnutls_record_check_pending (ctx->session) <= 0
323 && select_fd (fd, 0.0, WAIT_FOR_READ) <= 0)
326 read = wgnutls_read_timeout (fd, buf + offset, bufsize - offset,
327 ctx, opt.read_timeout);
338 memcpy (ctx->peekbuf + offset, buf + offset,
340 ctx->peeklen += read;
344 return offset + read;
348 wgnutls_errstr (int fd, void *arg)
350 struct wgnutls_transport_context *ctx = arg;
351 return gnutls_strerror (ctx->last_error);
355 wgnutls_close (int fd, void *arg)
357 struct wgnutls_transport_context *ctx = arg;
358 /*gnutls_bye (ctx->session, GNUTLS_SHUT_RDWR);*/
359 gnutls_deinit (ctx->session);
364 /* gnutls_transport is the singleton that describes the SSL transport
365 methods provided by this file. */
367 static struct transport_implementation wgnutls_transport =
369 wgnutls_read, wgnutls_write, wgnutls_poll,
370 wgnutls_peek, wgnutls_errstr, wgnutls_close
374 ssl_connect_wget (int fd, const char *hostname)
376 struct wgnutls_transport_context *ctx;
377 gnutls_session_t session;
379 gnutls_init (&session, GNUTLS_CLIENT);
381 /* We set the server name but only if it's not an IP address. */
382 if (! is_valid_ip_address (hostname))
384 gnutls_server_name_set (session, GNUTLS_NAME_DNS, hostname,
388 gnutls_set_default_priority (session);
389 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, credentials);
391 # define FD_TO_SOCKET(X) (X)
393 gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) FD_TO_SOCKET (fd));
396 #if HAVE_GNUTLS_PRIORITY_SET_DIRECT
397 switch (opt.secure_protocol)
399 case secure_protocol_auto:
401 case secure_protocol_sslv2:
402 case secure_protocol_sslv3:
403 err = gnutls_priority_set_direct (session, "NORMAL:-VERS-TLS-ALL", NULL);
405 case secure_protocol_tlsv1:
406 err = gnutls_priority_set_direct (session, "NORMAL:-VERS-SSL3.0", NULL);
412 int allowed_protocols[4] = {0, 0, 0, 0};
413 switch (opt.secure_protocol)
415 case secure_protocol_auto:
417 case secure_protocol_sslv2:
418 case secure_protocol_sslv3:
419 allowed_protocols[0] = GNUTLS_SSL3;
420 err = gnutls_protocol_set_priority (session, allowed_protocols);
423 case secure_protocol_tlsv1:
424 allowed_protocols[0] = GNUTLS_TLS1_0;
425 allowed_protocols[1] = GNUTLS_TLS1_1;
426 allowed_protocols[2] = GNUTLS_TLS1_2;
427 err = gnutls_protocol_set_priority (session, allowed_protocols);
437 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
438 gnutls_deinit (session);
442 err = gnutls_handshake (session);
445 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
446 gnutls_deinit (session);
450 ctx = xnew0 (struct wgnutls_transport_context);
451 ctx->session = session;
452 fd_register_transport (fd, &wgnutls_transport, ctx);
457 ssl_check_certificate (int fd, const char *host)
459 struct wgnutls_transport_context *ctx = fd_transport_context (fd);
464 /* If the user has specified --no-check-cert, we still want to warn
465 him about problems with the server's certificate. */
466 const char *severity = opt.check_cert ? _("ERROR") : _("WARNING");
469 err = gnutls_certificate_verify_peers2 (ctx->session, &status);
472 logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
473 severity, quotearg_style (escape_quoting_style, host));
478 if (status & GNUTLS_CERT_INVALID)
480 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s is not trusted.\n"),
481 severity, quote (host));
484 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
486 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s hasn't got a known issuer.\n"),
487 severity, quote (host));
490 if (status & GNUTLS_CERT_REVOKED)
492 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s has been revoked.\n"),
493 severity, quote (host));
497 if (gnutls_certificate_type_get (ctx->session) == GNUTLS_CRT_X509)
499 time_t now = time (NULL);
500 gnutls_x509_crt_t cert;
501 const gnutls_datum_t *cert_list;
502 unsigned int cert_list_size;
504 if ((err = gnutls_x509_crt_init (&cert)) < 0)
506 logprintf (LOG_NOTQUIET, _("Error initializing X509 certificate: %s\n"),
507 gnutls_strerror (err));
512 cert_list = gnutls_certificate_get_peers (ctx->session, &cert_list_size);
515 logprintf (LOG_NOTQUIET, _("No certificate found\n"));
519 err = gnutls_x509_crt_import (cert, cert_list, GNUTLS_X509_FMT_DER);
522 logprintf (LOG_NOTQUIET, _("Error parsing certificate: %s\n"),
523 gnutls_strerror (err));
527 if (now < gnutls_x509_crt_get_activation_time (cert))
529 logprintf (LOG_NOTQUIET, _("The certificate has not yet been activated\n"));
532 if (now >= gnutls_x509_crt_get_expiration_time (cert))
534 logprintf (LOG_NOTQUIET, _("The certificate has expired\n"));
537 if (!gnutls_x509_crt_check_hostname (cert, host))
539 logprintf (LOG_NOTQUIET,
540 _("The certificate's owner does not match hostname %s\n"),
544 gnutls_x509_crt_deinit (cert);
548 return opt.check_cert ? success : true;