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);
71 ca_directory = opt.ca_directory ? opt.ca_directory : "/etc/ssl/certs";
73 dir = opendir (ca_directory);
77 logprintf (LOG_NOTQUIET, _("ERROR: Cannot open directory %s.\n"),
83 while ((dent = readdir (dir)) != NULL)
87 asprintf (&ca_file, "%s/%s", ca_directory, dent->d_name);
91 if (S_ISREG (st.st_mode))
92 gnutls_certificate_set_x509_trust_file (credentials, ca_file,
102 gnutls_certificate_set_x509_trust_file (credentials, opt.ca_cert,
103 GNUTLS_X509_FMT_PEM);
107 struct wgnutls_transport_context
109 gnutls_session session; /* GnuTLS session handle */
110 int last_error; /* last error returned by read/write/... */
112 /* Since GnuTLS doesn't support the equivalent to recv(...,
113 MSG_PEEK) or SSL_peek(), we have to do it ourselves. Peeked data
114 is stored to PEEKBUF, and wgnutls_read checks that buffer before
121 # define MIN(i, j) ((i) <= (j) ? (i) : (j))
125 wgnutls_read (int fd, char *buf, int bufsize, void *arg)
128 struct wgnutls_transport_context *ctx = arg;
132 /* If we have any peek data, simply return that. */
133 int copysize = MIN (bufsize, ctx->peeklen);
134 memcpy (buf, ctx->peekbuf, copysize);
135 ctx->peeklen -= copysize;
136 if (ctx->peeklen != 0)
137 memmove (ctx->peekbuf, ctx->peekbuf + copysize, ctx->peeklen);
143 ret = gnutls_record_recv (ctx->session, buf, bufsize);
144 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
147 ctx->last_error = ret;
153 wgnutls_write (int fd, char *buf, int bufsize, void *arg)
156 struct wgnutls_transport_context *ctx = arg;
158 ret = gnutls_record_send (ctx->session, buf, bufsize);
159 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
161 ctx->last_error = ret;
166 wgnutls_poll (int fd, double timeout, int wait_for, void *arg)
168 struct wgnutls_transport_context *ctx = arg;
169 return ctx->peeklen || gnutls_record_check_pending (ctx->session)
170 || select_fd (fd, timeout, wait_for);
174 wgnutls_peek (int fd, char *buf, int bufsize, void *arg)
176 int ret = 0, read = 0;
177 struct wgnutls_transport_context *ctx = arg;
178 int offset = MIN (bufsize, ctx->peeklen);
179 if (bufsize > sizeof ctx->peekbuf)
180 bufsize = sizeof ctx->peekbuf;
183 memcpy (buf, ctx->peekbuf, offset);
185 if (bufsize > offset)
189 flags = fcntl (fd, F_GETFL, 0);
193 ret = fcntl (fd, F_SETFL, flags | O_NONBLOCK);
197 /* XXX: Assume it was blocking before. */
199 ret = ioctl (fd, FIONBIO, &zero);
205 ret = gnutls_record_recv (ctx->session, buf + offset,
208 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
222 memcpy (ctx->peekbuf + offset, buf + offset,
224 ctx->peeklen += read;
228 ret = fcntl (fd, F_SETFL, flags);
233 ret = ioctl (fd, FIONBIO, &one);
239 return offset + read;
243 wgnutls_errstr (int fd, void *arg)
245 struct wgnutls_transport_context *ctx = arg;
246 return gnutls_strerror (ctx->last_error);
250 wgnutls_close (int fd, void *arg)
252 struct wgnutls_transport_context *ctx = arg;
253 /*gnutls_bye (ctx->session, GNUTLS_SHUT_RDWR);*/
254 gnutls_deinit (ctx->session);
259 /* gnutls_transport is the singleton that describes the SSL transport
260 methods provided by this file. */
262 static struct transport_implementation wgnutls_transport =
264 wgnutls_read, wgnutls_write, wgnutls_poll,
265 wgnutls_peek, wgnutls_errstr, wgnutls_close
269 ssl_connect_wget (int fd)
271 static const int cert_type_priority[] = {
272 GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP, 0
274 struct wgnutls_transport_context *ctx;
275 gnutls_session session;
277 int allowed_protocols[4] = {0, 0, 0, 0};
278 gnutls_init (&session, GNUTLS_CLIENT);
279 gnutls_set_default_priority (session);
280 gnutls_certificate_type_set_priority (session, cert_type_priority);
281 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, credentials);
283 # define FD_TO_SOCKET(X) (X)
285 gnutls_transport_set_ptr (session, (gnutls_transport_ptr) FD_TO_SOCKET (fd));
288 switch (opt.secure_protocol)
290 case secure_protocol_auto:
292 case secure_protocol_sslv2:
293 case secure_protocol_sslv3:
294 allowed_protocols[0] = GNUTLS_SSL3;
295 err = gnutls_protocol_set_priority (session, allowed_protocols);
297 case secure_protocol_tlsv1:
298 allowed_protocols[0] = GNUTLS_TLS1_0;
299 allowed_protocols[1] = GNUTLS_TLS1_1;
300 allowed_protocols[2] = GNUTLS_TLS1_2;
301 err = gnutls_protocol_set_priority (session, allowed_protocols);
308 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
309 gnutls_deinit (session);
313 err = gnutls_handshake (session);
316 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
317 gnutls_deinit (session);
321 ctx = xnew0 (struct wgnutls_transport_context);
322 ctx->session = session;
323 fd_register_transport (fd, &wgnutls_transport, ctx);
328 ssl_check_certificate (int fd, const char *host)
330 struct wgnutls_transport_context *ctx = fd_transport_context (fd);
335 /* If the user has specified --no-check-cert, we still want to warn
336 him about problems with the server's certificate. */
337 const char *severity = opt.check_cert ? _("ERROR") : _("WARNING");
340 err = gnutls_certificate_verify_peers2 (ctx->session, &status);
343 logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
344 severity, quotearg_style (escape_quoting_style, host));
349 if (status & GNUTLS_CERT_INVALID)
351 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s is not trusted.\n"),
352 severity, quote (host));
355 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
357 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s hasn't got a known issuer.\n"),
358 severity, quote (host));
361 if (status & GNUTLS_CERT_REVOKED)
363 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s has been revoked.\n"),
364 severity, quote (host));
368 if (gnutls_certificate_type_get (ctx->session) == GNUTLS_CRT_X509)
370 time_t now = time (NULL);
371 gnutls_x509_crt cert;
372 const gnutls_datum *cert_list;
373 unsigned int cert_list_size;
375 if ((err = gnutls_x509_crt_init (&cert)) < 0)
377 logprintf (LOG_NOTQUIET, _("Error initializing X509 certificate: %s\n"),
378 gnutls_strerror (err));
383 cert_list = gnutls_certificate_get_peers (ctx->session, &cert_list_size);
386 logprintf (LOG_NOTQUIET, _("No certificate found\n"));
390 err = gnutls_x509_crt_import (cert, cert_list, GNUTLS_X509_FMT_DER);
393 logprintf (LOG_NOTQUIET, _("Error parsing certificate: %s\n"),
394 gnutls_strerror (err));
398 if (now < gnutls_x509_crt_get_activation_time (cert))
400 logprintf (LOG_NOTQUIET, _("The certificate has not yet been activated\n"));
403 if (now >= gnutls_x509_crt_get_expiration_time (cert))
405 logprintf (LOG_NOTQUIET, _("The certificate has expired\n"));
408 if (!gnutls_x509_crt_check_hostname (cert, host))
410 logprintf (LOG_NOTQUIET,
411 _("The certificate's owner does not match hostname %s\n"),
415 gnutls_x509_crt_deinit (cert);
419 return opt.check_cert ? success : true;