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>
50 /* Note: some of the functions private to this file have names that
51 begin with "wgnutls_" (e.g. wgnutls_read) so that they wouldn't be
52 confused with actual gnutls functions -- such as the gnutls_read
53 preprocessor macro. */
55 static gnutls_certificate_credentials credentials;
60 gnutls_global_init ();
61 gnutls_certificate_allocate_credentials (&credentials);
63 gnutls_certificate_set_x509_trust_file (credentials, opt.ca_cert,
68 struct wgnutls_transport_context {
69 gnutls_session session; /* GnuTLS session handle */
70 int last_error; /* last error returned by read/write/... */
72 /* Since GnuTLS doesn't support the equivalent to recv(...,
73 MSG_PEEK) or SSL_peek(), we have to do it ourselves. Peeked data
74 is stored to PEEKBUF, and wgnutls_read checks that buffer before
81 # define MIN(i, j) ((i) <= (j) ? (i) : (j))
85 wgnutls_read (int fd, char *buf, int bufsize, void *arg)
88 struct wgnutls_transport_context *ctx = arg;
92 /* If we have any peek data, simply return that. */
93 int copysize = MIN (bufsize, ctx->peeklen);
94 memcpy (buf, ctx->peekbuf, copysize);
95 ctx->peeklen -= copysize;
96 if (ctx->peeklen != 0)
97 memmove (ctx->peekbuf, ctx->peekbuf + copysize, ctx->peeklen);
103 ret = gnutls_record_recv (ctx->session, buf, bufsize);
104 while (ret == GNUTLS_E_INTERRUPTED);
107 ctx->last_error = ret;
112 wgnutls_write (int fd, char *buf, int bufsize, void *arg)
115 struct wgnutls_transport_context *ctx = arg;
117 ret = gnutls_record_send (ctx->session, buf, bufsize);
118 while (ret == GNUTLS_E_INTERRUPTED);
120 ctx->last_error = ret;
125 wgnutls_poll (int fd, double timeout, int wait_for, void *arg)
127 struct wgnutls_transport_context *ctx = arg;
128 return ctx->peeklen || gnutls_record_check_pending (ctx->session)
129 || select_fd (fd, timeout, wait_for);
133 wgnutls_peek (int fd, char *buf, int bufsize, void *arg)
136 struct wgnutls_transport_context *ctx = arg;
137 int offset = ctx->peeklen;
139 if (bufsize > sizeof ctx->peekbuf)
140 bufsize = sizeof ctx->peekbuf;
143 memcpy (buf, ctx->peekbuf, offset);
147 if (gnutls_record_check_pending (ctx->session)
148 || select_fd (fd, 0, WAIT_FOR_READ))
149 ret = gnutls_record_recv (ctx->session, buf + offset, bufsize - offset);
151 while (ret == GNUTLS_E_INTERRUPTED);
155 memcpy (ctx->peekbuf + offset, buf + offset, ret);
162 wgnutls_errstr (int fd, void *arg)
164 struct wgnutls_transport_context *ctx = arg;
165 return gnutls_strerror (ctx->last_error);
169 wgnutls_close (int fd, void *arg)
171 struct wgnutls_transport_context *ctx = arg;
172 /*gnutls_bye (ctx->session, GNUTLS_SHUT_RDWR);*/
173 gnutls_deinit (ctx->session);
178 /* gnutls_transport is the singleton that describes the SSL transport
179 methods provided by this file. */
181 static struct transport_implementation wgnutls_transport = {
182 wgnutls_read, wgnutls_write, wgnutls_poll,
183 wgnutls_peek, wgnutls_errstr, wgnutls_close
187 ssl_connect_wget (int fd)
189 static const int cert_type_priority[] = {
190 GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP, 0
192 struct wgnutls_transport_context *ctx;
193 gnutls_session session;
195 gnutls_init (&session, GNUTLS_CLIENT);
196 gnutls_set_default_priority (session);
197 gnutls_certificate_type_set_priority (session, cert_type_priority);
198 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, credentials);
199 gnutls_transport_set_ptr (session, (gnutls_transport_ptr) fd);
200 err = gnutls_handshake (session);
203 logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
204 gnutls_deinit (session);
207 ctx = xnew0 (struct wgnutls_transport_context);
208 ctx->session = session;
209 fd_register_transport (fd, &wgnutls_transport, ctx);
214 ssl_check_certificate (int fd, const char *host)
216 struct wgnutls_transport_context *ctx = fd_transport_context (fd);
221 /* If the user has specified --no-check-cert, we still want to warn
222 him about problems with the server's certificate. */
223 const char *severity = opt.check_cert ? _("ERROR") : _("WARNING");
226 err = gnutls_certificate_verify_peers2 (ctx->session, &status);
229 logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
230 severity, quotearg_style (escape_quoting_style, host));
235 if (status & GNUTLS_CERT_INVALID)
237 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s is not trusted.\n"),
238 severity, quote (host));
241 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
243 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s hasn't got a known issuer.\n"),
244 severity, quote (host));
247 if (status & GNUTLS_CERT_REVOKED)
249 logprintf (LOG_NOTQUIET, _("%s: The certificate of %s has been revoked.\n"),
250 severity, quote (host));
254 if (gnutls_certificate_type_get (ctx->session) == GNUTLS_CRT_X509)
256 time_t now = time (NULL);
257 gnutls_x509_crt cert;
258 const gnutls_datum *cert_list;
259 unsigned int cert_list_size;
261 if ((err = gnutls_x509_crt_init (&cert)) < 0)
263 logprintf (LOG_NOTQUIET, _("Error initializing X509 certificate: %s\n"),
264 gnutls_strerror (err));
269 cert_list = gnutls_certificate_get_peers (ctx->session, &cert_list_size);
272 logprintf (LOG_NOTQUIET, _("No certificate found\n"));
276 err = gnutls_x509_crt_import (cert, cert_list, GNUTLS_X509_FMT_DER);
279 logprintf (LOG_NOTQUIET, _("Error parsing certificate: %s\n"),
280 gnutls_strerror (err));
284 if (now < gnutls_x509_crt_get_activation_time (cert))
286 logprintf (LOG_NOTQUIET, _("The certificate has not yet been activated\n"));
289 if (now >= gnutls_x509_crt_get_expiration_time (cert))
291 logprintf (LOG_NOTQUIET, _("The certificate has expired\n"));
294 if (!gnutls_x509_crt_check_hostname (cert, host))
296 logprintf (LOG_NOTQUIET,
297 _("The certificate's owner does not match hostname %s\n"),
301 gnutls_x509_crt_deinit (cert);
305 return opt.check_cert ? success : true;