]> 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.
 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 Checks for libraries.
 dnl
 
-dnl Check for OpenSSL
-if test x"$with_ssl" != x"no"
+if test x"$with_ssl" = xgnutls
 then
 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
   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
   ], [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
     SSL_OBJ='openssl.o'
   fi
 fi
+
 AC_SUBST(SSL_OBJ)
 
 dnl Enable NTLM if requested and if SSL is available.
 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
 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@ 
 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)
 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
 
 # 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
 /* `gettext (FOO)' is long to write, so we use `_(FOO)'.  If NLS is
    unavailable, _(STRING) simply returns STRING.  */
 #ifdef HAVE_NLS