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>
44 #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)
130 struct wgnutls_transport_context *ctx = arg;
134 /* If we have any peek data, simply return that. */
135 int copysize = MIN (bufsize, ctx->peeklen);
136 memcpy (buf, ctx->peekbuf, copysize);
137 ctx->peeklen -= copysize;
138 if (ctx->peeklen != 0)
139 memmove (ctx->peekbuf, ctx->peekbuf + copysize, ctx->peeklen);
145 ret = gnutls_record_recv (ctx->session, buf, bufsize);
146 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
149 ctx->last_error = ret;
155 wgnutls_write (int fd, char *buf, int bufsize, void *arg)
158 struct wgnutls_transport_context *ctx = arg;
160 ret = gnutls_record_send (ctx->session, buf, bufsize);
161 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
163 ctx->last_error = ret;
168 wgnutls_poll (int fd, double timeout, int wait_for, void *arg)
170 struct wgnutls_transport_context *ctx = arg;
171 return ctx->peeklen || gnutls_record_check_pending (ctx->session)
172 || select_fd (fd, timeout, wait_for);
176 wgnutls_peek (int fd, char *buf, int bufsize, void *arg)
178 int ret = 0, read = 0;
179 struct wgnutls_transport_context *ctx = arg;
180 int offset = MIN (bufsize, ctx->peeklen);
181 if (bufsize > sizeof ctx->peekbuf)
182 bufsize = sizeof ctx->peekbuf;
185 memcpy (buf, ctx->peekbuf, offset);
187 if (bufsize > offset)
191 flags = fcntl (fd, F_GETFL, 0);
195 ret = fcntl (fd, F_SETFL, flags | O_NONBLOCK);
199 /* XXX: Assume it was blocking before. */
201 ret = ioctl (fd, FIONBIO, &zero);
207 ret = gnutls_record_recv (ctx->session, buf + offset,
210 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
224 memcpy (ctx->peekbuf + offset, buf + offset,
226 ctx->peeklen += read;
230 ret = fcntl (fd, F_SETFL, flags);
235 ret = ioctl (fd, FIONBIO, &one);
241 return offset + read;
245 wgnutls_errstr (int fd, void *arg)
247 struct wgnutls_transport_context *ctx = arg;
248 return gnutls_strerror (ctx->last_error);
252 wgnutls_close (int fd, void *arg)
254 struct wgnutls_transport_context *ctx = arg;
255 /*gnutls_bye (ctx->session, GNUTLS_SHUT_RDWR);*/
256 gnutls_deinit (ctx->session);
261 /* gnutls_transport is the singleton that describes the SSL transport
262 methods provided by this file. */
264 static struct transport_implementation wgnutls_transport =
266 wgnutls_read, wgnutls_write, wgnutls_poll,
267 wgnutls_peek, wgnutls_errstr, wgnutls_close
271 ssl_connect_wget (int fd)
273 static const int cert_type_priority[] = {
274 GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP, 0
276 struct wgnutls_transport_context *ctx;
277 gnutls_session session;
279 int allowed_protocols[4] = {0, 0, 0, 0};
280 gnutls_init (&session, GNUTLS_CLIENT);
281 gnutls_set_default_priority (session);
282 gnutls_certificate_type_set_priority (session, cert_type_priority);
283 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, credentials);
285 # define FD_TO_SOCKET(X) (X)
287 gnutls_transport_set_ptr (session, (gnutls_transport_ptr) FD_TO_SOCKET (fd));
290 switch (opt.secure_protocol)
292 case secure_protocol_auto:
294 case secure_protocol_sslv2:
295 case secure_protocol_sslv3:
296 allowed_protocols[0] = GNUTLS_SSL3;
297 err = gnutls_protocol_set_priority (session, allowed_protocols);
299 case secure_protocol_tlsv1:
300 allowed_protocols[0] = GNUTLS_TLS1_0;
301 allowed_protocols[1] = GNUTLS_TLS1_1;
302 allowed_protocols[2] = GNUTLS_TLS1_2;
303 err = gnutls_protocol_set_priority (session, allowed_protocols);
310 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
311 gnutls_deinit (session);
315 err = gnutls_handshake (session);
318 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
319 gnutls_deinit (session);
323 ctx = xnew0 (struct wgnutls_transport_context);
324 ctx->session = session;
325 fd_register_transport (fd, &wgnutls_transport, ctx);
330 ssl_check_certificate (int fd, const char *host)
332 struct wgnutls_transport_context *ctx = fd_transport_context (fd);
337 /* If the user has specified --no-check-cert, we still want to warn
338 him about problems with the server's certificate. */
339 const char *severity = opt.check_cert ? _("ERROR") : _("WARNING");
342 err = gnutls_certificate_verify_peers2 (ctx->session, &status);
345 logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
346 severity, quotearg_style (escape_quoting_style, host));
351 if (status & GNUTLS_CERT_INVALID)
353 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s is not trusted.\n"),
354 severity, quote (host));
357 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
359 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s hasn't got a known issuer.\n"),
360 severity, quote (host));
363 if (status & GNUTLS_CERT_REVOKED)
365 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s has been revoked.\n"),
366 severity, quote (host));
370 if (gnutls_certificate_type_get (ctx->session) == GNUTLS_CRT_X509)
372 time_t now = time (NULL);
373 gnutls_x509_crt cert;
374 const gnutls_datum *cert_list;
375 unsigned int cert_list_size;
377 if ((err = gnutls_x509_crt_init (&cert)) < 0)
379 logprintf (LOG_NOTQUIET, _("Error initializing X509 certificate: %s\n"),
380 gnutls_strerror (err));
385 cert_list = gnutls_certificate_get_peers (ctx->session, &cert_list_size);
388 logprintf (LOG_NOTQUIET, _("No certificate found\n"));
392 err = gnutls_x509_crt_import (cert, cert_list, GNUTLS_X509_FMT_DER);
395 logprintf (LOG_NOTQUIET, _("Error parsing certificate: %s\n"),
396 gnutls_strerror (err));
400 if (now < gnutls_x509_crt_get_activation_time (cert))
402 logprintf (LOG_NOTQUIET, _("The certificate has not yet been activated\n"));
405 if (now >= gnutls_x509_crt_get_expiration_time (cert))
407 logprintf (LOG_NOTQUIET, _("The certificate has expired\n"));
410 if (!gnutls_x509_crt_check_hostname (cert, host))
412 logprintf (LOG_NOTQUIET,
413 _("The certificate's owner does not match hostname %s\n"),
417 gnutls_x509_crt_deinit (cert);
421 return opt.check_cert ? success : true;