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>
54 /* Note: some of the functions private to this file have names that
55 begin with "wgnutls_" (e.g. wgnutls_read) so that they wouldn't be
56 confused with actual gnutls functions -- such as the gnutls_read
57 preprocessor macro. */
59 static gnutls_certificate_credentials credentials;
64 const char *ca_directory;
67 gnutls_global_init ();
68 gnutls_certificate_allocate_credentials (&credentials);
70 ca_directory = opt.ca_directory ? opt.ca_directory : "/etc/ssl/certs";
72 dir = opendir (ca_directory);
76 logprintf (LOG_NOTQUIET, _("ERROR: Cannot open directory %s.\n"),
82 while ((dent = readdir (dir)) != NULL)
86 asprintf (&ca_file, "%s/%s", ca_directory, dent->d_name);
90 if (S_ISREG (st.st_mode))
91 gnutls_certificate_set_x509_trust_file (credentials, ca_file,
101 gnutls_certificate_set_x509_trust_file (credentials, opt.ca_cert,
102 GNUTLS_X509_FMT_PEM);
106 struct wgnutls_transport_context
108 gnutls_session session; /* GnuTLS session handle */
109 int last_error; /* last error returned by read/write/... */
111 /* Since GnuTLS doesn't support the equivalent to recv(...,
112 MSG_PEEK) or SSL_peek(), we have to do it ourselves. Peeked data
113 is stored to PEEKBUF, and wgnutls_read checks that buffer before
120 # define MIN(i, j) ((i) <= (j) ? (i) : (j))
124 wgnutls_read (int fd, char *buf, int bufsize, void *arg)
127 struct wgnutls_transport_context *ctx = arg;
131 /* If we have any peek data, simply return that. */
132 int copysize = MIN (bufsize, ctx->peeklen);
133 memcpy (buf, ctx->peekbuf, copysize);
134 ctx->peeklen -= copysize;
135 if (ctx->peeklen != 0)
136 memmove (ctx->peekbuf, ctx->peekbuf + copysize, ctx->peeklen);
142 ret = gnutls_record_recv (ctx->session, buf, bufsize);
143 while (ret == GNUTLS_E_INTERRUPTED);
146 ctx->last_error = ret;
152 wgnutls_write (int fd, char *buf, int bufsize, void *arg)
155 struct wgnutls_transport_context *ctx = arg;
157 ret = gnutls_record_send (ctx->session, buf, bufsize);
158 while (ret == GNUTLS_E_INTERRUPTED);
160 ctx->last_error = ret;
165 wgnutls_poll (int fd, double timeout, int wait_for, void *arg)
167 struct wgnutls_transport_context *ctx = arg;
168 return ctx->peeklen || gnutls_record_check_pending (ctx->session)
169 || select_fd (fd, timeout, wait_for);
173 wgnutls_peek (int fd, char *buf, int bufsize, void *arg)
176 struct wgnutls_transport_context *ctx = arg;
177 int offset = MIN (bufsize, ctx->peeklen);
178 if (bufsize > sizeof ctx->peekbuf)
179 bufsize = sizeof ctx->peekbuf;
182 memcpy (buf, ctx->peekbuf, offset);
184 if (bufsize > offset)
187 flags = fcntl (fd, F_GETFL, 0);
191 ret = fcntl (fd, F_SETFL, flags | O_NONBLOCK);
197 ret = gnutls_record_recv (ctx->session, buf + offset,
200 while (ret == GNUTLS_E_INTERRUPTED);
212 memcpy (ctx->peekbuf + offset, buf + offset,
217 fcntl (fd, F_SETFL, flags);
226 wgnutls_errstr (int fd, void *arg)
228 struct wgnutls_transport_context *ctx = arg;
229 return gnutls_strerror (ctx->last_error);
233 wgnutls_close (int fd, void *arg)
235 struct wgnutls_transport_context *ctx = arg;
236 /*gnutls_bye (ctx->session, GNUTLS_SHUT_RDWR);*/
237 gnutls_deinit (ctx->session);
242 /* gnutls_transport is the singleton that describes the SSL transport
243 methods provided by this file. */
245 static struct transport_implementation wgnutls_transport =
247 wgnutls_read, wgnutls_write, wgnutls_poll,
248 wgnutls_peek, wgnutls_errstr, wgnutls_close
252 ssl_connect_wget (int fd)
254 static const int cert_type_priority[] = {
255 GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP, 0
257 struct wgnutls_transport_context *ctx;
258 gnutls_session session;
260 int allowed_protocols[4] = {0, 0, 0, 0};
261 gnutls_init (&session, GNUTLS_CLIENT);
262 gnutls_set_default_priority (session);
263 gnutls_certificate_type_set_priority (session, cert_type_priority);
264 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, credentials);
266 # define FD_TO_SOCKET(X) (X)
268 gnutls_transport_set_ptr (session, (gnutls_transport_ptr) FD_TO_SOCKET (fd));
271 switch (opt.secure_protocol)
273 case secure_protocol_auto:
275 case secure_protocol_sslv2:
276 case secure_protocol_sslv3:
277 allowed_protocols[0] = GNUTLS_SSL3;
278 err = gnutls_protocol_set_priority (session, allowed_protocols);
280 case secure_protocol_tlsv1:
281 allowed_protocols[0] = GNUTLS_TLS1_0;
282 allowed_protocols[1] = GNUTLS_TLS1_1;
283 allowed_protocols[2] = GNUTLS_TLS1_2;
284 err = gnutls_protocol_set_priority (session, allowed_protocols);
291 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
292 gnutls_deinit (session);
296 err = gnutls_handshake (session);
299 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
300 gnutls_deinit (session);
304 ctx = xnew0 (struct wgnutls_transport_context);
305 ctx->session = session;
306 fd_register_transport (fd, &wgnutls_transport, ctx);
311 ssl_check_certificate (int fd, const char *host)
313 struct wgnutls_transport_context *ctx = fd_transport_context (fd);
318 /* If the user has specified --no-check-cert, we still want to warn
319 him about problems with the server's certificate. */
320 const char *severity = opt.check_cert ? _("ERROR") : _("WARNING");
323 err = gnutls_certificate_verify_peers2 (ctx->session, &status);
326 logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
327 severity, quotearg_style (escape_quoting_style, host));
332 if (status & GNUTLS_CERT_INVALID)
334 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s is not trusted.\n"),
335 severity, quote (host));
338 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
340 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s hasn't got a known issuer.\n"),
341 severity, quote (host));
344 if (status & GNUTLS_CERT_REVOKED)
346 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s has been revoked.\n"),
347 severity, quote (host));
351 if (gnutls_certificate_type_get (ctx->session) == GNUTLS_CRT_X509)
353 time_t now = time (NULL);
354 gnutls_x509_crt cert;
355 const gnutls_datum *cert_list;
356 unsigned int cert_list_size;
358 if ((err = gnutls_x509_crt_init (&cert)) < 0)
360 logprintf (LOG_NOTQUIET, _("Error initializing X509 certificate: %s\n"),
361 gnutls_strerror (err));
366 cert_list = gnutls_certificate_get_peers (ctx->session, &cert_list_size);
369 logprintf (LOG_NOTQUIET, _("No certificate found\n"));
373 err = gnutls_x509_crt_import (cert, cert_list, GNUTLS_X509_FMT_DER);
376 logprintf (LOG_NOTQUIET, _("Error parsing certificate: %s\n"),
377 gnutls_strerror (err));
381 if (now < gnutls_x509_crt_get_activation_time (cert))
383 logprintf (LOG_NOTQUIET, _("The certificate has not yet been activated\n"));
386 if (now >= gnutls_x509_crt_get_expiration_time (cert))
388 logprintf (LOG_NOTQUIET, _("The certificate has expired\n"));
391 if (!gnutls_x509_crt_check_hostname (cert, host))
393 logprintf (LOG_NOTQUIET,
394 _("The certificate's owner does not match hostname %s\n"),
398 gnutls_x509_crt_deinit (cert);
402 return opt.check_cert ? success : true;