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>
55 /* Note: some of the functions private to this file have names that
56 begin with "wgnutls_" (e.g. wgnutls_read) so that they wouldn't be
57 confused with actual gnutls functions -- such as the gnutls_read
58 preprocessor macro. */
60 static gnutls_certificate_credentials credentials;
65 const char *ca_directory;
68 gnutls_global_init ();
69 gnutls_certificate_allocate_credentials (&credentials);
70 gnutls_certificate_set_verify_flags(credentials,
71 GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
73 ca_directory = opt.ca_directory ? opt.ca_directory : "/etc/ssl/certs";
75 dir = opendir (ca_directory);
79 logprintf (LOG_NOTQUIET, _("ERROR: Cannot open directory %s.\n"),
85 while ((dent = readdir (dir)) != NULL)
89 asprintf (&ca_file, "%s/%s", ca_directory, dent->d_name);
93 if (S_ISREG (st.st_mode))
94 gnutls_certificate_set_x509_trust_file (credentials, ca_file,
104 gnutls_certificate_set_x509_trust_file (credentials, opt.ca_cert,
105 GNUTLS_X509_FMT_PEM);
109 struct wgnutls_transport_context
111 gnutls_session session; /* GnuTLS session handle */
112 int last_error; /* last error returned by read/write/... */
114 /* Since GnuTLS doesn't support the equivalent to recv(...,
115 MSG_PEEK) or SSL_peek(), we have to do it ourselves. Peeked data
116 is stored to PEEKBUF, and wgnutls_read checks that buffer before
123 # define MIN(i, j) ((i) <= (j) ? (i) : (j))
127 wgnutls_read (int fd, char *buf, int bufsize, void *arg)
133 struct ptimer *timer;
134 struct wgnutls_transport_context *ctx = arg;
138 /* If we have any peek data, simply return that. */
139 int copysize = MIN (bufsize, ctx->peeklen);
140 memcpy (buf, ctx->peekbuf, copysize);
141 ctx->peeklen -= copysize;
142 if (ctx->peeklen != 0)
143 memmove (ctx->peekbuf, ctx->peekbuf + copysize, ctx->peeklen);
148 if (opt.read_timeout)
151 flags = fcntl (fd, F_GETFL, 0);
155 ret = fcntl (fd, F_SETFL, flags | O_NONBLOCK);
159 /* XXX: Assume it was blocking before. */
161 ret = ioctl (fd, FIONBIO, &one);
165 timer = ptimer_new ();
173 ret = gnutls_record_recv (ctx->session, buf, bufsize);
174 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
176 while (opt.read_timeout == 0 || ptimer_measure (timer) < opt.read_timeout);
178 if (opt.read_timeout)
180 ptimer_destroy (timer);
182 ret = fcntl (fd, F_SETFL, flags);
187 ret = ioctl (fd, FIONBIO, &zero);
194 ctx->last_error = ret;
200 wgnutls_write (int fd, char *buf, int bufsize, void *arg)
203 struct wgnutls_transport_context *ctx = arg;
205 ret = gnutls_record_send (ctx->session, buf, bufsize);
206 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
208 ctx->last_error = ret;
213 wgnutls_poll (int fd, double timeout, int wait_for, void *arg)
215 struct wgnutls_transport_context *ctx = arg;
216 return ctx->peeklen || gnutls_record_check_pending (ctx->session)
217 || select_fd (fd, timeout, wait_for);
221 wgnutls_peek (int fd, char *buf, int bufsize, void *arg)
224 struct wgnutls_transport_context *ctx = arg;
225 int offset = MIN (bufsize, ctx->peeklen);
226 if (bufsize > sizeof ctx->peekbuf)
227 bufsize = sizeof ctx->peekbuf;
230 memcpy (buf, ctx->peekbuf, offset);
232 if (bufsize > offset)
234 if (gnutls_record_check_pending (ctx->session) <= 0
235 && select_fd (fd, 0.0, WAIT_FOR_READ) <= 0)
238 read = gnutls_record_recv (ctx->session, buf + offset,
251 memcpy (ctx->peekbuf + offset, buf + offset,
253 ctx->peeklen += read;
257 return offset + read;
261 wgnutls_errstr (int fd, void *arg)
263 struct wgnutls_transport_context *ctx = arg;
264 return gnutls_strerror (ctx->last_error);
268 wgnutls_close (int fd, void *arg)
270 struct wgnutls_transport_context *ctx = arg;
271 /*gnutls_bye (ctx->session, GNUTLS_SHUT_RDWR);*/
272 gnutls_deinit (ctx->session);
277 /* gnutls_transport is the singleton that describes the SSL transport
278 methods provided by this file. */
280 static struct transport_implementation wgnutls_transport =
282 wgnutls_read, wgnutls_write, wgnutls_poll,
283 wgnutls_peek, wgnutls_errstr, wgnutls_close
287 ssl_connect_wget (int fd)
289 struct wgnutls_transport_context *ctx;
290 gnutls_session session;
292 gnutls_init (&session, GNUTLS_CLIENT);
293 gnutls_set_default_priority (session);
294 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, credentials);
296 # define FD_TO_SOCKET(X) (X)
298 gnutls_transport_set_ptr (session, (gnutls_transport_ptr) FD_TO_SOCKET (fd));
301 #if HAVE_GNUTLS_PRIORITY_SET_DIRECT
302 switch (opt.secure_protocol)
304 case secure_protocol_auto:
306 case secure_protocol_sslv2:
307 case secure_protocol_sslv3:
308 err = gnutls_priority_set_direct (session, "NORMAL:-VERS-TLS-ALL", NULL);
310 case secure_protocol_tlsv1:
311 err = gnutls_priority_set_direct (session, "NORMAL:-VERS-SSL3.0", NULL);
317 int allowed_protocols[4] = {0, 0, 0, 0};
318 switch (opt.secure_protocol)
320 case secure_protocol_auto:
322 case secure_protocol_sslv2:
323 case secure_protocol_sslv3:
324 allowed_protocols[0] = GNUTLS_SSL3;
325 err = gnutls_protocol_set_priority (session, allowed_protocols);
328 case secure_protocol_tlsv1:
329 allowed_protocols[0] = GNUTLS_TLS1_0;
330 allowed_protocols[1] = GNUTLS_TLS1_1;
331 allowed_protocols[2] = GNUTLS_TLS1_2;
332 err = gnutls_protocol_set_priority (session, allowed_protocols);
342 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
343 gnutls_deinit (session);
347 err = gnutls_handshake (session);
350 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
351 gnutls_deinit (session);
355 ctx = xnew0 (struct wgnutls_transport_context);
356 ctx->session = session;
357 fd_register_transport (fd, &wgnutls_transport, ctx);
362 ssl_check_certificate (int fd, const char *host)
364 struct wgnutls_transport_context *ctx = fd_transport_context (fd);
369 /* If the user has specified --no-check-cert, we still want to warn
370 him about problems with the server's certificate. */
371 const char *severity = opt.check_cert ? _("ERROR") : _("WARNING");
374 err = gnutls_certificate_verify_peers2 (ctx->session, &status);
377 logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
378 severity, quotearg_style (escape_quoting_style, host));
383 if (status & GNUTLS_CERT_INVALID)
385 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s is not trusted.\n"),
386 severity, quote (host));
389 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
391 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s hasn't got a known issuer.\n"),
392 severity, quote (host));
395 if (status & GNUTLS_CERT_REVOKED)
397 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s has been revoked.\n"),
398 severity, quote (host));
402 if (gnutls_certificate_type_get (ctx->session) == GNUTLS_CRT_X509)
404 time_t now = time (NULL);
405 gnutls_x509_crt cert;
406 const gnutls_datum *cert_list;
407 unsigned int cert_list_size;
409 if ((err = gnutls_x509_crt_init (&cert)) < 0)
411 logprintf (LOG_NOTQUIET, _("Error initializing X509 certificate: %s\n"),
412 gnutls_strerror (err));
417 cert_list = gnutls_certificate_get_peers (ctx->session, &cert_list_size);
420 logprintf (LOG_NOTQUIET, _("No certificate found\n"));
424 err = gnutls_x509_crt_import (cert, cert_list, GNUTLS_X509_FMT_DER);
427 logprintf (LOG_NOTQUIET, _("Error parsing certificate: %s\n"),
428 gnutls_strerror (err));
432 if (now < gnutls_x509_crt_get_activation_time (cert))
434 logprintf (LOG_NOTQUIET, _("The certificate has not yet been activated\n"));
437 if (now >= gnutls_x509_crt_get_expiration_time (cert))
439 logprintf (LOG_NOTQUIET, _("The certificate has expired\n"));
442 if (!gnutls_x509_crt_check_hostname (cert, host))
444 logprintf (LOG_NOTQUIET,
445 _("The certificate's owner does not match hostname %s\n"),
449 gnutls_x509_crt_deinit (cert);
453 return opt.check_cert ? success : true;