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. */
42 #include <gnutls/gnutls.h>
43 #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 gnutls_global_init ();
65 gnutls_certificate_allocate_credentials (&credentials);
67 gnutls_certificate_set_x509_trust_file (credentials, opt.ca_cert,
72 struct wgnutls_transport_context {
73 gnutls_session session; /* GnuTLS session handle */
74 int last_error; /* last error returned by read/write/... */
76 /* Since GnuTLS doesn't support the equivalent to recv(...,
77 MSG_PEEK) or SSL_peek(), we have to do it ourselves. Peeked data
78 is stored to PEEKBUF, and wgnutls_read checks that buffer before
85 # define MIN(i, j) ((i) <= (j) ? (i) : (j))
89 wgnutls_read (int fd, char *buf, int bufsize, void *arg)
92 struct wgnutls_transport_context *ctx = arg;
96 /* If we have any peek data, simply return that. */
97 int copysize = MIN (bufsize, ctx->peeklen);
98 memcpy (buf, ctx->peekbuf, copysize);
99 ctx->peeklen -= copysize;
100 if (ctx->peeklen != 0)
101 memmove (ctx->peekbuf, ctx->peekbuf + copysize, ctx->peeklen);
107 ret = gnutls_record_recv (ctx->session, buf, bufsize);
108 while (ret == GNUTLS_E_INTERRUPTED);
111 ctx->last_error = ret;
116 wgnutls_write (int fd, char *buf, int bufsize, void *arg)
119 struct wgnutls_transport_context *ctx = arg;
121 ret = gnutls_record_send (ctx->session, buf, bufsize);
122 while (ret == GNUTLS_E_INTERRUPTED);
124 ctx->last_error = ret;
129 wgnutls_poll (int fd, double timeout, int wait_for, void *arg)
131 struct wgnutls_transport_context *ctx = arg;
132 return ctx->peeklen || gnutls_record_check_pending (ctx->session)
133 || select_fd (fd, timeout, wait_for);
137 wgnutls_peek (int fd, char *buf, int bufsize, void *arg)
140 struct wgnutls_transport_context *ctx = arg;
141 int offset = ctx->peeklen;
143 if (bufsize > sizeof ctx->peekbuf)
144 bufsize = sizeof ctx->peekbuf;
147 memcpy (buf, ctx->peekbuf, offset);
151 if (gnutls_record_check_pending (ctx->session)
152 || select_fd (fd, 0, WAIT_FOR_READ))
153 ret = gnutls_record_recv (ctx->session, buf + offset, bufsize - offset);
155 while (ret == GNUTLS_E_INTERRUPTED);
159 memcpy (ctx->peekbuf + offset, buf + offset, ret);
166 wgnutls_errstr (int fd, void *arg)
168 struct wgnutls_transport_context *ctx = arg;
169 return gnutls_strerror (ctx->last_error);
173 wgnutls_close (int fd, void *arg)
175 struct wgnutls_transport_context *ctx = arg;
176 /*gnutls_bye (ctx->session, GNUTLS_SHUT_RDWR);*/
177 gnutls_deinit (ctx->session);
182 /* gnutls_transport is the singleton that describes the SSL transport
183 methods provided by this file. */
185 static struct transport_implementation wgnutls_transport = {
186 wgnutls_read, wgnutls_write, wgnutls_poll,
187 wgnutls_peek, wgnutls_errstr, wgnutls_close
191 ssl_connect_wget (int fd)
193 static const int cert_type_priority[] = {
194 GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP, 0
196 struct wgnutls_transport_context *ctx;
197 gnutls_session session;
199 int allowed_protocols[4] = {0, 0, 0, 0};
200 gnutls_init (&session, GNUTLS_CLIENT);
201 gnutls_set_default_priority (session);
202 gnutls_certificate_type_set_priority (session, cert_type_priority);
203 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, credentials);
205 # define FD_TO_SOCKET(X) (X)
207 gnutls_transport_set_ptr (session, (gnutls_transport_ptr) FD_TO_SOCKET (fd));
210 switch (opt.secure_protocol)
212 case secure_protocol_auto:
214 case secure_protocol_sslv2:
215 case secure_protocol_sslv3:
216 allowed_protocols[0] = GNUTLS_SSL3;
217 err = gnutls_protocol_set_priority (session, allowed_protocols);
219 case secure_protocol_tlsv1:
220 allowed_protocols[0] = GNUTLS_TLS1_0;
221 allowed_protocols[1] = GNUTLS_TLS1_1;
222 allowed_protocols[2] = GNUTLS_TLS1_2;
223 err = gnutls_protocol_set_priority (session, allowed_protocols);
230 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
231 gnutls_deinit (session);
235 err = gnutls_handshake (session);
238 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
239 gnutls_deinit (session);
243 ctx = xnew0 (struct wgnutls_transport_context);
244 ctx->session = session;
245 fd_register_transport (fd, &wgnutls_transport, ctx);
250 ssl_check_certificate (int fd, const char *host)
252 struct wgnutls_transport_context *ctx = fd_transport_context (fd);
257 /* If the user has specified --no-check-cert, we still want to warn
258 him about problems with the server's certificate. */
259 const char *severity = opt.check_cert ? _("ERROR") : _("WARNING");
262 err = gnutls_certificate_verify_peers2 (ctx->session, &status);
265 logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
266 severity, quotearg_style (escape_quoting_style, host));
271 if (status & GNUTLS_CERT_INVALID)
273 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s is not trusted.\n"),
274 severity, quote (host));
277 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
279 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s hasn't got a known issuer.\n"),
280 severity, quote (host));
283 if (status & GNUTLS_CERT_REVOKED)
285 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s has been revoked.\n"),
286 severity, quote (host));
290 if (gnutls_certificate_type_get (ctx->session) == GNUTLS_CRT_X509)
292 time_t now = time (NULL);
293 gnutls_x509_crt cert;
294 const gnutls_datum *cert_list;
295 unsigned int cert_list_size;
297 if ((err = gnutls_x509_crt_init (&cert)) < 0)
299 logprintf (LOG_NOTQUIET, _("Error initializing X509 certificate: %s\n"),
300 gnutls_strerror (err));
305 cert_list = gnutls_certificate_get_peers (ctx->session, &cert_list_size);
308 logprintf (LOG_NOTQUIET, _("No certificate found\n"));
312 err = gnutls_x509_crt_import (cert, cert_list, GNUTLS_X509_FMT_DER);
315 logprintf (LOG_NOTQUIET, _("Error parsing certificate: %s\n"),
316 gnutls_strerror (err));
320 if (now < gnutls_x509_crt_get_activation_time (cert))
322 logprintf (LOG_NOTQUIET, _("The certificate has not yet been activated\n"));
325 if (now >= gnutls_x509_crt_get_expiration_time (cert))
327 logprintf (LOG_NOTQUIET, _("The certificate has expired\n"));
330 if (!gnutls_x509_crt_check_hostname (cert, host))
332 logprintf (LOG_NOTQUIET,
333 _("The certificate's owner does not match hostname %s\n"),
337 gnutls_x509_crt_deinit (cert);
341 return opt.check_cert ? success : true;