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>
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);
69 gnutls_certificate_set_verify_flags(credentials,
70 GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
72 ca_directory = opt.ca_directory ? opt.ca_directory : "/etc/ssl/certs";
74 dir = opendir (ca_directory);
78 logprintf (LOG_NOTQUIET, _("ERROR: Cannot open directory %s.\n"),
84 while ((dent = readdir (dir)) != NULL)
88 asprintf (&ca_file, "%s/%s", ca_directory, dent->d_name);
92 if (S_ISREG (st.st_mode))
93 gnutls_certificate_set_x509_trust_file (credentials, ca_file,
103 gnutls_certificate_set_x509_trust_file (credentials, opt.ca_cert,
104 GNUTLS_X509_FMT_PEM);
108 struct wgnutls_transport_context
110 gnutls_session session; /* GnuTLS session handle */
111 int last_error; /* last error returned by read/write/... */
113 /* Since GnuTLS doesn't support the equivalent to recv(...,
114 MSG_PEEK) or SSL_peek(), we have to do it ourselves. Peeked data
115 is stored to PEEKBUF, and wgnutls_read checks that buffer before
122 # define MIN(i, j) ((i) <= (j) ? (i) : (j))
126 wgnutls_read (int fd, char *buf, int bufsize, void *arg)
129 struct wgnutls_transport_context *ctx = arg;
133 /* If we have any peek data, simply return that. */
134 int copysize = MIN (bufsize, ctx->peeklen);
135 memcpy (buf, ctx->peekbuf, copysize);
136 ctx->peeklen -= copysize;
137 if (ctx->peeklen != 0)
138 memmove (ctx->peekbuf, ctx->peekbuf + copysize, ctx->peeklen);
144 ret = gnutls_record_recv (ctx->session, buf, bufsize);
145 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
148 ctx->last_error = ret;
154 wgnutls_write (int fd, char *buf, int bufsize, void *arg)
157 struct wgnutls_transport_context *ctx = arg;
159 ret = gnutls_record_send (ctx->session, buf, bufsize);
160 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
162 ctx->last_error = ret;
167 wgnutls_poll (int fd, double timeout, int wait_for, void *arg)
169 struct wgnutls_transport_context *ctx = arg;
170 return ctx->peeklen || gnutls_record_check_pending (ctx->session)
171 || select_fd (fd, timeout, wait_for);
175 wgnutls_peek (int fd, char *buf, int bufsize, void *arg)
178 struct wgnutls_transport_context *ctx = arg;
179 int offset = MIN (bufsize, ctx->peeklen);
180 if (bufsize > sizeof ctx->peekbuf)
181 bufsize = sizeof ctx->peekbuf;
184 memcpy (buf, ctx->peekbuf, offset);
186 if (bufsize > offset)
188 if (gnutls_record_check_pending (ctx->session) <= 0
189 && select_fd (fd, 0.0, WAIT_FOR_READ) <= 0)
192 read = gnutls_record_recv (ctx->session, buf + offset,
205 memcpy (ctx->peekbuf + offset, buf + offset,
207 ctx->peeklen += read;
211 return offset + read;
215 wgnutls_errstr (int fd, void *arg)
217 struct wgnutls_transport_context *ctx = arg;
218 return gnutls_strerror (ctx->last_error);
222 wgnutls_close (int fd, void *arg)
224 struct wgnutls_transport_context *ctx = arg;
225 /*gnutls_bye (ctx->session, GNUTLS_SHUT_RDWR);*/
226 gnutls_deinit (ctx->session);
231 /* gnutls_transport is the singleton that describes the SSL transport
232 methods provided by this file. */
234 static struct transport_implementation wgnutls_transport =
236 wgnutls_read, wgnutls_write, wgnutls_poll,
237 wgnutls_peek, wgnutls_errstr, wgnutls_close
241 ssl_connect_wget (int fd)
243 static const int cert_type_priority[] = {
244 GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP, 0
246 struct wgnutls_transport_context *ctx;
247 gnutls_session session;
249 gnutls_init (&session, GNUTLS_CLIENT);
250 gnutls_set_default_priority (session);
251 gnutls_certificate_type_set_priority (session, cert_type_priority);
252 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, credentials);
254 # define FD_TO_SOCKET(X) (X)
256 gnutls_transport_set_ptr (session, (gnutls_transport_ptr) FD_TO_SOCKET (fd));
259 #if HAVE_GNUTLS_PRIORITY_SET_DIRECT
260 switch (opt.secure_protocol)
262 case secure_protocol_auto:
264 case secure_protocol_sslv2:
265 case secure_protocol_sslv3:
266 err = gnutls_priority_set_direct (session, "NORMAL:-VERS-TLS-ALL", NULL);
268 case secure_protocol_tlsv1:
269 err = gnutls_priority_set_direct (session, "NORMAL:-VERS-SSL3.0", NULL);
275 int allowed_protocols[4] = {0, 0, 0, 0};
276 switch (opt.secure_protocol)
278 case secure_protocol_auto:
280 case secure_protocol_sslv2:
281 case secure_protocol_sslv3:
282 allowed_protocols[0] = GNUTLS_SSL3;
283 err = gnutls_protocol_set_priority (session, allowed_protocols);
286 case secure_protocol_tlsv1:
287 allowed_protocols[0] = GNUTLS_TLS1_0;
288 allowed_protocols[1] = GNUTLS_TLS1_1;
289 allowed_protocols[2] = GNUTLS_TLS1_2;
290 err = gnutls_protocol_set_priority (session, allowed_protocols);
300 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
301 gnutls_deinit (session);
305 err = gnutls_handshake (session);
308 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
309 gnutls_deinit (session);
313 ctx = xnew0 (struct wgnutls_transport_context);
314 ctx->session = session;
315 fd_register_transport (fd, &wgnutls_transport, ctx);
320 ssl_check_certificate (int fd, const char *host)
322 struct wgnutls_transport_context *ctx = fd_transport_context (fd);
327 /* If the user has specified --no-check-cert, we still want to warn
328 him about problems with the server's certificate. */
329 const char *severity = opt.check_cert ? _("ERROR") : _("WARNING");
332 err = gnutls_certificate_verify_peers2 (ctx->session, &status);
335 logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
336 severity, quotearg_style (escape_quoting_style, host));
341 if (status & GNUTLS_CERT_INVALID)
343 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s is not trusted.\n"),
344 severity, quote (host));
347 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
349 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s hasn't got a known issuer.\n"),
350 severity, quote (host));
353 if (status & GNUTLS_CERT_REVOKED)
355 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s has been revoked.\n"),
356 severity, quote (host));
360 if (gnutls_certificate_type_get (ctx->session) == GNUTLS_CRT_X509)
362 time_t now = time (NULL);
363 gnutls_x509_crt cert;
364 const gnutls_datum *cert_list;
365 unsigned int cert_list_size;
367 if ((err = gnutls_x509_crt_init (&cert)) < 0)
369 logprintf (LOG_NOTQUIET, _("Error initializing X509 certificate: %s\n"),
370 gnutls_strerror (err));
375 cert_list = gnutls_certificate_get_peers (ctx->session, &cert_list_size);
378 logprintf (LOG_NOTQUIET, _("No certificate found\n"));
382 err = gnutls_x509_crt_import (cert, cert_list, GNUTLS_X509_FMT_DER);
385 logprintf (LOG_NOTQUIET, _("Error parsing certificate: %s\n"),
386 gnutls_strerror (err));
390 if (now < gnutls_x509_crt_get_activation_time (cert))
392 logprintf (LOG_NOTQUIET, _("The certificate has not yet been activated\n"));
395 if (now >= gnutls_x509_crt_get_expiration_time (cert))
397 logprintf (LOG_NOTQUIET, _("The certificate has expired\n"));
400 if (!gnutls_x509_crt_check_hostname (cert, host))
402 logprintf (LOG_NOTQUIET,
403 _("The certificate's owner does not match hostname %s\n"),
407 gnutls_x509_crt_deinit (cert);
411 return opt.check_cert ? success : true;