]> sjero.net Git - wget/commitdiff
[svn] Add GnuTLS support.
authorhniksic <devnull@localhost>
Tue, 5 Jul 2005 00:16:46 +0000 (17:16 -0700)
committerhniksic <devnull@localhost>
Tue, 5 Jul 2005 00:16:46 +0000 (17:16 -0700)
ChangeLog
configure.in
src/ChangeLog
src/Makefile.in
src/gnutls.c [new file with mode: 0644]
src/wget.h

index 0cfc11d3cbf0aa44349a7dcac67e2112ef92bb51..d34bd9f4150278fff9eb346d9e671e3e3c2c841d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2005-07-05  Hrvoje Niksic  <hniksic@xemacs.org>
+
+       * configure.in: Add check for GnuTLS if --with-ssl=gnutls is used.
+
 2005-07-03  Hrvoje Niksic  <hniksic@xemacs.org>
 
        * po/POTFILES.in: Include src/ptimer.c.
index 68107e04c7c1d93e9c55425dec76f507bfdae5d6..ba3d28dad1a1d3a0817e9e0a699277840abff490 100644 (file)
@@ -239,9 +239,20 @@ dnl
 dnl Checks for libraries.
 dnl
 
-dnl Check for OpenSSL
-if test x"$with_ssl" != x"no"
+if test x"$with_ssl" = xgnutls
 then
+  dnl Now actually check for -lssl
+  AC_LIB_HAVE_LINKFLAGS([gnutls], [], [
+#include <gnutls/gnutls.h>
+  ], [gnutls_global_init()])
+  if test x"$LIBGNUTLS" != x
+  then
+    AC_MSG_NOTICE([compiling in support for SSL via GnuTLS])
+    AC_DEFINE([HAVE_GNUTLS], 1,
+             [Define if support for the GnuTLS library is being compiled in.])
+    SSL_OBJ='gnutls.o'
+  fi
+else
   dnl As of this writing (OpenSSL 0.9.6), the libcrypto shared library
   dnl doesn't record its dependency on libdl, so we need to make sure
   dnl -ldl ends up in LIBS on systems that have it.  Most OSes use
@@ -262,12 +273,13 @@ then
   ], [SSL_library_init ()])
   if test x"$LIBSSL" != x
   then
-    AC_MSG_NOTICE([compiling in support for SSL])
-    AC_DEFINE([HAVE_SSL], 1,
-             [Define if SSL support is being compiled in.])
+    AC_MSG_NOTICE([compiling in support for SSL via OpenSSL])
+    AC_DEFINE([HAVE_OPENSSL], 1,
+             [Define if support for the OpenSSL library is being compiled in.])
     SSL_OBJ='openssl.o'
   fi
 fi
+
 AC_SUBST(SSL_OBJ)
 
 dnl Enable NTLM if requested and if SSL is available.
index fb93734f38ae81ace941f7e8ccc48c268ac94814..644559f22a4b5a40b15d59efbdb4343e12a96cea 100644 (file)
@@ -1,3 +1,10 @@
+2005-07-05  Hrvoje Niksic  <hniksic@xemacs.org>
+
+       * wget.h (or): Define HAVE_SSL when either HAVE_OPENSSL or
+       HAVE_GNUTLS are defined.
+
+       * gnutls.c: New file.
+
 2005-07-05  Hrvoje Niksic  <hniksic@xemacs.org>
 
        * http.c (gethttp): Don't print the request write error message
index 7b793e1276b5341717d860dc7773cebb403e408f..5769b114450b0ac4623a9d262ccf1afccc1189e3 100644 (file)
@@ -51,7 +51,7 @@ CPPFLAGS = @CPPFLAGS@
 DEFS     = @DEFS@ -DSYSTEM_WGETRC=\"$(sysconfdir)/wgetrc\" -DLOCALEDIR=\"$(localedir)\"
 CFLAGS   = @CFLAGS@
 LDFLAGS  = @LDFLAGS@ 
-LIBS     = @LIBS@ @LIBSSL@
+LIBS     = @LIBS@ @LIBSSL@ @LIBGNUTLS@
 exeext   = @exeext@
 
 INCLUDES = -I. -I$(srcdir)
diff --git a/src/gnutls.c b/src/gnutls.c
new file mode 100644 (file)
index 0000000..5cf8bd8
--- /dev/null
@@ -0,0 +1,254 @@
+/* SSL support via GnuTLS library.
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Wget.
+
+GNU Wget is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+GNU Wget is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Wget; if not, write to the Free Software Foundation, Inc.,
+51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+In addition, as a special exception, the Free Software Foundation
+gives permission to link the code of its release of Wget with the
+OpenSSL project's "OpenSSL" library (or with modified versions of it
+that use the same license as the "OpenSSL" library), and distribute
+the linked executables.  You must obey the GNU General Public License
+in all respects for all of the code used other than "OpenSSL".  If you
+modify this file, you may extend this exception to your version of the
+file, but you are not obligated to do so.  If you do not wish to do
+so, delete this exception statement from your version.  */
+
+#include <config.h>
+
+#include <assert.h>
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <string.h>
+#include <stdio.h>
+
+#include <gnutls/gnutls.h>
+
+#include "wget.h"
+#include "utils.h"
+#include "connect.h"
+#include "url.h"
+#include "ssl.h"
+
+/* Note: some of the functions private to this file have names that
+   begin with "wgnutls_" (e.g. wgnutls_read) so that they wouldn't be
+   confused with actual gnutls functions -- such as the gnutls_read
+   preprocessor macro.  */
+
+static gnutls_certificate_credentials credentials;
+
+bool
+ssl_init ()
+{
+  gnutls_global_init ();
+  gnutls_certificate_allocate_credentials (&credentials);
+  if (opt.ca_cert)
+    gnutls_certificate_set_x509_trust_file (credentials, opt.ca_cert,
+                                           GNUTLS_X509_FMT_PEM);
+  return true;
+}
+
+struct wgnutls_transport_context {
+  gnutls_session session;      /* GnuTLS session handle */
+  int last_error;              /* last error returned by read/write/... */
+
+  /* Since GnuTLS doesn't support the equivalent to recv(...,
+     MSG_PEEK) or SSL_peek(), we have to do it ourselves.  Peeked data
+     is stored to PEEKBUF, and wgnutls_read checks that buffer before
+     actually reading.  */
+  char peekbuf[512];
+  int peekstart, peeklen;
+};
+
+#ifndef MIN
+# define MIN(i, j) ((i) <= (j) ? (i) : (j))
+#endif
+
+static int
+wgnutls_read (int fd, char *buf, int bufsize, void *arg)
+{
+  int ret;
+  struct wgnutls_transport_context *ctx = arg;
+
+  if (ctx->peeklen)
+    {
+      /* If we have any peek data, simply return that. */
+      int copysize = MIN (bufsize, ctx->peeklen);
+      memcpy (buf, ctx->peekbuf + ctx->peekstart, copysize);
+      ctx->peeklen -= copysize;
+      if (ctx->peeklen != 0)
+       ctx->peekstart += copysize;
+      else
+       ctx->peekstart = 0;
+      return copysize;
+    }
+
+  do
+    ret = gnutls_record_recv (ctx->session, buf, bufsize);
+  while (ret == GNUTLS_E_INTERRUPTED);
+
+  if (ret < 0)
+    ctx->last_error = ret;
+  return ret;
+}
+
+static int
+wgnutls_write (int fd, char *buf, int bufsize, void *arg)
+{
+  int ret;
+  struct wgnutls_transport_context *ctx = arg;
+  do
+    ret = gnutls_record_send (ctx->session, buf, bufsize);
+  while (ret == GNUTLS_E_INTERRUPTED);
+  if (ret < 0)
+    ctx->last_error = ret;
+  return ret;
+}
+
+static int
+wgnutls_poll (int fd, double timeout, int wait_for, void *arg)
+{
+  return 1;
+}
+
+static int
+wgnutls_peek (int fd, char *buf, int bufsize, void *arg)
+{
+  int ret;
+  struct wgnutls_transport_context *ctx = arg;
+
+  /* We don't support peeks following peeks: the reader must drain all
+     peeked data before the next peek.  */
+  assert (ctx->peeklen == 0);
+  if (bufsize > sizeof ctx->peekbuf)
+    bufsize = sizeof ctx->peekbuf;
+
+  do
+    ret = gnutls_record_recv (ctx->session, buf, bufsize);
+  while (ret == GNUTLS_E_INTERRUPTED);
+
+  if (ret >= 0)
+    {
+      memcpy (ctx->peekbuf, buf, ret);
+      ctx->peeklen = ret;
+    }
+  return ret;
+}
+
+static const char *
+wgnutls_errstr (int fd, void *arg)
+{
+  struct wgnutls_transport_context *ctx = arg;
+  return gnutls_strerror (ctx->last_error);
+}
+
+static void
+wgnutls_close (int fd, void *arg)
+{
+  struct wgnutls_transport_context *ctx = arg;
+  /*gnutls_bye (ctx->session, GNUTLS_SHUT_RDWR);*/
+  gnutls_deinit (ctx->session);
+  xfree (ctx);
+#ifndef WINDOWS
+  close (fd);
+#else
+  closesocket (fd);
+#endif
+}
+
+/* gnutls_transport is the singleton that describes the SSL transport
+   methods provided by this file.  */
+
+static struct transport_implementation wgnutls_transport = {
+  wgnutls_read, wgnutls_write, wgnutls_poll,
+  wgnutls_peek, wgnutls_errstr, wgnutls_close
+};
+
+bool
+ssl_connect (int fd) 
+{
+  static const int cert_type_priority[] = {
+    GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP, 0
+  };
+  struct wgnutls_transport_context *ctx;
+  gnutls_session session;
+  int err;
+  gnutls_init (&session, GNUTLS_CLIENT);
+  gnutls_set_default_priority (session);
+  gnutls_certificate_type_set_priority (session, cert_type_priority);
+  gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, credentials);
+  gnutls_transport_set_ptr (session, (gnutls_transport_ptr) fd);
+  err = gnutls_handshake (session);
+  if (err < 0)
+    {
+      logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
+      gnutls_deinit (session);
+      return false;
+    }
+  ctx = xnew0 (struct wgnutls_transport_context);
+  ctx->session = session;
+  fd_register_transport (fd, &wgnutls_transport, ctx);
+  return true;
+}
+
+bool
+ssl_check_certificate (int fd, const char *host)
+{
+  struct wgnutls_transport_context *ctx = fd_transport_context (fd);
+
+  unsigned int status;
+  const gnutls_datum *cert_list;
+  int cert_list_size, ret;
+  gnutls_x509_crt cert;
+
+  /* If the user has specified --no-check-cert, we still want to warn
+     him about problems with the server's certificate.  */
+  const char *severity = opt.check_cert ? _("ERROR") : _("WARNING");
+  bool success = true;
+
+  ret = gnutls_certificate_verify_peers2 (ctx->session, &status);
+  if (ret < 0)
+    {
+      logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
+                severity, escnonprint (host));
+      success = false;
+      goto no_cert;
+    }
+
+  if (status & GNUTLS_CERT_INVALID)
+    {
+      logprintf (LOG_NOTQUIET, _("%s: The certificate of `%s' is not trusted.\n"),
+                severity, escnonprint (host));
+      success = false;
+    }
+  if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
+    {
+      logprintf (LOG_NOTQUIET, _("%s: The certificate of `%s' hasn't got a known issuer.\n"),
+                severity, escnonprint (host));
+      success = false;
+    }
+  if (status & GNUTLS_CERT_REVOKED)
+    {
+      logprintf (LOG_NOTQUIET, _("%s: The certificate of `%s' has been revoked.\n"),
+                severity, escnonprint (host));
+      success = false;
+    }
+
+ no_cert:
+  return opt.check_cert ? success : true;
+}
index 7ab17b7c8c75b29871a1df9efdd10bdfddaa4169..8c76282c6345a4336a4c0308722717559dddc062 100644 (file)
@@ -40,6 +40,10 @@ so, delete this exception statement from your version.  */
 # define NDEBUG
 #endif
 
+#if defined HAVE_OPENSSL || defined HAVE_GNUTLS
+# define HAVE_SSL
+#endif
+
 /* `gettext (FOO)' is long to write, so we use `_(FOO)'.  If NLS is
    unavailable, _(STRING) simply returns STRING.  */
 #ifdef HAVE_NLS