1 /* SSL support via GnuTLS library.
2 Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 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. */
43 #include <gnutls/gnutls.h>
44 #include <gnutls/x509.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 {
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;
151 wgnutls_write (int fd, char *buf, int bufsize, void *arg)
154 struct wgnutls_transport_context *ctx = arg;
156 ret = gnutls_record_send (ctx->session, buf, bufsize);
157 while (ret == GNUTLS_E_INTERRUPTED);
159 ctx->last_error = ret;
164 wgnutls_poll (int fd, double timeout, int wait_for, void *arg)
166 struct wgnutls_transport_context *ctx = arg;
167 return ctx->peeklen || gnutls_record_check_pending (ctx->session)
168 || select_fd (fd, timeout, wait_for);
172 wgnutls_peek (int fd, char *buf, int bufsize, void *arg)
175 struct wgnutls_transport_context *ctx = arg;
176 int offset = MIN (bufsize, ctx->peeklen);
177 if (bufsize > sizeof ctx->peekbuf)
178 bufsize = sizeof ctx->peekbuf;
181 memcpy (buf, ctx->peekbuf, offset);
183 if (bufsize > offset)
187 if (gnutls_record_check_pending (ctx->session)
188 || select_fd (fd, 0, WAIT_FOR_READ))
189 ret = gnutls_record_recv (ctx->session, buf + offset,
192 while (ret == GNUTLS_E_INTERRUPTED);
196 memcpy (ctx->peekbuf + offset, buf + offset,
206 wgnutls_errstr (int fd, void *arg)
208 struct wgnutls_transport_context *ctx = arg;
209 return gnutls_strerror (ctx->last_error);
213 wgnutls_close (int fd, void *arg)
215 struct wgnutls_transport_context *ctx = arg;
216 /*gnutls_bye (ctx->session, GNUTLS_SHUT_RDWR);*/
217 gnutls_deinit (ctx->session);
222 /* gnutls_transport is the singleton that describes the SSL transport
223 methods provided by this file. */
225 static struct transport_implementation wgnutls_transport = {
226 wgnutls_read, wgnutls_write, wgnutls_poll,
227 wgnutls_peek, wgnutls_errstr, wgnutls_close
231 ssl_connect_wget (int fd)
233 static const int cert_type_priority[] = {
234 GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP, 0
236 struct wgnutls_transport_context *ctx;
237 gnutls_session session;
239 int allowed_protocols[4] = {0, 0, 0, 0};
240 gnutls_init (&session, GNUTLS_CLIENT);
241 gnutls_set_default_priority (session);
242 gnutls_certificate_type_set_priority (session, cert_type_priority);
243 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, credentials);
245 # define FD_TO_SOCKET(X) (X)
247 gnutls_transport_set_ptr (session, (gnutls_transport_ptr) FD_TO_SOCKET (fd));
250 switch (opt.secure_protocol)
252 case secure_protocol_auto:
254 case secure_protocol_sslv2:
255 case secure_protocol_sslv3:
256 allowed_protocols[0] = GNUTLS_SSL3;
257 err = gnutls_protocol_set_priority (session, allowed_protocols);
259 case secure_protocol_tlsv1:
260 allowed_protocols[0] = GNUTLS_TLS1_0;
261 allowed_protocols[1] = GNUTLS_TLS1_1;
262 allowed_protocols[2] = GNUTLS_TLS1_2;
263 err = gnutls_protocol_set_priority (session, allowed_protocols);
270 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
271 gnutls_deinit (session);
275 err = gnutls_handshake (session);
278 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
279 gnutls_deinit (session);
283 ctx = xnew0 (struct wgnutls_transport_context);
284 ctx->session = session;
285 fd_register_transport (fd, &wgnutls_transport, ctx);
290 ssl_check_certificate (int fd, const char *host)
292 struct wgnutls_transport_context *ctx = fd_transport_context (fd);
297 /* If the user has specified --no-check-cert, we still want to warn
298 him about problems with the server's certificate. */
299 const char *severity = opt.check_cert ? _("ERROR") : _("WARNING");
302 err = gnutls_certificate_verify_peers2 (ctx->session, &status);
305 logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
306 severity, quotearg_style (escape_quoting_style, host));
311 if (status & GNUTLS_CERT_INVALID)
313 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s is not trusted.\n"),
314 severity, quote (host));
317 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
319 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s hasn't got a known issuer.\n"),
320 severity, quote (host));
323 if (status & GNUTLS_CERT_REVOKED)
325 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s has been revoked.\n"),
326 severity, quote (host));
330 if (gnutls_certificate_type_get (ctx->session) == GNUTLS_CRT_X509)
332 time_t now = time (NULL);
333 gnutls_x509_crt cert;
334 const gnutls_datum *cert_list;
335 unsigned int cert_list_size;
337 if ((err = gnutls_x509_crt_init (&cert)) < 0)
339 logprintf (LOG_NOTQUIET, _("Error initializing X509 certificate: %s\n"),
340 gnutls_strerror (err));
345 cert_list = gnutls_certificate_get_peers (ctx->session, &cert_list_size);
348 logprintf (LOG_NOTQUIET, _("No certificate found\n"));
352 err = gnutls_x509_crt_import (cert, cert_list, GNUTLS_X509_FMT_DER);
355 logprintf (LOG_NOTQUIET, _("Error parsing certificate: %s\n"),
356 gnutls_strerror (err));
360 if (now < gnutls_x509_crt_get_activation_time (cert))
362 logprintf (LOG_NOTQUIET, _("The certificate has not yet been activated\n"));
365 if (now >= gnutls_x509_crt_get_expiration_time (cert))
367 logprintf (LOG_NOTQUIET, _("The certificate has expired\n"));
370 if (!gnutls_x509_crt_check_hostname (cert, host))
372 logprintf (LOG_NOTQUIET,
373 _("The certificate's owner does not match hostname %s\n"),
377 gnutls_x509_crt_deinit (cert);
381 return opt.check_cert ? success : true;