unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Emacs core TLS support
@ 2010-01-13 21:53 Ted Zlatanov
  2010-01-13 23:46 ` Chong Yidong
  0 siblings, 1 reply; 93+ messages in thread
From: Ted Zlatanov @ 2010-01-13 21:53 UTC (permalink / raw)
  To: emacs-devel

Is there any chance Emacs can offer core support for TLS-encrypted
network connections?  I have no idea what's involved, I'm just checking
on the possibility.

Thanks
Ted





^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-01-13 21:53 Emacs core TLS support Ted Zlatanov
@ 2010-01-13 23:46 ` Chong Yidong
  2010-01-14 14:09   ` Ted Zlatanov
  0 siblings, 1 reply; 93+ messages in thread
From: Chong Yidong @ 2010-01-13 23:46 UTC (permalink / raw)
  To: Ted Zlatanov; +Cc: emacs-devel

Ted Zlatanov <tzz@lifelogs.com> writes:

> Is there any chance Emacs can offer core support for TLS-encrypted
> network connections?  I have no idea what's involved, I'm just checking
> on the possibility.

What's the advantage of offering core support over using gnutls-cli
(like starttls.el does)?




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
@ 2010-01-14  1:37 MON KEY
  0 siblings, 0 replies; 93+ messages in thread
From: MON KEY @ 2010-01-14  1:37 UTC (permalink / raw)
  To: emacs-devel

> What's the advantage of offering core support over using gnutls-cli
> (like starttls.el does)?

It is far more apt to work "out of the box " on on w32...

As it is now, assuming it can be configured correctly it remains an
unbelievable headache to debug.
It would prob. make auth-sources.el more robust to work with as well
(which, BTW isn't doing the `debug' thing very well itself on w32
either)

For example, try using auth-sources.el on w32 to retrieve the
credentials for a CIFS domain which uses underscores from a
.authinfo.gpg file stored in a non standard location e.g. not under
%home%. It works on a GNU system, but not alway without some
fiddling...

All of which is to say the entire Emacs authentication toolset gets
long in the tooth quite quickly when used in the aggregate. Moreover,
when they fail they fall over in opaque ways because of the security
concerns.

/s_P\




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-01-13 23:46 ` Chong Yidong
@ 2010-01-14 14:09   ` Ted Zlatanov
  2010-01-14 15:44     ` Stefan Monnier
  0 siblings, 1 reply; 93+ messages in thread
From: Ted Zlatanov @ 2010-01-14 14:09 UTC (permalink / raw)
  To: emacs-devel; +Cc: Simon Josefsson

On Wed, 13 Jan 2010 18:46:41 -0500 Chong Yidong <cyd@stupidchicken.com> wrote: 

CY> Ted Zlatanov <tzz@lifelogs.com> writes:
>> Is there any chance Emacs can offer core support for TLS-encrypted
>> network connections?  I have no idea what's involved, I'm just checking
>> on the possibility.

CY> What's the advantage of offering core support over using gnutls-cli
CY> (like starttls.el does)?
On Wed, 13 Jan 2010 20:37:42 -0500 MON KEY <monkey@sandpframing.com> wrote: 

MK> It is far more apt to work "out of the box " on on w32...

Portability is one consideration.  The parts of Gnus that touch W32
through starttls.el have been a sore point in terms of support, both
offered (too little) and requested (too much).  I don't have a list of
issues on hand but at least 5 have come up in the last year IIRC.

gnutls-cli and the alternative starttls binary are external binaries.
For encryption protocols like TLS it's both inefficient and insecure to
use external binaries to implement them.

In addition to portability, efficiency, and security, core support would
also be easier to configure if it requires no external binaries
installed.  New users would surely benefit from this.

Simon Josefsson already put a patch together at
http://josefsson.org/securemacs but it will probably need to be revised
a bit, the last change was in 2002.  It offers gnutls.el as an
alternative to starttls.el, with a similar API.  As long as this is
optional and autodetected through configure, I don't see a downside.  It
may need to be folded into starttls.el but that's not a big deal.  I'm
cc-ing Simon in case he has any comments.

Ted





^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-01-14 14:09   ` Ted Zlatanov
@ 2010-01-14 15:44     ` Stefan Monnier
  2010-01-14 16:38       ` Ted Zlatanov
  0 siblings, 1 reply; 93+ messages in thread
From: Stefan Monnier @ 2010-01-14 15:44 UTC (permalink / raw)
  To: Ted Zlatanov; +Cc: Simon Josefsson, emacs-devel

> Simon Josefsson already put a patch together at
> http://josefsson.org/securemacs but it will probably need to be revised
> a bit, the last change was in 2002.  It offers gnutls.el as an
> alternative to starttls.el, with a similar API.  As long as this is
> optional and autodetected through configure, I don't see a downside.  It
> may need to be folded into starttls.el but that's not a big deal.  I'm
> cc-ing Simon in case he has any comments.

I think I'd be OK with adding a --with-gnutls configure option that
links Emacs against that library.  Especially if we can provide
a compatibility footls.el library that works both --with-gnutls
and without.


        Stefan




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-01-14 15:44     ` Stefan Monnier
@ 2010-01-14 16:38       ` Ted Zlatanov
  2010-01-29 19:59         ` Ted Zlatanov
  0 siblings, 1 reply; 93+ messages in thread
From: Ted Zlatanov @ 2010-01-14 16:38 UTC (permalink / raw)
  To: emacs-devel

On Thu, 14 Jan 2010 10:44:13 -0500 Stefan Monnier <monnier@iro.umontreal.ca> wrote: 

>> Simon Josefsson already put a patch together at
>> http://josefsson.org/securemacs but it will probably need to be revised
>> a bit, the last change was in 2002.  It offers gnutls.el as an
>> alternative to starttls.el, with a similar API.  As long as this is
>> optional and autodetected through configure, I don't see a downside.  It
>> may need to be folded into starttls.el but that's not a big deal.  I'm
>> cc-ing Simon in case he has any comments.

SM> I think I'd be OK with adding a --with-gnutls configure option that
SM> links Emacs against that library.  Especially if we can provide
SM> a compatibility footls.el library that works both --with-gnutls
SM> and without.

Is anyone interested in reviewing Simon's patch?  I think it does
exactly what you suggest except the compatibility layer, which should be
trivial since Simon kept the invocation semantics the same between
gnutls.el and starttls.el.

Ted





^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-01-14 16:38       ` Ted Zlatanov
@ 2010-01-29 19:59         ` Ted Zlatanov
  2010-08-12 23:00           ` Ted Zlatanov
  0 siblings, 1 reply; 93+ messages in thread
From: Ted Zlatanov @ 2010-01-29 19:59 UTC (permalink / raw)
  To: emacs-devel

On Thu, 14 Jan 2010 10:38:44 -0600 Ted Zlatanov <tzz@lifelogs.com> wrote: 

TZ> On Thu, 14 Jan 2010 10:44:13 -0500 Stefan Monnier <monnier@iro.umontreal.ca> wrote: 
>>> Simon Josefsson already put a patch together at
>>> http://josefsson.org/securemacs but it will probably need to be revised
>>> a bit, the last change was in 2002.  It offers gnutls.el as an
>>> alternative to starttls.el, with a similar API.  As long as this is
>>> optional and autodetected through configure, I don't see a downside.  It
>>> may need to be folded into starttls.el but that's not a big deal.  I'm
>>> cc-ing Simon in case he has any comments.

SM> I think I'd be OK with adding a --with-gnutls configure option that
SM> links Emacs against that library.  Especially if we can provide
SM> a compatibility footls.el library that works both --with-gnutls
SM> and without.

TZ> Is anyone interested in reviewing Simon's patch?  I think it does
TZ> exactly what you suggest except the compatibility layer, which should be
TZ> trivial since Simon kept the invocation semantics the same between
TZ> gnutls.el and starttls.el.

ping...  I hope someone better acquainted with the internals than me can
take a look.

Thanks!
Ted





^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-01-29 19:59         ` Ted Zlatanov
@ 2010-08-12 23:00           ` Ted Zlatanov
  2010-08-13 11:04             ` James Cloos
  2010-08-13 13:54             ` Leo
  0 siblings, 2 replies; 93+ messages in thread
From: Ted Zlatanov @ 2010-08-12 23:00 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 2083 bytes --]

On Fri, 29 Jan 2010 13:59:27 -0600 Ted Zlatanov <tzz@lifelogs.com> wrote: 

TZ> On Thu, 14 Jan 2010 10:38:44 -0600 Ted Zlatanov <tzz@lifelogs.com> wrote: 
TZ> On Thu, 14 Jan 2010 10:44:13 -0500 Stefan Monnier <monnier@iro.umontreal.ca> wrote: 
>>>> Simon Josefsson already put a patch together at
>>>> http://josefsson.org/securemacs but it will probably need to be revised
>>>> a bit, the last change was in 2002.  It offers gnutls.el as an
>>>> alternative to starttls.el, with a similar API.  As long as this is
>>>> optional and autodetected through configure, I don't see a downside.  It
>>>> may need to be folded into starttls.el but that's not a big deal.  I'm
>>>> cc-ing Simon in case he has any comments.

SM> I think I'd be OK with adding a --with-gnutls configure option that
SM> links Emacs against that library.  Especially if we can provide
SM> a compatibility footls.el library that works both --with-gnutls
SM> and without.

TZ> Is anyone interested in reviewing Simon's patch?  I think it does
TZ> exactly what you suggest except the compatibility layer, which should be
TZ> trivial since Simon kept the invocation semantics the same between
TZ> gnutls.el and starttls.el.

I posted a revised version of the patch on the gnutls-devel mailing
list and asked for help there:
http://thread.gmane.org/gmane.comp.encryption.gpg.gnutls.devel/4430

(note there's a minor revision of the patch posted today at
http://thread.gmane.org/gmane.comp.encryption.gpg.gnutls.devel/4442)

Simon Josefsson is active on that list but doesn't seem interested in
further supporting that patch.  So it's up to the Emacs developers to
take this on.

The patch is far from done but at least all the wrapper code is written
and it has no issues AFAIK.  All that remains is for someone with good C
knowledge to look through process.c and process.h and adjust the API
calls appropriately.  Unfortunately I haven't done C in a long time and
don't know the Emacs internals well, so it's really inefficient for me
to dig through it.

I'm attaching the latest patch here for completeness.

Ted


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: tls.patch --]
[-- Type: text/x-diff, Size: 24375 bytes --]

=== modified file 'configure.in'
--- configure.in	2010-08-10 14:22:29 +0000
+++ configure.in	2010-08-12 22:48:32 +0000
@@ -169,6 +169,7 @@
 OPTION_DEFAULT_ON([dbus],[don't compile with D-Bus support])
 OPTION_DEFAULT_ON([gconf],[don't compile with GConf support])
 OPTION_DEFAULT_ON([selinux],[don't compile with SELinux support])
+OPTION_DEFAULT_ON([gnutls],[don't use -lgnutls for SSL/TLS support])
 
 ## For the times when you want to build Emacs but don't have
 ## a suitable makeinfo, and can live without the manuals.
@@ -1983,6 +1984,13 @@
 fi
 AC_SUBST(LIBSELINUX_LIBS)
 
+HAVE_GNUTLS=no
+if test "${with_gnutls}" = "yes" ; then
+  PKG_CHECK_MODULES([LIBGNUTLS], [gnutls >= 2.2.4])
+  AC_DEFINE(HAVE_GNUTLS)
+  HAVE_GNUTLS=yes
+fi
+
 dnl Do not put whitespace before the #include statements below.
 dnl Older compilers (eg sunos4 cc) choke on it.
 HAVE_XAW3D=no
@@ -3666,6 +3674,7 @@
 echo "  Does Emacs use -ldbus?                                  ${HAVE_DBUS}"
 echo "  Does Emacs use -lgconf?                                 ${HAVE_GCONF}"
 echo "  Does Emacs use -lselinux?                               ${HAVE_LIBSELINUX}"
+echo "  Does Emacs use Gnu TLS?                                 ${HAVE_GNUTLS}"
 
 echo "  Does Emacs use -lfreetype?                              ${HAVE_FREETYPE}"
 echo "  Does Emacs use -lm17n-flt?                              ${HAVE_M17N_FLT}"

=== modified file 'src/Makefile.in'
--- src/Makefile.in	2010-07-12 14:16:38 +0000
+++ src/Makefile.in	2010-08-12 22:47:22 +0000
@@ -280,6 +280,9 @@
 
 LIBSELINUX_LIBS = @LIBSELINUX_LIBS@
 
+LIBGNUTLS_LIBS = @LIBGNUTLS_LIBS@
+LIBGNUTLS_CFLAGS = @LIBGNUTLS_CFLAGS@
+
 INTERVALS_H = dispextern.h intervals.h composite.h
 
 GETLOADAVG_LIBS = @GETLOADAVG_LIBS@
@@ -318,6 +321,7 @@
   ${C_SWITCH_X_SYSTEM} ${CFLAGS_SOUND} ${RSVG_CFLAGS} ${DBUS_CFLAGS} \
   ${GCONF_CFLAGS} ${FREETYPE_CFLAGS} ${FONTCONFIG_CFLAGS} \
   ${LIBOTF_CFLAGS} ${M17N_FLT_CFLAGS} ${DEPFLAGS} ${PROFILING_CFLAGS} \
+  $(LIBGNUTLS_CFLAGS) \
   ${C_WARNINGS_SWITCH} ${CFLAGS}
 ALL_OBJC_CFLAGS=$(ALL_CFLAGS) $(GNU_OBJC_CFLAGS)
 
@@ -593,6 +597,7 @@
    $(RSVG_LIBS) $(DBUS_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \
    $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) ${GCONF_LIBS} ${LIBSELINUX_LIBS} \
    $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
+   $(LIBGNUTLS_LIBS) \
    $(LIB_GCC) $(LIB_MATH) $(LIB_STANDARD) $(LIB_GCC)
 
 all: emacs${EXEEXT} $(OTHER_FILES)

=== modified file 'src/config.in'
--- src/config.in	2010-08-09 19:25:41 +0000
+++ src/config.in	2010-08-12 22:24:33 +0000
@@ -255,6 +255,9 @@
 /* Define to 1 if you have a gif (or ungif) library. */
 #undef HAVE_GIF
 
+/* Define if we have the GNU TLS library.  */
+#undef HAVE_GNUTLS
+
 /* Define to 1 if you have the gpm library (-lgpm). */
 #undef HAVE_GPM
 
@@ -1085,6 +1088,12 @@
 #include config_opsysfile
 #include config_machfile
 
+#if HAVE_GNUTLS
+#define LIBGNUTLS $(LIBGNUTLS_LIBS)
+#else /* not HAVE_GNUTLS */
+#define LIBGNUTLS
+#endif /* not HAVE_GNUTLS */
+
 /* Set up some defines, C and LD flags for NeXTstep interface on GNUstep.
   (There is probably a better place to do this, but right now the Cocoa
    side does this in s/darwin.h and we cannot

=== modified file 'src/process.c'
--- src/process.c	2010-08-09 09:35:21 +0000
+++ src/process.c	2010-08-12 22:41:55 +0000
@@ -111,6 +111,10 @@
 #include "syssignal.h"
 #include "syswait.h"
 
+#ifdef HAVE_GNUTLS
+#include <gnutls/gnutls.h>
+#endif
+
 #if defined (USE_GTK) || defined (HAVE_GCONF)
 #include "xgselect.h"
 #endif /* defined (USE_GTK) || defined (HAVE_GCONF) */
@@ -1538,6 +1542,10 @@
   XPROCESS (proc)->filter = Qnil;
   XPROCESS (proc)->command = Flist (nargs - 2, args + 2);
 
+#ifdef HAVE_GNUTLS
+  XPROCESS (proc)->gnutls_state = Qnil;
+#endif
+
 #ifdef ADAPTIVE_READ_BUFFERING
   XPROCESS (proc)->adaptive_read_buffering
     = (NILP (Vprocess_adaptive_read_buffering) ? 0
@@ -5069,6 +5077,65 @@
   return Qt;
 }
 
+#ifdef HAVE_GNUTLS
+
+int
+emacs_gnutls_write (fildes, state, buf, nbyte)
+     int fildes;
+     gnutls_session_t state;
+     char *buf;
+     unsigned int nbyte;
+{
+  register int rtnval, bytes_written;
+
+  puts("emacs_gnutls_write");
+
+  bytes_written = 0;
+
+  while (nbyte > 0)
+    {
+      rtnval = gnutls_write (state, buf, nbyte);
+
+      if (rtnval == -1)
+	{
+	  if (errno == EINTR)
+	    continue;
+	  else
+	    return (bytes_written ? bytes_written : -1);
+	}
+
+      buf += rtnval;
+      nbyte -= rtnval;
+      bytes_written += rtnval;
+    }
+  printf("wrote %d bytes\n", bytes_written);
+  fsync(STDOUT_FILENO);
+
+  return (bytes_written);
+}
+
+int
+emacs_gnutls_read (fildes, state, buf, nbyte)
+     int fildes; 
+     gnutls_session_t state;
+     char *buf;
+     unsigned int nbyte;
+{
+  register int rtnval;
+
+  puts("emacs_gnutls_read");
+
+  do {
+    rtnval = gnutls_read( state, buf, nbyte);
+    printf("read %d bytes\n", rtnval);
+  } while( rtnval==GNUTLS_E_INTERRUPTED || rtnval==GNUTLS_E_AGAIN);
+  printf("read %d bytes\n", rtnval);
+  fsync(STDOUT_FILENO);
+
+  return (rtnval);
+}
+#endif
+
 /* Read pending output from the process channel,
    starting with our buffered-ahead character if we have one.
    Yield number of decoded characters read.
@@ -5111,7 +5178,12 @@
 #endif
   if (proc_buffered_char[channel] < 0)
     {
-      nbytes = emacs_read (channel, chars + carryover, readmax);
+#ifdef HAVE_GNUTLS
+      if (NETCONN_P(proc) && !NILP (XPROCESS(proc)->gnutls_state))
+	nbytes = emacs_gnutls_read (channel, XPROCESS(proc)->gnutls_state, chars + carryover, readmax);
+      else
+#endif
+	nbytes = emacs_read (channel, chars + carryover, readmax);
 #ifdef ADAPTIVE_READ_BUFFERING
       if (nbytes > 0 && p->adaptive_read_buffering)
 	{
@@ -5144,7 +5216,12 @@
     {
       chars[carryover] = proc_buffered_char[channel];
       proc_buffered_char[channel] = -1;
-      nbytes = emacs_read (channel, chars + carryover + 1,  readmax - 1);
+#ifdef HAVE_GNUTLS
+      if (NETCONN_P(proc) && !NILP (XPROCESS(proc)->gnutls_state))
+	nbytes = emacs_gnutls_read (channel, XPROCESS(proc)->gnutls_state, chars + carryover + 1, readmax - 1);
+      else
+#endif
+	nbytes = emacs_read (channel, chars + carryover + 1,  readmax - 1);
       if (nbytes < 0)
 	nbytes = 1;
       else
@@ -5554,7 +5631,14 @@
 	      else
 #endif
 		{
-		  rv = emacs_write (outfd, (char *) buf, this);
+#ifdef HAVE_GNUTLS
+		  if (NETCONN_P(proc) && !NILP (XPROCESS(proc)->gnutls_state))
+		    rv = emacs_gnutls_write (outfd,
+					     XPROCESS(proc)->gnutls_state, 
+					     (char *) buf, this);
+		  else
+#endif
+		    rv = emacs_write (outfd, (char *) buf, this);
 #ifdef ADAPTIVE_READ_BUFFERING
 		  if (p->read_output_delay > 0
 		      && p->adaptive_read_buffering == 1)
@@ -6788,6 +6872,523 @@
 
 \f
 
+#ifdef HAVE_GNUTLS
+
+int gnutls_callback (state, client_certs, ncerts, req_ca_cert, nreqs)
+     gnutls_session_t state;
+     const gnutls_datum *client_certs;
+     int ncerts;
+     const gnutls_datum* req_ca_cert;
+     int nreqs;
+{
+  if (client_certs == NULL) {
+    /* means the we will only be called again if the library cannot
+     * determine which certificate to send
+     */
+    return 0;
+  }
+
+  puts("In callback");
+
+  return -1; /* send no certificate to the peer */
+}
+
+DEFUN ("gnutls-init", Fgnutls_init, Sgnutls_init, 2, 2, 0,
+       doc: /* Initializes GNU TLS for process PROC for use as CONNECTION-END.
+CONNECTION-END is used to indicate if this process is as a server or
+client. Can be one of `gnutls-client' and `gnutls-server'.  Currently
+only `gnutls-client' is supported.
+
+Processes must be initialized with this function before other GNU TLS
+functions are used.  This function allocates resources which can only
+be deallocated by calling `gnutls-deinit'. Returns zero on success. */)
+     (proc, connection_end)
+     Lisp_Object proc, connection_end;
+{
+  int ret;
+  
+  CHECK_PROCESS (proc);
+
+  ret = gnutls_init((gnutls_session_t*)&(XPROCESS(proc)->gnutls_state), 
+		    connection_end);
+
+  return XINT(ret);
+}
+
+DEFUN ("gnutls-deinit", Fgnutls_deinit, Sgnutls_deinit, 1, 1, 0,
+       doc: /* Deallocate GNU TLS resources associated with PROCESS.
+See also `gnutls-init'. */)
+     (proc)
+     Lisp_Object proc;
+{
+  int ret;
+  gnutls_session_t state;
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  gnutls_deinit(state);
+
+  return Qnil;
+}
+
+DEFUN ("gnutls-global-init", Fgnutls_global_init, 
+       Sgnutls_global_init, 0, 0, 0,
+       doc: /* Initializes global GNU TLS state to defaults.
+Call `gnutls-global-deinit' when GNU TLS usage is no longer needed.
+Returns zero on success. */)
+     ()
+{
+  Lisp_Object lret;
+  int ret;
+
+  ret = gnutls_global_init();
+  XSETINT (lret, ret);
+
+  return lret;
+}
+
+DEFUN ("gnutls-global-deinit", Fgnutls_global_deinit, 
+       Sgnutls_global_deinit, 0, 0, 0,
+       doc: /* Deinitializes global GNU TLS state.
+See also `gnutls-global-init'. */)
+     ()
+{
+  gnutls_global_deinit();
+
+  return Qnil;
+}
+
+Lisp_Object
+generic_set_priority (func, nargs, args)
+     int (*func)( gnutls_session_t state, const int*);
+     int nargs;
+     Lisp_Object *args;
+{
+  Lisp_Object proc;
+  Lisp_Object lret;
+  gnutls_session_t state;
+  int *algs;
+  size_t len;
+  int ret;
+  int i;
+  
+  proc = args[0];
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  for (i = 1; i < nargs; i++)
+      CHECK_NUMBER (args[i]);
+
+  len = nargs * sizeof(int);
+  algs = xmalloc (len);
+  for (i = 1; i < nargs; i++)
+      algs[i-1] = XFASTINT(args[i]);
+  algs[i-1] = 0;
+  ret = (*func) (state, algs);
+  xfree(algs);
+
+  XSETINT (lret, ret);
+  return lret;
+}
+
+DEFUN ("gnutls-protocol-set-priority", Fgnutls_protocol_set_priority, 
+       Sgnutls_protocol_set_priority, 1, MANY, 0,
+       doc: /* Sets the priority on the protocol versions supported by GNU TLS for PROCESS.
+The first parameter must be a process.	Subsequent parameters should
+be integers.  Priority is higher for protocols specified before
+others.	 Note that the priority is set on the client.  The server does
+not use the protocols's priority except for disabling protocols that
+were not specified. */)
+     (nargs, args)
+     int nargs;
+     Lisp_Object *args;
+{
+  Lisp_Object ret;
+
+  ret = generic_set_priority (&gnutls_protocol_set_priority, nargs, args);
+  
+  return ret;
+}
+
+DEFUN ("gnutls-cipher-set-priority", Fgnutls_cipher_set_priority, 
+       Sgnutls_cipher_set_priority, 1, MANY, 0,
+       doc: /* Sets the priority on the bulk ciphers supported by GNU TLS for PROCESS.
+The first parameter must be a process.	Subsequent parameters should
+be integers.  Priority is higher for protocols specified before
+others.	 Note that the priority is set on the client.  The server does
+not use the protocols's priority except for disabling protocols that
+were not specified. */)
+     (nargs, args)
+     int nargs;
+     Lisp_Object *args;
+{
+  Lisp_Object ret;
+
+  ret = generic_set_priority (&gnutls_cipher_set_priority, nargs, args);
+  
+  return ret;
+}
+
+DEFUN ("gnutls-compression-set-priority", Fgnutls_compression_set_priority, 
+       Sgnutls_compression_set_priority, 1, MANY, 0,
+       doc: /* Sets the priority on compression algorithms supported by GNU TLS for PROCESS.
+The first parameter must be a process.	Subsequent parameters should
+be integers.  Priority is higher for protocols specified before
+others.	 Note that the priority is set on the client.  The server does
+not use the protocols's priority except for disabling protocols that
+were not specified. */)
+     (nargs, args)
+     int nargs;
+     Lisp_Object *args;
+{
+  Lisp_Object ret;
+
+  ret = generic_set_priority (&gnutls_compression_set_priority, nargs, args);
+  
+  return ret;
+}
+
+DEFUN ("gnutls-kx-set-priority", Fgnutls_kx_set_priority, 
+       Sgnutls_kx_set_priority, 1, MANY, 0,
+       doc: /* Sets the priority on key exchange algorithms supported by GNU TLS for PROCESS.
+The first parameter must be a process.	Subsequent parameters should
+be integers.  Priority is higher for protocols specified before
+others.	 Note that the priority is set on the client.  The server does
+not use the protocols's priority except for disabling protocols that
+were not specified. */)
+     (nargs, args)
+     int nargs;
+     Lisp_Object *args;
+{
+  Lisp_Object ret;
+
+  ret = generic_set_priority (&gnutls_kx_set_priority, nargs, args);
+
+  return ret;
+}
+
+DEFUN ("gnutls-mac-set-priority", Fgnutls_mac_set_priority, 
+       Sgnutls_mac_set_priority, 1, MANY, 0,
+       doc: /* Sets the priority on MAC algorithms supported by GNU TLS for PROCESS.
+The first parameter must be a process.	Subsequent parameters should
+be integers.  Priority is higher for protocols specified before
+others.	 Note that the priority is set on the client.  The server does
+not use the protocols's priority except for disabling protocols that
+were not specified. */)
+     (nargs, args)
+     int nargs;
+     Lisp_Object *args;
+{
+  Lisp_Object ret;
+
+  ret = generic_set_priority (&gnutls_mac_set_priority, nargs, args);
+  
+  return ret;
+}
+
+/* BROKEN: can't figure out how to use this */
+// DEFUN ("gnutls-x509pki-set-client-cert-callback", 
+//	  Fgnutls_x509pki_set_client_cert_callback, 
+//	  Sgnutls_x509pki_set_client_cert_callback, 2, 2, 0,
+//	  doc: /* XXX Not completely implemented yet. */)
+//	(proc, callback)
+//	Lisp_Object proc, callback;
+// {
+//   gnutls_certificate_credentials_t x509_cred;
+//   Lisp_Object lret;
+//   int ret;
+
+//   CHECK_PROCESS (proc);
+//   x509_cred = (gnutls_certificate_credentials_t) XPROCESS(proc)->x509_cred;
+
+//   XPROCESS(proc)->x509_callback = callback;
+//   gnutls_x509pki_set_client_cert_callback (x509_cred, &gnutls_callback);
+
+//   return Qnil;
+// }
+
+DEFUN ("gnutls-x509pki-set-client-key-file", 
+       Fgnutls_x509pki_set_client_key_file,
+       Sgnutls_x509pki_set_client_key_file, 3, 3, 0,
+       doc: /* Set X.509 client credentials for PROCESS
+CERTFILE is a PEM encoded file containing the certificate list (path)
+for the specified private key. KEYFILE is a PEM encoded file
+containing a private key.  Returns zero on success.
+
+This function may be called more than once (in case multiple
+keys/certificates exist for the server).
+
+Currently only PKCS-1 PEM encoded RSA private keys are accepted by
+this function. */)
+     (proc, certfile, keyfile)
+     Lisp_Object proc;
+     Lisp_Object certfile;
+     Lisp_Object keyfile;
+{
+  gnutls_session_t state;
+  gnutls_certificate_credentials_t x509_cred;
+  Lisp_Object lret;
+  int ret;
+
+  CHECK_STRING(certfile);
+  CHECK_STRING(keyfile);
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  x509_cred = (gnutls_certificate_credentials_t) XPROCESS(proc)->x509_cred;
+
+  ret = gnutls_x509pki_set_client_key_file (x509_cred, 
+					    XSTRING (certfile)->data, 
+					    XSTRING (keyfile)->data);
+
+  XSETINT (lret, ret);
+  return lret;
+}
+
+DEFUN ("gnutls-x509pki-set-client-trust-file", 
+       Fgnutls_x509pki_set_client_trust_file,
+       Sgnutls_x509pki_set_client_trust_file, 3, 3, 0,
+       doc: /* Set X.509 trusted credentials for PROCESS
+CAFILE is a PEM encoded file containing trusted CAs. CRLFILE is a PEM
+encoded file containing CRLs (ignored for now). Returns zero on
+success. */)
+     (proc, cafile, crlfile)
+     Lisp_Object proc;
+     Lisp_Object cafile;
+     Lisp_Object crlfile;
+{
+  gnutls_session_t state;
+  gnutls_certificate_credentials_t x509_cred;
+  Lisp_Object lret;
+  int ret;
+
+  CHECK_STRING(cafile);
+  CHECK_STRING(crlfile);
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  x509_cred = (gnutls_certificate_credentials_t) XPROCESS(proc)->x509_cred;
+
+  ret = gnutls_x509pki_set_client_trust_file (x509_cred, 
+					    NILP (cafile) ? NULL : 
+					    XSTRING (cafile)->data,
+					    NILP (crlfile) ? NULL : 
+					    XSTRING (crlfile)->data);
+
+  XSETINT (lret, ret);
+  return lret;
+}
+
+DEFUN ("gnutls-srp-set-client-cred", Fgnutls_srp_set_client_cred,
+       Sgnutls_srp_set_client_cred, 3, 3, 0,
+       doc: /* Set SRP username and password for PROCESS.  
+PROCESS must be a process. USERNAME is the user's userid. PASSWORD is
+the user's password. Returns zero on success. */)
+     (proc, username, password)
+     Lisp_Object proc;
+     Lisp_Object username;
+     Lisp_Object password;
+{
+  gnutls_session_t state;
+  gnutls_srp_client_credentials_t srp_cred;
+  Lisp_Object lret;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  srp_cred = (gnutls_srp_client_credentials_t) XPROCESS(proc)->srp_cred;
+
+  ret = gnutls_srp_set_client_credentials (srp_cred,
+					   NILP (username) ? NULL :
+					   XSTRING(username)->data, 
+					   NILP (password) ? NULL :
+					   XSTRING(password)->data);
+
+  XSETINT (lret, ret);
+  return lret;
+}
+
+DEFUN ("gnutls-anon-set-client-cred", Fgnutls_anon_set_client_cred,
+       Sgnutls_anon_set_client_cred, 2, 2, 0,
+       doc: /* Set the number of bits to use in anonymous Diffie-Hellman exchange for PROCESS.
+DH_BITS is the number of bits in DH key exchange. Returns zero on 
+success. */)
+     (proc, dh_bits)
+     Lisp_Object proc;
+     Lisp_Object dh_bits;
+{
+  gnutls_session_t state;
+  gnutls_anon_client_credentials_t anon_cred;
+  Lisp_Object lret;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  anon_cred = (gnutls_anon_client_credentials_t) XPROCESS(proc)->anon_cred;
+
+  ret = gnutls_anon_set_client_dh_params (anon_cred, XINT(dh_bits));
+
+  XSETINT (lret, ret);
+  return lret;
+}
+
+DEFUN ("gnutls-cred-set", Fgnutls_cred_set, 
+       Sgnutls_cred_set, 2, 2, 0,
+       doc: /* Enables GNU TLS authentication for PROCESS.
+TYPE is an integer indicating the type of the credentials, either
+`gnutls-anon', `gnutls-srp' or `gnutls-x509pki'.
+
+Each authentication type may need additional information in order to
+work.  For anonymous (`gnutls-anon'), see also
+`gnutls-anon-set-client-cred'.	For SRP (`gnutls-srp'), see also
+`gnutls-srp-set-client-cred'.  For X.509 PKI (`gnutls-x509pki'), see
+also `gnutls-x509pki-set-client-trust-file',
+`gnutls-x509pki-set-client-key-file', and
+`gnutls-x509pki-set-cert-callback'. */)
+     (proc, type)
+     Lisp_Object proc, type;
+{
+  gnutls_session_t state;
+  gnutls_certificate_credentials_t x509_cred;
+  gnutls_anon_client_credentials_t anon_cred;
+  gnutls_srp_client_credentials_t srp_cred;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  x509_cred = (gnutls_certificate_client_credentials) XPROCESS(proc)->x509_cred;
+  anon_cred = (gnutls_anon_client_credentials_t) XPROCESS(proc)->anon_cred;
+  srp_cred = (gnutls_srp_client_credentials_t) XPROCESS(proc)->srp_cred;
+
+  switch (XINT (type))
+    {
+    case GNUTLS_CRD_CERTIFICATE: 
+      if (gnutls_crd_allocate_client_credentials (&x509_cred, 1) < 0)
+	memory_full ();
+      ret = gnutls_cred_set (state, GNUTLS_CRD_CERTIFICATE, x509_cred);
+      break;
+
+    case GNUTLS_CRD_ANON:
+      if (gnutls_anon_allocate_client_credentials (&anon_cred) < 0)
+	memory_full ();
+      ret = gnutls_cred_set (state, GNUTLS_CRD_ANON, anon_cred);
+      break;
+
+    case GNUTLS_CRD_SRP:
+      if (gnutls_srp_allocate_client_credentials (&srp_cred) < 0)
+	memory_full ();
+      ret = gnutls_cred_set (state, GNUTLS_CRD_SRP, srp_cred);
+      break;
+    }
+
+  return XINT(ret);
+}
+
+DEFUN ("gnutls-bye", Fgnutls_bye, 
+       Sgnutls_bye, 2, 2, 0,
+       doc: /* Terminate current GNU TLS connection for PROCESS.
+The connection should have been initiated using gnutls_handshake().
+HOW should be one of `gnutls-shut-rdwr', `gnutls-shut-wr'.
+
+In case of `gnutls-shut-rdwr' then the TLS connection gets terminated
+and further receives and sends will be disallowed. If the return value
+is zero you may continue using the connection.	`gnutls-shut-rdwr'
+actually sends an alert containing a close request and waits for the
+peer to reply with the same message.
+  
+In case of `gnutls-shut-wr' then the TLS connection gets terminated
+and further sends will be disallowed. In order to reuse the connection
+you should wait for an EOF from the peer.  `gnutls-shut-wr' sends an
+alert containing a close request.
+  
+This function may also return `gnutls-e-again', or
+`gnutls-e-interrupted'. */)
+     (proc, how)
+     Lisp_Object proc, how;
+{
+  gnutls_session_t state;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  CHECK_NUMBER (how);
+
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  ret = gnutls_bye(state, XFASTINT(how));
+  
+  return XINT(ret);
+}
+
+DEFUN ("gnutls-handshake", Fgnutls_handshake, 
+       Sgnutls_handshake, 1, 1, 0,
+       doc: /* Perform GNU TLS handshake for PROCESS.
+The identity of the peer is checked automatically.  This function will
+fail if any problem is encountered, and will return a negative error
+code. In case of a client, if it has been asked to resume a session,
+but the server didn't, then a full handshake will be performed.
+  
+This function may also return the non-fatal errors `gnutls-e-again',
+or `gnutls-e-interrupted'. In that case you may resume the handshake
+(by calling this function again). */)
+     (proc)
+     Lisp_Object proc;
+{
+  gnutls_session_t state;
+  Lisp_Object lret;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  gnutls_transport_set_ptr( state, XPROCESS(proc)->infd);
+  ret = gnutls_handshake( state);
+  XSETINT(lret, ret);
+  
+  return lret;
+}
+
+DEFUN ("gnutls-rehandshake", Fgnutls_rehandshake, 
+       Sgnutls_rehandshake, 1, 1, 0,
+       doc: /* Renegotiate GNU TLS security parameters for PROCESS.
+This function will renegotiate security parameters with the
+client. This should only be called in case of a server.
+
+This message informs the peer that we want to renegotiate parameters
+\(perform a handshake).
+  
+If this function succeeds (returns 0), you must call the
+gnutls_handshake() function in order to negotiate the new parameters.
+  
+If the client does not wish to renegotiate parameters he will reply
+with an alert message, thus the return code will be
+`gnutls-e-warning-alert-received' and the alert will be
+`gnutls-e-no-renegotiation'. */)
+     (proc)
+     Lisp_Object proc;
+{
+  gnutls_session_t state;
+  Lisp_Object lret;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  gnutls_transport_set_ptr( state, XPROCESS(proc)->infd);
+  ret = gnutls_rehandshake( state);
+  XSETINT(lret, ret);
+  
+  return lret;
+}
+#endif
+
+\f
+
 static int add_gpm_wait_descriptor_called_flag;
 
 void
@@ -7708,6 +8309,25 @@
   defsubr (&Sprocess_coding_system);
   defsubr (&Sset_process_filter_multibyte);
   defsubr (&Sprocess_filter_multibyte_p);
+#ifdef HAVE_GNUTLS
+  defsubr (&Sgnutls_global_init);
+  defsubr (&Sgnutls_global_deinit);
+  defsubr (&Sgnutls_init);
+  defsubr (&Sgnutls_deinit);
+  defsubr (&Sgnutls_protocol_set_priority);
+  defsubr (&Sgnutls_cipher_set_priority);
+  defsubr (&Sgnutls_compression_set_priority);
+  defsubr (&Sgnutls_kx_set_priority);
+  defsubr (&Sgnutls_mac_set_priority);
+  defsubr (&Sgnutls_cred_set);
+  defsubr (&Sgnutls_handshake);
+  defsubr (&Sgnutls_rehandshake);
+  defsubr (&Sgnutls_x509pki_set_client_key_file);
+  defsubr (&Sgnutls_x509pki_set_client_trust_file);
+  defsubr (&Sgnutls_srp_set_client_cred);
+  defsubr (&Sgnutls_anon_set_client_cred);
+  defsubr (&Sgnutls_bye);
+#endif /* HAVE_GNUTLS */
 
 #endif	/* subprocesses */
 

=== modified file 'src/process.h'
--- src/process.h	2010-08-11 12:34:46 +0000
+++ src/process.h	2010-08-12 22:35:18 +0000
@@ -121,6 +121,14 @@
        needs to be synced to `status'.  */
     unsigned int raw_status_new : 1;
     int raw_status;
+
+#ifdef HAVE_GNUTLS
+    /* XXX Store GNU TLS state and auth mechanisms in Lisp_Objects. */
+    Lisp_Object gnutls_state;
+    Lisp_Object x509_cred, x509_callback;
+    Lisp_Object anon_cred;
+    Lisp_Object srp_cred;
+#endif
 };
 
 /* Every field in the preceding structure except for the first two


^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-08-12 23:00           ` Ted Zlatanov
@ 2010-08-13 11:04             ` James Cloos
  2010-08-13 15:07               ` Ted Zlatanov
  2010-08-13 13:54             ` Leo
  1 sibling, 1 reply; 93+ messages in thread
From: James Cloos @ 2010-08-13 11:04 UTC (permalink / raw)
  To: Ted Zlatanov; +Cc: emacs-devel

I'm just scanning though the patch for now, but the first think I notice
is that it needs to be updated from k&r to ansi.  An example:

+int
+emacs_gnutls_write (fildes, state, buf, nbyte)
+     int fildes;
+     gnutls_session_t state;
+     char *buf;
+     unsigned int nbyte;
+{
+  register int rtnval, bytes_written;

should be changed to:

+int
+emacs_gnutls_write (int fildes, gnutls_session_t state, char *buf, unsigned int nbyte)
+{
+  register int rtnval, bytes_written;

As so for the rest of the new C functions.

(Having written that, I don't remember whether the 23 branch was also
updated from k&r; so the above may only apply if it is meant just for
trunk.)

-JimC
-- 
James Cloos <cloos@jhcloos.com>         OpenPGP: 1024D/ED7DAEA6



^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-08-12 23:00           ` Ted Zlatanov
  2010-08-13 11:04             ` James Cloos
@ 2010-08-13 13:54             ` Leo
  2010-08-13 14:50               ` Ted Zlatanov
  1 sibling, 1 reply; 93+ messages in thread
From: Leo @ 2010-08-13 13:54 UTC (permalink / raw)
  To: emacs-devel

On 2010-08-13 00:00 +0100, Ted Zlatanov wrote:
> I posted a revised version of the patch on the gnutls-devel mailing
> list and asked for help there:
> http://thread.gmane.org/gmane.comp.encryption.gpg.gnutls.devel/4430
>
> (note there's a minor revision of the patch posted today at
> http://thread.gmane.org/gmane.comp.encryption.gpg.gnutls.devel/4442)
>
> Simon Josefsson is active on that list but doesn't seem interested in
> further supporting that patch.  So it's up to the Emacs developers to
> take this on.
>
> The patch is far from done but at least all the wrapper code is written
> and it has no issues AFAIK.  All that remains is for someone with good C
> knowledge to look through process.c and process.h and adjust the API
> calls appropriately.  Unfortunately I haven't done C in a long time and
> don't know the Emacs internals well, so it's really inefficient for me
> to dig through it.
>
> I'm attaching the latest patch here for completeness.

As a user, I think such feature would be very nice to have.

BTW, I remembered seeing rms OK the ffi feature. I wonder if there's a
plan for this. It would open up a new world of applications for emacs.
For example, at the moment emacs lacks a (good) English grammar checker.

> Ted

Leo




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-08-13 13:54             ` Leo
@ 2010-08-13 14:50               ` Ted Zlatanov
  2010-08-14 19:20                 ` Leo
  0 siblings, 1 reply; 93+ messages in thread
From: Ted Zlatanov @ 2010-08-13 14:50 UTC (permalink / raw)
  To: emacs-devel

On Fri, 13 Aug 2010 14:54:37 +0100 Leo <sdl.web@gmail.com> wrote: 

L> As a user, I think such feature would be very nice to have.

Yeah, easily 30% of Gnus issues are SSL-related, especially on W32
systems.

L> BTW, I remembered seeing rms OK the ffi feature. I wonder if there's a
L> plan for this. It would open up a new world of applications for emacs.
L> For example, at the moment emacs lacks a (good) English grammar checker.

I would not want SSL support to be pluggable :)  But yes, I think
generally it will make Emacs much better to have binary extensions.

Ted




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-08-13 11:04             ` James Cloos
@ 2010-08-13 15:07               ` Ted Zlatanov
  2010-08-13 15:51                 ` Julien Danjou
                                   ` (2 more replies)
  0 siblings, 3 replies; 93+ messages in thread
From: Ted Zlatanov @ 2010-08-13 15:07 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 849 bytes --]

On Fri, 13 Aug 2010 07:04:49 -0400 James Cloos <cloos@jhcloos.com> wrote: 

JC> I'm just scanning though the patch for now, but the first think I notice
JC> is that it needs to be updated from k&r to ansi.  

Fixed, except for:

process.c: In function ‘Fgnutls_global_init’:
process.c:6927: warning: old-style function definition
process.c: In function ‘Fgnutls_global_deinit’:
process.c:6942: warning: old-style function definition

Those two have no parameters, so I'm not sure what to fix.

JC> (Having written that, I don't remember whether the 23 branch was also
JC> updated from k&r; so the above may only apply if it is meant just for
JC> trunk.)

I was getting compiler warnings so we're supposed to use ANSI.  I just
didn't bother because there are so many more important issues with the
patch.  I attach the revised version.

Ted


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: tls.patch --]
[-- Type: text/x-diff, Size: 23849 bytes --]

=== modified file 'configure.in'
--- configure.in	2010-08-10 14:22:29 +0000
+++ configure.in	2010-08-12 22:48:32 +0000
@@ -169,6 +169,7 @@
 OPTION_DEFAULT_ON([dbus],[don't compile with D-Bus support])
 OPTION_DEFAULT_ON([gconf],[don't compile with GConf support])
 OPTION_DEFAULT_ON([selinux],[don't compile with SELinux support])
+OPTION_DEFAULT_ON([gnutls],[don't use -lgnutls for SSL/TLS support])
 
 ## For the times when you want to build Emacs but don't have
 ## a suitable makeinfo, and can live without the manuals.
@@ -1983,6 +1984,13 @@
 fi
 AC_SUBST(LIBSELINUX_LIBS)
 
+HAVE_GNUTLS=no
+if test "${with_gnutls}" = "yes" ; then
+  PKG_CHECK_MODULES([LIBGNUTLS], [gnutls >= 2.2.4])
+  AC_DEFINE(HAVE_GNUTLS)
+  HAVE_GNUTLS=yes
+fi
+
 dnl Do not put whitespace before the #include statements below.
 dnl Older compilers (eg sunos4 cc) choke on it.
 HAVE_XAW3D=no
@@ -3666,6 +3674,7 @@
 echo "  Does Emacs use -ldbus?                                  ${HAVE_DBUS}"
 echo "  Does Emacs use -lgconf?                                 ${HAVE_GCONF}"
 echo "  Does Emacs use -lselinux?                               ${HAVE_LIBSELINUX}"
+echo "  Does Emacs use Gnu TLS?                                 ${HAVE_GNUTLS}"
 
 echo "  Does Emacs use -lfreetype?                              ${HAVE_FREETYPE}"
 echo "  Does Emacs use -lm17n-flt?                              ${HAVE_M17N_FLT}"

=== modified file 'src/Makefile.in'
--- src/Makefile.in	2010-07-12 14:16:38 +0000
+++ src/Makefile.in	2010-08-12 22:47:22 +0000
@@ -280,6 +280,9 @@
 
 LIBSELINUX_LIBS = @LIBSELINUX_LIBS@
 
+LIBGNUTLS_LIBS = @LIBGNUTLS_LIBS@
+LIBGNUTLS_CFLAGS = @LIBGNUTLS_CFLAGS@
+
 INTERVALS_H = dispextern.h intervals.h composite.h
 
 GETLOADAVG_LIBS = @GETLOADAVG_LIBS@
@@ -318,6 +321,7 @@
   ${C_SWITCH_X_SYSTEM} ${CFLAGS_SOUND} ${RSVG_CFLAGS} ${DBUS_CFLAGS} \
   ${GCONF_CFLAGS} ${FREETYPE_CFLAGS} ${FONTCONFIG_CFLAGS} \
   ${LIBOTF_CFLAGS} ${M17N_FLT_CFLAGS} ${DEPFLAGS} ${PROFILING_CFLAGS} \
+  $(LIBGNUTLS_CFLAGS) \
   ${C_WARNINGS_SWITCH} ${CFLAGS}
 ALL_OBJC_CFLAGS=$(ALL_CFLAGS) $(GNU_OBJC_CFLAGS)
 
@@ -593,6 +597,7 @@
    $(RSVG_LIBS) $(DBUS_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \
    $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) ${GCONF_LIBS} ${LIBSELINUX_LIBS} \
    $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
+   $(LIBGNUTLS_LIBS) \
    $(LIB_GCC) $(LIB_MATH) $(LIB_STANDARD) $(LIB_GCC)
 
 all: emacs${EXEEXT} $(OTHER_FILES)

=== modified file 'src/config.in'
--- src/config.in	2010-08-09 19:25:41 +0000
+++ src/config.in	2010-08-12 22:24:33 +0000
@@ -255,6 +255,9 @@
 /* Define to 1 if you have a gif (or ungif) library. */
 #undef HAVE_GIF
 
+/* Define if we have the GNU TLS library.  */
+#undef HAVE_GNUTLS
+
 /* Define to 1 if you have the gpm library (-lgpm). */
 #undef HAVE_GPM
 
@@ -1085,6 +1088,12 @@
 #include config_opsysfile
 #include config_machfile
 
+#if HAVE_GNUTLS
+#define LIBGNUTLS $(LIBGNUTLS_LIBS)
+#else /* not HAVE_GNUTLS */
+#define LIBGNUTLS
+#endif /* not HAVE_GNUTLS */
+
 /* Set up some defines, C and LD flags for NeXTstep interface on GNUstep.
   (There is probably a better place to do this, but right now the Cocoa
    side does this in s/darwin.h and we cannot

=== modified file 'src/process.c'
--- src/process.c	2010-08-09 09:35:21 +0000
+++ src/process.c	2010-08-13 15:03:01 +0000
@@ -111,6 +111,10 @@
 #include "syssignal.h"
 #include "syswait.h"
 
+#ifdef HAVE_GNUTLS
+#include <gnutls/gnutls.h>
+#endif
+
 #if defined (USE_GTK) || defined (HAVE_GCONF)
 #include "xgselect.h"
 #endif /* defined (USE_GTK) || defined (HAVE_GCONF) */
@@ -1538,6 +1542,10 @@
   XPROCESS (proc)->filter = Qnil;
   XPROCESS (proc)->command = Flist (nargs - 2, args + 2);
 
+#ifdef HAVE_GNUTLS
+  XPROCESS (proc)->gnutls_state = Qnil;
+#endif
+
 #ifdef ADAPTIVE_READ_BUFFERING
   XPROCESS (proc)->adaptive_read_buffering
     = (NILP (Vprocess_adaptive_read_buffering) ? 0
@@ -5069,6 +5077,59 @@
   return Qt;
 }
 
+#ifdef HAVE_GNUTLS
+
+int
+emacs_gnutls_write (int fildes, gnutls_session_t state, char *buf,
+                    unsigned int nbyte)
+{
+  register int rtnval, bytes_written;
+
+  puts("emacs_gnutls_write");
+
+  bytes_written = 0;
+
+  while (nbyte > 0)
+    {
+      rtnval = gnutls_write (state, buf, nbyte);
+
+      if (rtnval == -1)
+	{
+	  if (errno == EINTR)
+	    continue;
+	  else
+	    return (bytes_written ? bytes_written : -1);
+	}
+
+      buf += rtnval;
+      nbyte -= rtnval;
+      bytes_written += rtnval;
+    }
+  printf("wrote %d bytes\n", bytes_written);
+  fsync(STDOUT_FILENO);
+
+  return (bytes_written);
+}
+
+int
+emacs_gnutls_read (int fildes, gnutls_session_t state, char *buf,
+                   unsigned int nbyte)
+{
+  register int rtnval;
+
+  puts("emacs_gnutls_read");
+
+  do {
+    rtnval = gnutls_read( state, buf, nbyte);
+    printf("read %d bytes\n", rtnval);
+  } while( rtnval==GNUTLS_E_INTERRUPTED || rtnval==GNUTLS_E_AGAIN);
+  printf("read %d bytes\n", rtnval);
+  fsync(STDOUT_FILENO);
+
+  return (rtnval);
+}
+#endif
+
 /* Read pending output from the process channel,
    starting with our buffered-ahead character if we have one.
    Yield number of decoded characters read.
@@ -5111,7 +5172,12 @@
 #endif
   if (proc_buffered_char[channel] < 0)
     {
-      nbytes = emacs_read (channel, chars + carryover, readmax);
+#ifdef HAVE_GNUTLS
+      if (NETCONN_P(proc) && !NILP (XPROCESS(proc)->gnutls_state))
+	nbytes = emacs_gnutls_read (channel, XPROCESS(proc)->gnutls_state, chars + carryover, readmax);
+      else
+#endif
+	nbytes = emacs_read (channel, chars + carryover, readmax);
 #ifdef ADAPTIVE_READ_BUFFERING
       if (nbytes > 0 && p->adaptive_read_buffering)
 	{
@@ -5144,7 +5210,12 @@
     {
       chars[carryover] = proc_buffered_char[channel];
       proc_buffered_char[channel] = -1;
-      nbytes = emacs_read (channel, chars + carryover + 1,  readmax - 1);
+#ifdef HAVE_GNUTLS
+      if (NETCONN_P(proc) && !NILP (XPROCESS(proc)->gnutls_state))
+	nbytes = emacs_gnutls_read (channel, XPROCESS(proc)->gnutls_state, chars + carryover + 1, readmax - 1);
+      else
+#endif
+	nbytes = emacs_read (channel, chars + carryover + 1,  readmax - 1);
       if (nbytes < 0)
 	nbytes = 1;
       else
@@ -5554,7 +5625,14 @@
 	      else
 #endif
 		{
-		  rv = emacs_write (outfd, (char *) buf, this);
+#ifdef HAVE_GNUTLS
+		  if (NETCONN_P(proc) && !NILP (XPROCESS(proc)->gnutls_state))
+		    rv = emacs_gnutls_write (outfd,
+					     XPROCESS(proc)->gnutls_state, 
+					     (char *) buf, this);
+		  else
+#endif
+		    rv = emacs_write (outfd, (char *) buf, this);
 #ifdef ADAPTIVE_READ_BUFFERING
 		  if (p->read_output_delay > 0
 		      && p->adaptive_read_buffering == 1)
@@ -6788,6 +6866,490 @@
 
 \f
 
+#ifdef HAVE_GNUTLS
+
+int gnutls_callback (gnutls_session_t state, const gnutls_datum *client_certs,
+                     int ncerts, const gnutls_datum* req_ca_cert, int nreqs)
+{
+  if (client_certs == NULL) {
+    /* means the we will only be called again if the library cannot
+     * determine which certificate to send
+     */
+    return 0;
+  }
+
+  puts("In callback");
+
+  return -1; /* send no certificate to the peer */
+}
+
+DEFUN ("gnutls-init", Fgnutls_init, Sgnutls_init, 2, 2, 0,
+       doc: /* Initializes GNU TLS for process PROC for use as CONNECTION-END.
+CONNECTION-END is used to indicate if this process is as a server or
+client. Can be one of `gnutls-client' and `gnutls-server'.  Currently
+only `gnutls-client' is supported.
+
+Processes must be initialized with this function before other GNU TLS
+functions are used.  This function allocates resources which can only
+be deallocated by calling `gnutls-deinit'. Returns zero on success. */)
+  ( Lisp_Object proc, Lisp_Object connection_end)
+{
+  int ret;
+  
+  CHECK_PROCESS (proc);
+
+  ret = gnutls_init((gnutls_session_t*)&(XPROCESS(proc)->gnutls_state), 
+		    connection_end);
+
+  return XINT(ret);
+}
+
+DEFUN ("gnutls-deinit", Fgnutls_deinit, Sgnutls_deinit, 1, 1, 0,
+       doc: /* Deallocate GNU TLS resources associated with PROCESS.
+See also `gnutls-init'. */)
+  (Lisp_Object proc)
+{
+  int ret;
+  gnutls_session_t state;
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  gnutls_deinit(state);
+
+  return Qnil;
+}
+
+DEFUN ("gnutls-global-init", Fgnutls_global_init, 
+       Sgnutls_global_init, 0, 0, 0,
+       doc: /* Initializes global GNU TLS state to defaults.
+Call `gnutls-global-deinit' when GNU TLS usage is no longer needed.
+Returns zero on success. */)
+  ()
+{
+  Lisp_Object lret;
+  int ret;
+
+  ret = gnutls_global_init();
+  XSETINT (lret, ret);
+
+  return lret;
+}
+
+DEFUN ("gnutls-global-deinit", Fgnutls_global_deinit, 
+       Sgnutls_global_deinit, 0, 0, 0,
+       doc: /* Deinitializes global GNU TLS state.
+See also `gnutls-global-init'. */)
+  ()
+{
+  gnutls_global_deinit();
+
+  return Qnil;
+}
+
+Lisp_Object
+generic_set_priority (int (*func)( gnutls_session_t state, const int*),
+                      int nargs, Lisp_Object *args)
+{
+  Lisp_Object proc;
+  Lisp_Object lret;
+  gnutls_session_t state;
+  int *algs;
+  size_t len;
+  int ret;
+  int i;
+  
+  proc = args[0];
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  for (i = 1; i < nargs; i++)
+      CHECK_NUMBER (args[i]);
+
+  len = nargs * sizeof(int);
+  algs = xmalloc (len);
+  for (i = 1; i < nargs; i++)
+      algs[i-1] = XFASTINT(args[i]);
+  algs[i-1] = 0;
+  ret = (*func) (state, algs);
+  xfree(algs);
+
+  XSETINT (lret, ret);
+  return lret;
+}
+
+DEFUN ("gnutls-protocol-set-priority", Fgnutls_protocol_set_priority, 
+       Sgnutls_protocol_set_priority, 1, MANY, 0,
+       doc: /* Sets the priority on the protocol versions supported by GNU TLS for PROCESS.
+The first parameter must be a process.	Subsequent parameters should
+be integers.  Priority is higher for protocols specified before
+others.	 Note that the priority is set on the client.  The server does
+not use the protocols's priority except for disabling protocols that
+were not specified. */)
+  (int nargs, Lisp_Object *args)
+{
+  Lisp_Object ret;
+
+  ret = generic_set_priority (&gnutls_protocol_set_priority, nargs, args);
+  
+  return ret;
+}
+
+DEFUN ("gnutls-cipher-set-priority", Fgnutls_cipher_set_priority, 
+       Sgnutls_cipher_set_priority, 1, MANY, 0,
+       doc: /* Sets the priority on the bulk ciphers supported by GNU TLS for PROCESS.
+The first parameter must be a process.	Subsequent parameters should
+be integers.  Priority is higher for protocols specified before
+others.	 Note that the priority is set on the client.  The server does
+not use the protocols's priority except for disabling protocols that
+were not specified. */)
+  (int nargs, Lisp_Object *args)
+{
+  Lisp_Object ret;
+
+  ret = generic_set_priority (&gnutls_cipher_set_priority, nargs, args);
+  
+  return ret;
+}
+
+DEFUN ("gnutls-compression-set-priority", Fgnutls_compression_set_priority, 
+       Sgnutls_compression_set_priority, 1, MANY, 0,
+       doc: /* Sets the priority on compression algorithms supported by GNU TLS for PROCESS.
+The first parameter must be a process.	Subsequent parameters should
+be integers.  Priority is higher for protocols specified before
+others.	 Note that the priority is set on the client.  The server does
+not use the protocols's priority except for disabling protocols that
+were not specified. */)
+  (int nargs, Lisp_Object *args)
+{
+  Lisp_Object ret;
+
+  ret = generic_set_priority (&gnutls_compression_set_priority, nargs, args);
+  
+  return ret;
+}
+
+DEFUN ("gnutls-kx-set-priority", Fgnutls_kx_set_priority, 
+       Sgnutls_kx_set_priority, 1, MANY, 0,
+       doc: /* Sets the priority on key exchange algorithms supported by GNU TLS for PROCESS.
+The first parameter must be a process.	Subsequent parameters should
+be integers.  Priority is higher for protocols specified before
+others.	 Note that the priority is set on the client.  The server does
+not use the protocols's priority except for disabling protocols that
+were not specified. */)
+  (int nargs, Lisp_Object *args)
+{
+  Lisp_Object ret;
+
+  ret = generic_set_priority (&gnutls_kx_set_priority, nargs, args);
+
+  return ret;
+}
+
+DEFUN ("gnutls-mac-set-priority", Fgnutls_mac_set_priority, 
+       Sgnutls_mac_set_priority, 1, MANY, 0,
+       doc: /* Sets the priority on MAC algorithms supported by GNU TLS for PROCESS.
+The first parameter must be a process.	Subsequent parameters should
+be integers.  Priority is higher for protocols specified before
+others.	 Note that the priority is set on the client.  The server does
+not use the protocols's priority except for disabling protocols that
+were not specified. */)
+  (int nargs, Lisp_Object *args)
+{
+  Lisp_Object ret;
+
+  ret = generic_set_priority (&gnutls_mac_set_priority, nargs, args);
+  
+  return ret;
+}
+
+/* BROKEN: can't figure out how to use this */
+// DEFUN ("gnutls-x509pki-set-client-cert-callback", 
+//	  Fgnutls_x509pki_set_client_cert_callback, 
+//	  Sgnutls_x509pki_set_client_cert_callback, 2, 2, 0,
+//	  doc: /* XXX Not completely implemented yet. */)
+//	(proc, callback)
+//	Lisp_Object proc, callback;
+// {
+//   gnutls_certificate_credentials_t x509_cred;
+//   Lisp_Object lret;
+//   int ret;
+
+//   CHECK_PROCESS (proc);
+//   x509_cred = (gnutls_certificate_credentials_t) XPROCESS(proc)->x509_cred;
+
+//   XPROCESS(proc)->x509_callback = callback;
+//   gnutls_x509pki_set_client_cert_callback (x509_cred, &gnutls_callback);
+
+//   return Qnil;
+// }
+
+DEFUN ("gnutls-x509pki-set-client-key-file", 
+       Fgnutls_x509pki_set_client_key_file,
+       Sgnutls_x509pki_set_client_key_file, 3, 3, 0,
+       doc: /* Set X.509 client credentials for PROCESS
+CERTFILE is a PEM encoded file containing the certificate list (path)
+for the specified private key. KEYFILE is a PEM encoded file
+containing a private key.  Returns zero on success.
+
+This function may be called more than once (in case multiple
+keys/certificates exist for the server).
+
+Currently only PKCS-1 PEM encoded RSA private keys are accepted by
+this function. */)
+  (Lisp_Object proc, Lisp_Object certfile, Lisp_Object keyfile)
+{
+  gnutls_session_t state;
+  gnutls_certificate_credentials_t x509_cred;
+  Lisp_Object lret;
+  int ret;
+
+  CHECK_STRING(certfile);
+  CHECK_STRING(keyfile);
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  x509_cred = (gnutls_certificate_credentials_t) XPROCESS(proc)->x509_cred;
+
+  ret = gnutls_x509pki_set_client_key_file (x509_cred, 
+					    XSTRING (certfile)->data, 
+					    XSTRING (keyfile)->data);
+
+  XSETINT (lret, ret);
+  return lret;
+}
+
+DEFUN ("gnutls-x509pki-set-client-trust-file", 
+       Fgnutls_x509pki_set_client_trust_file,
+       Sgnutls_x509pki_set_client_trust_file, 3, 3, 0,
+       doc: /* Set X.509 trusted credentials for PROCESS
+CAFILE is a PEM encoded file containing trusted CAs. CRLFILE is a PEM
+encoded file containing CRLs (ignored for now). Returns zero on
+success. */)
+  (Lisp_Object proc, Lisp_Object cafile, Lisp_Object crlfile)
+{
+  gnutls_session_t state;
+  gnutls_certificate_credentials_t x509_cred;
+  Lisp_Object lret;
+  int ret;
+
+  CHECK_STRING(cafile);
+  CHECK_STRING(crlfile);
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  x509_cred = (gnutls_certificate_credentials_t) XPROCESS(proc)->x509_cred;
+
+  ret = gnutls_x509pki_set_client_trust_file (x509_cred, 
+					    NILP (cafile) ? NULL : 
+					    XSTRING (cafile)->data,
+					    NILP (crlfile) ? NULL : 
+					    XSTRING (crlfile)->data);
+
+  XSETINT (lret, ret);
+  return lret;
+}
+
+DEFUN ("gnutls-srp-set-client-cred", Fgnutls_srp_set_client_cred,
+       Sgnutls_srp_set_client_cred, 3, 3, 0,
+       doc: /* Set SRP username and password for PROCESS.  
+PROCESS must be a process. USERNAME is the user's userid. PASSWORD is
+the user's password. Returns zero on success. */)
+  (Lisp_Object proc, Lisp_Object username, Lisp_Object password)
+{
+  gnutls_session_t state;
+  gnutls_srp_client_credentials_t srp_cred;
+  Lisp_Object lret;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  srp_cred = (gnutls_srp_client_credentials_t) XPROCESS(proc)->srp_cred;
+
+  ret = gnutls_srp_set_client_credentials (srp_cred,
+					   NILP (username) ? NULL :
+					   XSTRING(username)->data, 
+					   NILP (password) ? NULL :
+					   XSTRING(password)->data);
+
+  XSETINT (lret, ret);
+  return lret;
+}
+
+DEFUN ("gnutls-anon-set-client-cred", Fgnutls_anon_set_client_cred,
+       Sgnutls_anon_set_client_cred, 2, 2, 0,
+       doc: /* Set the number of bits to use in anonymous Diffie-Hellman exchange for PROCESS.
+DH_BITS is the number of bits in DH key exchange. Returns zero on 
+success. */)
+  (Lisp_Object proc, Lisp_Object dh_bits)
+{
+  gnutls_session_t state;
+  gnutls_anon_client_credentials_t anon_cred;
+  Lisp_Object lret;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  anon_cred = (gnutls_anon_client_credentials_t) XPROCESS(proc)->anon_cred;
+
+  ret = gnutls_anon_set_client_dh_params (anon_cred, XINT(dh_bits));
+
+  XSETINT (lret, ret);
+  return lret;
+}
+
+DEFUN ("gnutls-cred-set", Fgnutls_cred_set, 
+       Sgnutls_cred_set, 2, 2, 0,
+       doc: /* Enables GNU TLS authentication for PROCESS.
+TYPE is an integer indicating the type of the credentials, either
+`gnutls-anon', `gnutls-srp' or `gnutls-x509pki'.
+
+Each authentication type may need additional information in order to
+work.  For anonymous (`gnutls-anon'), see also
+`gnutls-anon-set-client-cred'.	For SRP (`gnutls-srp'), see also
+`gnutls-srp-set-client-cred'.  For X.509 PKI (`gnutls-x509pki'), see
+also `gnutls-x509pki-set-client-trust-file',
+`gnutls-x509pki-set-client-key-file', and
+`gnutls-x509pki-set-cert-callback'. */)
+  (Lisp_Object proc, Lisp_Object type)
+{
+  gnutls_session_t state;
+  gnutls_certificate_credentials_t x509_cred;
+  gnutls_anon_client_credentials_t anon_cred;
+  gnutls_srp_client_credentials_t srp_cred;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  x509_cred = (gnutls_certificate_client_credentials) XPROCESS(proc)->x509_cred;
+  anon_cred = (gnutls_anon_client_credentials_t) XPROCESS(proc)->anon_cred;
+  srp_cred = (gnutls_srp_client_credentials_t) XPROCESS(proc)->srp_cred;
+
+  switch (XINT (type))
+    {
+    case GNUTLS_CRD_CERTIFICATE: 
+      if (gnutls_crd_allocate_client_credentials (&x509_cred, 1) < 0)
+	memory_full ();
+      ret = gnutls_cred_set (state, GNUTLS_CRD_CERTIFICATE, x509_cred);
+      break;
+
+    case GNUTLS_CRD_ANON:
+      if (gnutls_anon_allocate_client_credentials (&anon_cred) < 0)
+	memory_full ();
+      ret = gnutls_cred_set (state, GNUTLS_CRD_ANON, anon_cred);
+      break;
+
+    case GNUTLS_CRD_SRP:
+      if (gnutls_srp_allocate_client_credentials (&srp_cred) < 0)
+	memory_full ();
+      ret = gnutls_cred_set (state, GNUTLS_CRD_SRP, srp_cred);
+      break;
+    }
+
+  return XINT(ret);
+}
+
+DEFUN ("gnutls-bye", Fgnutls_bye, 
+       Sgnutls_bye, 2, 2, 0,
+       doc: /* Terminate current GNU TLS connection for PROCESS.
+The connection should have been initiated using gnutls_handshake().
+HOW should be one of `gnutls-shut-rdwr', `gnutls-shut-wr'.
+
+In case of `gnutls-shut-rdwr' then the TLS connection gets terminated
+and further receives and sends will be disallowed. If the return value
+is zero you may continue using the connection.	`gnutls-shut-rdwr'
+actually sends an alert containing a close request and waits for the
+peer to reply with the same message.
+  
+In case of `gnutls-shut-wr' then the TLS connection gets terminated
+and further sends will be disallowed. In order to reuse the connection
+you should wait for an EOF from the peer.  `gnutls-shut-wr' sends an
+alert containing a close request.
+  
+This function may also return `gnutls-e-again', or
+`gnutls-e-interrupted'. */)
+  (Lisp_Object proc, Lisp_Object how)
+{
+  gnutls_session_t state;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  CHECK_NUMBER (how);
+
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  ret = gnutls_bye(state, XFASTINT(how));
+  
+  return XINT(ret);
+}
+
+DEFUN ("gnutls-handshake", Fgnutls_handshake, 
+       Sgnutls_handshake, 1, 1, 0,
+       doc: /* Perform GNU TLS handshake for PROCESS.
+The identity of the peer is checked automatically.  This function will
+fail if any problem is encountered, and will return a negative error
+code. In case of a client, if it has been asked to resume a session,
+but the server didn't, then a full handshake will be performed.
+  
+This function may also return the non-fatal errors `gnutls-e-again',
+or `gnutls-e-interrupted'. In that case you may resume the handshake
+(by calling this function again). */)
+  (Lisp_Object proc)
+{
+  gnutls_session_t state;
+  Lisp_Object lret;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  gnutls_transport_set_ptr( state, XPROCESS(proc)->infd);
+  ret = gnutls_handshake( state);
+  XSETINT(lret, ret);
+  
+  return lret;
+}
+
+DEFUN ("gnutls-rehandshake", Fgnutls_rehandshake, 
+       Sgnutls_rehandshake, 1, 1, 0,
+       doc: /* Renegotiate GNU TLS security parameters for PROCESS.
+This function will renegotiate security parameters with the
+client. This should only be called in case of a server.
+
+This message informs the peer that we want to renegotiate parameters
+\(perform a handshake).
+  
+If this function succeeds (returns 0), you must call the
+gnutls_handshake() function in order to negotiate the new parameters.
+  
+If the client does not wish to renegotiate parameters he will reply
+with an alert message, thus the return code will be
+`gnutls-e-warning-alert-received' and the alert will be
+`gnutls-e-no-renegotiation'. */)
+  (Lisp_Object proc)
+{
+  gnutls_session_t state;
+  Lisp_Object lret;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  gnutls_transport_set_ptr( state, XPROCESS(proc)->infd);
+  ret = gnutls_rehandshake( state);
+  XSETINT(lret, ret);
+  
+  return lret;
+}
+#endif
+
+\f
+
 static int add_gpm_wait_descriptor_called_flag;
 
 void
@@ -7708,6 +8270,25 @@
   defsubr (&Sprocess_coding_system);
   defsubr (&Sset_process_filter_multibyte);
   defsubr (&Sprocess_filter_multibyte_p);
+#ifdef HAVE_GNUTLS
+  defsubr (&Sgnutls_global_init);
+  defsubr (&Sgnutls_global_deinit);
+  defsubr (&Sgnutls_init);
+  defsubr (&Sgnutls_deinit);
+  defsubr (&Sgnutls_protocol_set_priority);
+  defsubr (&Sgnutls_cipher_set_priority);
+  defsubr (&Sgnutls_compression_set_priority);
+  defsubr (&Sgnutls_kx_set_priority);
+  defsubr (&Sgnutls_mac_set_priority);
+  defsubr (&Sgnutls_cred_set);
+  defsubr (&Sgnutls_handshake);
+  defsubr (&Sgnutls_rehandshake);
+  defsubr (&Sgnutls_x509pki_set_client_key_file);
+  defsubr (&Sgnutls_x509pki_set_client_trust_file);
+  defsubr (&Sgnutls_srp_set_client_cred);
+  defsubr (&Sgnutls_anon_set_client_cred);
+  defsubr (&Sgnutls_bye);
+#endif /* HAVE_GNUTLS */
 
 #endif	/* subprocesses */
 

=== modified file 'src/process.h'
--- src/process.h	2010-08-11 12:34:46 +0000
+++ src/process.h	2010-08-12 22:35:18 +0000
@@ -121,6 +121,14 @@
        needs to be synced to `status'.  */
     unsigned int raw_status_new : 1;
     int raw_status;
+
+#ifdef HAVE_GNUTLS
+    /* XXX Store GNU TLS state and auth mechanisms in Lisp_Objects. */
+    Lisp_Object gnutls_state;
+    Lisp_Object x509_cred, x509_callback;
+    Lisp_Object anon_cred;
+    Lisp_Object srp_cred;
+#endif
 };
 
 /* Every field in the preceding structure except for the first two


^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-08-13 15:07               ` Ted Zlatanov
@ 2010-08-13 15:51                 ` Julien Danjou
  2010-08-13 16:11                   ` Eli Zaretskii
  2010-08-13 15:53                 ` David Kastrup
  2010-08-13 15:57                 ` Chong Yidong
  2 siblings, 1 reply; 93+ messages in thread
From: Julien Danjou @ 2010-08-13 15:51 UTC (permalink / raw)
  To: Ted Zlatanov; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 486 bytes --]

On Fri, Aug 13 2010, Ted Zlatanov wrote: 

> process.c: In function ‘Fgnutls_global_init’: process.c:6927: 
> warning: old-style function definition process.c: In function 
> ‘Fgnutls_global_deinit’: process.c:6942: warning: old-style 
> function definition  Those two have no parameters, so I'm not 
> sure what to fix. 

It seems that the DEFUN macro is still k&r. Not your fault AFAICT.

-- 
Julien Danjou
// ᐰ <julien@danjou.info>   http://julien.danjou.info

[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-08-13 15:07               ` Ted Zlatanov
  2010-08-13 15:51                 ` Julien Danjou
@ 2010-08-13 15:53                 ` David Kastrup
  2010-08-13 16:11                   ` Julien Danjou
  2010-08-13 15:57                 ` Chong Yidong
  2 siblings, 1 reply; 93+ messages in thread
From: David Kastrup @ 2010-08-13 15:53 UTC (permalink / raw)
  To: emacs-devel

Ted Zlatanov <tzz@lifelogs.com> writes:

> On Fri, 13 Aug 2010 07:04:49 -0400 James Cloos <cloos@jhcloos.com> wrote: 
>
> JC> I'm just scanning though the patch for now, but the first think I notice
> JC> is that it needs to be updated from k&r to ansi.  
>
> Fixed, except for:
>
> process.c: In function ‘Fgnutls_global_init’:
> process.c:6927: warning: old-style function definition
> process.c: In function ‘Fgnutls_global_deinit’:
> process.c:6942: warning: old-style function definition
>
> Those two have no parameters, so I'm not sure what to fix.

int xxx(void);

IIRC

-- 
David Kastrup




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-08-13 15:07               ` Ted Zlatanov
  2010-08-13 15:51                 ` Julien Danjou
  2010-08-13 15:53                 ` David Kastrup
@ 2010-08-13 15:57                 ` Chong Yidong
  2010-08-13 17:25                   ` Ted Zlatanov
  2 siblings, 1 reply; 93+ messages in thread
From: Chong Yidong @ 2010-08-13 15:57 UTC (permalink / raw)
  To: Ted Zlatanov; +Cc: emacs-devel

Hi Ted,

Thanks for bringing up the patch again.  I haven't read it closely, but
here are some initial remarks and questions:


Ted Zlatanov <tzz@lifelogs.com> writes:

> +  do {
> +    rtnval = gnutls_read( state, buf, nbyte);
> +    printf("read %d bytes\n", rtnval);
> +  } while( rtnval==GNUTLS_E_INTERRUPTED || rtnval==GNUTLS_E_AGAIN);

You should use the GNU style here.

> +DEFUN ("gnutls-init", Fgnutls_init, Sgnutls_init, 2, 2, 0,
> +       doc: /* Initializes GNU TLS for process PROC for use as CONNECTION-END.

This should be "Initialize" instead of "Initializes".

In general, this docstring is not very informative.  I have not been
following this patch closely; just from reading the docstring, I'm not
sure what gnutls-init is supposed to do.  I assume that it means that,
once it is called, all data sent from Emacs to the process PROC, and
vice versa, will be encrypted using the GnuTLS library.  Is that right?
Does `gnutls-handshake' need to be called before, or after, this?  What
happens if you try to send data to PROC before `gnutls-handshake'?
These issues should be explained in the docstring.

More generally, why do we need to a separate `gnutls-init' call, instead
of making `gnutls-handshake' and other functions automatically enable
GnuTLS functionality for the process?

> +DEFUN ("gnutls-deinit", Fgnutls_deinit, Sgnutls_deinit, 1, 1, 0,

I think this should be called `gnutls-stop' or something like that;
"deinit" is not a proper word.  Maybe rename `gnutls-init' to
`gnutls-start'.

> +DEFUN ("gnutls-global-init", Fgnutls_global_init,
> +       Sgnutls_global_init, 0, 0, 0,
> +       doc: /* Initializes global GNU TLS state to defaults.
> +Call `gnutls-global-deinit' when GNU TLS usage is no longer needed.
> +Returns zero on success. */)

This is again not very informative.  Does it mean that it is equivalent
to calling `gnutls-init' on every process by default?

> +DEFUN ("gnutls-global-deinit", Fgnutls_global_deinit,

Again, "deinit" should not be used.

> +DEFUN ("gnutls-protocol-set-priority", Fgnutls_protocol_set_priority,
> +       Sgnutls_protocol_set_priority, 1, MANY, 0,
> +       doc: /* Sets the priority on the protocol versions supported by GNU TLS for PROCESS.
> +The first parameter must be a process.	Subsequent parameters should
> +be integers.  Priority is higher for protocols specified before

Use the word "argument" instead of "parameter".  Also, there is some
formatting mix-up in this and other docstrings.



^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-08-13 15:51                 ` Julien Danjou
@ 2010-08-13 16:11                   ` Eli Zaretskii
  0 siblings, 0 replies; 93+ messages in thread
From: Eli Zaretskii @ 2010-08-13 16:11 UTC (permalink / raw)
  To: Julien Danjou; +Cc: tzz, emacs-devel

> From: Julien Danjou <julien@danjou.info>
> Date: Fri, 13 Aug 2010 17:51:57 +0200
> Cc: emacs-devel@gnu.org
> 
> It seems that the DEFUN macro is still k&r.

It is?  How do you see that?



^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-08-13 15:53                 ` David Kastrup
@ 2010-08-13 16:11                   ` Julien Danjou
  0 siblings, 0 replies; 93+ messages in thread
From: Julien Danjou @ 2010-08-13 16:11 UTC (permalink / raw)
  To: David Kastrup; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 257 bytes --]

On Fri, Aug 13 2010, David Kastrup wrote: 

> int xxx(void); 

Yeah, correct, my bad. Changing () to (void) should fix it, since 
DEFUN with 0 args declare (void) too. :-)

-- 
Julien Danjou
// ᐰ <julien@danjou.info>   http://julien.danjou.info

[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-08-13 15:57                 ` Chong Yidong
@ 2010-08-13 17:25                   ` Ted Zlatanov
  2010-08-14  0:15                     ` Chong Yidong
  0 siblings, 1 reply; 93+ messages in thread
From: Ted Zlatanov @ 2010-08-13 17:25 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 4580 bytes --]

On Fri, 13 Aug 2010 11:57:45 -0400 Chong Yidong <cyd@stupidchicken.com> wrote: 

CY> Ted Zlatanov <tzz@lifelogs.com> writes:

>> +  do {
>> +    rtnval = gnutls_read( state, buf, nbyte);
>> +    printf("read %d bytes\n", rtnval);
>> +  } while( rtnval==GNUTLS_E_INTERRUPTED || rtnval==GNUTLS_E_AGAIN);

CY> You should use the GNU style here.

Fixed.

>> +DEFUN ("gnutls-init", Fgnutls_init, Sgnutls_init, 2, 2, 0,
>> +       doc: /* Initializes GNU TLS for process PROC for use as CONNECTION-END.

CY> This should be "Initialize" instead of "Initializes".

Fixed.

CY> In general, this docstring is not very informative.  I have not been
CY> following this patch closely; just from reading the docstring, I'm not
CY> sure what gnutls-init is supposed to do.  I assume that it means that,
CY> once it is called, all data sent from Emacs to the process PROC, and
CY> vice versa, will be encrypted using the GnuTLS library.  Is that right?
CY> Does `gnutls-handshake' need to be called before, or after, this?  What
CY> happens if you try to send data to PROC before `gnutls-handshake'?
CY> These issues should be explained in the docstring.

CY> More generally, why do we need to a separate `gnutls-init' call, instead
CY> of making `gnutls-handshake' and other functions automatically enable
CY> GnuTLS functionality for the process?

Simon's code included a gnutls.el library, attached here.  It shows how
to use it.  It's a straightforward port of the GnuTLS calls (hence the
docstrings assume familiarity with that library) so you have to call
them in order just like a C client would.  We could try to collect that
sequence (as seen in `open-ssl-stream' and `starttls-negotiate' twice,
why I don't know):

1) global init (set up static structures)
2) init the client
3) set protocol, cipher, compression, kx, mac priority
4) set credentials

into one C function call.  gnutls-handshake is called repeatedly (while
EAGAIN is returned) until either an error happens or it succeeds.  You
can even rehandshake().  So I think the idea is that it should be a
repeatable call while the rest of the initialization is supposed to be
done just once.  All of that could certainly be wrapped in a single C
call, but Simon did it the other way.

Writing to the stream before the handshake has succeeded will return -1
for number of bytes written, but the exact process is up to GnuTLS and
errno is passing the error code back to us:

(from `emacs_gnutls_write')
...
rtnval = gnutls_write (state, buf, nbyte);

if (rtnval == -1)
{
  if (errno == EINTR)
    continue;
  else
    return (bytes_written ? bytes_written : -1);
}
...

This won't happen unless the process' gnutls_state is set by
`gnutls_init', but it could potentially happen before a successful
handshake.

That's a lot to put into the docstrings for all those functions.  It's
probably better to point people to the gnutls.el docs.

>> +DEFUN ("gnutls-deinit", Fgnutls_deinit, Sgnutls_deinit, 1, 1, 0,

CY> I think this should be called `gnutls-stop' or something like that;
CY> "deinit" is not a proper word.  Maybe rename `gnutls-init' to
CY> `gnutls-start'.

>> +DEFUN ("gnutls-global-init", Fgnutls_global_init,

CY> This is again not very informative.  Does it mean that it is equivalent
CY> to calling `gnutls-init' on every process by default?

>> +DEFUN ("gnutls-global-deinit", Fgnutls_global_deinit,

CY> Again, "deinit" should not be used.

But those are the GnuTLS names for the functions.  So it's confusing if
the Emacs core process.c functions map to different names in GnuTLS.
Unless we abstract the process creation at the C layer (aggregating what
`open-ssl-stream' does and eliminating the one-to-one function
mappings), I think it's worse to rename these functions.

>> +DEFUN ("gnutls-protocol-set-priority", Fgnutls_protocol_set_priority,
>> +       Sgnutls_protocol_set_priority, 1, MANY, 0,
>> +       doc: /* Sets the priority on the protocol versions supported by GNU TLS for PROCESS.
>> +The first parameter must be a process.	Subsequent parameters should
>> +be integers.  Priority is higher for protocols specified before

CY> Use the word "argument" instead of "parameter".  Also, there is some
CY> formatting mix-up in this and other docstrings.

That's fixed and I removed the TAB characters that came from the
original patch.

On Fri, 13 Aug 2010 17:53:36 +0200 David Kastrup <dak@gnu.org> wrote: 

DK> int xxx(void);

Thanks, applied.

Also note there's some ambition in this patch to have Emacs provide
server-side SSL.  I don't know if that should be removed completely or
considered.

Ted


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: tls.patch --]
[-- Type: text/x-diff, Size: 23866 bytes --]

=== modified file 'configure.in'
--- configure.in	2010-08-10 14:22:29 +0000
+++ configure.in	2010-08-12 22:48:32 +0000
@@ -169,6 +169,7 @@
 OPTION_DEFAULT_ON([dbus],[don't compile with D-Bus support])
 OPTION_DEFAULT_ON([gconf],[don't compile with GConf support])
 OPTION_DEFAULT_ON([selinux],[don't compile with SELinux support])
+OPTION_DEFAULT_ON([gnutls],[don't use -lgnutls for SSL/TLS support])
 
 ## For the times when you want to build Emacs but don't have
 ## a suitable makeinfo, and can live without the manuals.
@@ -1983,6 +1984,13 @@
 fi
 AC_SUBST(LIBSELINUX_LIBS)
 
+HAVE_GNUTLS=no
+if test "${with_gnutls}" = "yes" ; then
+  PKG_CHECK_MODULES([LIBGNUTLS], [gnutls >= 2.2.4])
+  AC_DEFINE(HAVE_GNUTLS)
+  HAVE_GNUTLS=yes
+fi
+
 dnl Do not put whitespace before the #include statements below.
 dnl Older compilers (eg sunos4 cc) choke on it.
 HAVE_XAW3D=no
@@ -3666,6 +3674,7 @@
 echo "  Does Emacs use -ldbus?                                  ${HAVE_DBUS}"
 echo "  Does Emacs use -lgconf?                                 ${HAVE_GCONF}"
 echo "  Does Emacs use -lselinux?                               ${HAVE_LIBSELINUX}"
+echo "  Does Emacs use Gnu TLS?                                 ${HAVE_GNUTLS}"
 
 echo "  Does Emacs use -lfreetype?                              ${HAVE_FREETYPE}"
 echo "  Does Emacs use -lm17n-flt?                              ${HAVE_M17N_FLT}"

=== modified file 'src/Makefile.in'
--- src/Makefile.in	2010-07-12 14:16:38 +0000
+++ src/Makefile.in	2010-08-12 22:47:22 +0000
@@ -280,6 +280,9 @@
 
 LIBSELINUX_LIBS = @LIBSELINUX_LIBS@
 
+LIBGNUTLS_LIBS = @LIBGNUTLS_LIBS@
+LIBGNUTLS_CFLAGS = @LIBGNUTLS_CFLAGS@
+
 INTERVALS_H = dispextern.h intervals.h composite.h
 
 GETLOADAVG_LIBS = @GETLOADAVG_LIBS@
@@ -318,6 +321,7 @@
   ${C_SWITCH_X_SYSTEM} ${CFLAGS_SOUND} ${RSVG_CFLAGS} ${DBUS_CFLAGS} \
   ${GCONF_CFLAGS} ${FREETYPE_CFLAGS} ${FONTCONFIG_CFLAGS} \
   ${LIBOTF_CFLAGS} ${M17N_FLT_CFLAGS} ${DEPFLAGS} ${PROFILING_CFLAGS} \
+  $(LIBGNUTLS_CFLAGS) \
   ${C_WARNINGS_SWITCH} ${CFLAGS}
 ALL_OBJC_CFLAGS=$(ALL_CFLAGS) $(GNU_OBJC_CFLAGS)
 
@@ -593,6 +597,7 @@
    $(RSVG_LIBS) $(DBUS_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \
    $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) ${GCONF_LIBS} ${LIBSELINUX_LIBS} \
    $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
+   $(LIBGNUTLS_LIBS) \
    $(LIB_GCC) $(LIB_MATH) $(LIB_STANDARD) $(LIB_GCC)
 
 all: emacs${EXEEXT} $(OTHER_FILES)

=== modified file 'src/config.in'
--- src/config.in	2010-08-09 19:25:41 +0000
+++ src/config.in	2010-08-12 22:24:33 +0000
@@ -255,6 +255,9 @@
 /* Define to 1 if you have a gif (or ungif) library. */
 #undef HAVE_GIF
 
+/* Define if we have the GNU TLS library.  */
+#undef HAVE_GNUTLS
+
 /* Define to 1 if you have the gpm library (-lgpm). */
 #undef HAVE_GPM
 
@@ -1085,6 +1088,12 @@
 #include config_opsysfile
 #include config_machfile
 
+#if HAVE_GNUTLS
+#define LIBGNUTLS $(LIBGNUTLS_LIBS)
+#else /* not HAVE_GNUTLS */
+#define LIBGNUTLS
+#endif /* not HAVE_GNUTLS */
+
 /* Set up some defines, C and LD flags for NeXTstep interface on GNUstep.
   (There is probably a better place to do this, but right now the Cocoa
    side does this in s/darwin.h and we cannot

=== modified file 'src/process.c'
--- src/process.c	2010-08-09 09:35:21 +0000
+++ src/process.c	2010-08-13 17:15:11 +0000
@@ -111,6 +111,10 @@
 #include "syssignal.h"
 #include "syswait.h"
 
+#ifdef HAVE_GNUTLS
+#include <gnutls/gnutls.h>
+#endif
+
 #if defined (USE_GTK) || defined (HAVE_GCONF)
 #include "xgselect.h"
 #endif /* defined (USE_GTK) || defined (HAVE_GCONF) */
@@ -1538,6 +1542,10 @@
   XPROCESS (proc)->filter = Qnil;
   XPROCESS (proc)->command = Flist (nargs - 2, args + 2);
 
+#ifdef HAVE_GNUTLS
+  XPROCESS (proc)->gnutls_state = Qnil;
+#endif
+
 #ifdef ADAPTIVE_READ_BUFFERING
   XPROCESS (proc)->adaptive_read_buffering
     = (NILP (Vprocess_adaptive_read_buffering) ? 0
@@ -5069,6 +5077,61 @@
   return Qt;
 }
 
+#ifdef HAVE_GNUTLS
+
+int
+emacs_gnutls_write (int fildes, gnutls_session_t state, char *buf,
+                    unsigned int nbyte)
+{
+  register int rtnval, bytes_written;
+
+  puts("emacs_gnutls_write");
+
+  bytes_written = 0;
+
+  while (nbyte > 0)
+    {
+      rtnval = gnutls_write (state, buf, nbyte);
+
+      if (rtnval == -1)
+	{
+	  if (errno == EINTR)
+	    continue;
+	  else
+	    return (bytes_written ? bytes_written : -1);
+	}
+
+      buf += rtnval;
+      nbyte -= rtnval;
+      bytes_written += rtnval;
+    }
+  printf("wrote %d bytes\n", bytes_written);
+  fsync(STDOUT_FILENO);
+
+  return (bytes_written);
+}
+
+int
+emacs_gnutls_read (int fildes, gnutls_session_t state, char *buf,
+                   unsigned int nbyte)
+{
+  register int rtnval;
+
+  puts("emacs_gnutls_read");
+
+  do
+    {
+      rtnval = gnutls_read( state, buf, nbyte);
+      printf("read %d bytes\n", rtnval);
+    }
+  while( rtnval==GNUTLS_E_INTERRUPTED || rtnval==GNUTLS_E_AGAIN);
+  printf("read %d bytes\n", rtnval);
+  fsync(STDOUT_FILENO);
+
+  return (rtnval);
+}
+#endif
+
 /* Read pending output from the process channel,
    starting with our buffered-ahead character if we have one.
    Yield number of decoded characters read.
@@ -5111,7 +5174,12 @@
 #endif
   if (proc_buffered_char[channel] < 0)
     {
-      nbytes = emacs_read (channel, chars + carryover, readmax);
+#ifdef HAVE_GNUTLS
+      if (NETCONN_P(proc) && !NILP (XPROCESS(proc)->gnutls_state))
+	nbytes = emacs_gnutls_read (channel, XPROCESS(proc)->gnutls_state, chars + carryover, readmax);
+      else
+#endif
+	nbytes = emacs_read (channel, chars + carryover, readmax);
 #ifdef ADAPTIVE_READ_BUFFERING
       if (nbytes > 0 && p->adaptive_read_buffering)
 	{
@@ -5144,7 +5212,12 @@
     {
       chars[carryover] = proc_buffered_char[channel];
       proc_buffered_char[channel] = -1;
-      nbytes = emacs_read (channel, chars + carryover + 1,  readmax - 1);
+#ifdef HAVE_GNUTLS
+      if (NETCONN_P(proc) && !NILP (XPROCESS(proc)->gnutls_state))
+	nbytes = emacs_gnutls_read (channel, XPROCESS(proc)->gnutls_state, chars + carryover + 1, readmax - 1);
+      else
+#endif
+	nbytes = emacs_read (channel, chars + carryover + 1,  readmax - 1);
       if (nbytes < 0)
 	nbytes = 1;
       else
@@ -5554,7 +5627,14 @@
 	      else
 #endif
 		{
-		  rv = emacs_write (outfd, (char *) buf, this);
+#ifdef HAVE_GNUTLS
+		  if (NETCONN_P(proc) && !NILP (XPROCESS(proc)->gnutls_state))
+		    rv = emacs_gnutls_write (outfd,
+					     XPROCESS(proc)->gnutls_state, 
+					     (char *) buf, this);
+		  else
+#endif
+		    rv = emacs_write (outfd, (char *) buf, this);
 #ifdef ADAPTIVE_READ_BUFFERING
 		  if (p->read_output_delay > 0
 		      && p->adaptive_read_buffering == 1)
@@ -6788,6 +6868,490 @@
 
 \f
 
+#ifdef HAVE_GNUTLS
+
+int gnutls_callback (gnutls_session_t state, const gnutls_datum *client_certs,
+                     int ncerts, const gnutls_datum* req_ca_cert, int nreqs)
+{
+  if (client_certs == NULL) {
+    /* means the we will only be called again if the library cannot
+     * determine which certificate to send
+     */
+    return 0;
+  }
+
+  puts("In callback");
+
+  return -1; /* send no certificate to the peer */
+}
+
+DEFUN ("gnutls-init", Fgnutls_init, Sgnutls_init, 2, 2, 0,
+       doc: /* Initialize GNU TLS for process PROC for use as CONNECTION-END.
+CONNECTION-END is used to indicate if this process is as a server or
+client. Can be one of `gnutls-client' and `gnutls-server'.  Currently
+only `gnutls-client' is supported.
+
+Processes must be initialized with this function before other GNU TLS
+functions are used.  This function allocates resources which can only
+be deallocated by calling `gnutls-deinit'. Returns zero on success. */)
+  ( Lisp_Object proc, Lisp_Object connection_end)
+{
+  int ret;
+  
+  CHECK_PROCESS (proc);
+
+  ret = gnutls_init((gnutls_session_t*)&(XPROCESS(proc)->gnutls_state), 
+		    connection_end);
+
+  return XINT(ret);
+}
+
+DEFUN ("gnutls-deinit", Fgnutls_deinit, Sgnutls_deinit, 1, 1, 0,
+       doc: /* Deallocate GNU TLS resources associated with PROCESS.
+See also `gnutls-init'. */)
+  (Lisp_Object proc)
+{
+  int ret;
+  gnutls_session_t state;
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  gnutls_deinit(state);
+
+  return Qnil;
+}
+
+DEFUN ("gnutls-global-init", Fgnutls_global_init, 
+       Sgnutls_global_init, 0, 0, 0,
+       doc: /* Initializes global GNU TLS state to defaults.
+Call `gnutls-global-deinit' when GNU TLS usage is no longer needed.
+Returns zero on success. */)
+  (void)
+{
+  Lisp_Object lret;
+  int ret;
+
+  ret = gnutls_global_init();
+  XSETINT (lret, ret);
+
+  return lret;
+}
+
+DEFUN ("gnutls-global-deinit", Fgnutls_global_deinit, 
+       Sgnutls_global_deinit, 0, 0, 0,
+       doc: /* Deinitializes global GNU TLS state.
+See also `gnutls-global-init'. */)
+  (void)
+{
+  gnutls_global_deinit();
+
+  return Qnil;
+}
+
+Lisp_Object
+generic_set_priority (int (*func)( gnutls_session_t state, const int*),
+                      int nargs, Lisp_Object *args)
+{
+  Lisp_Object proc;
+  Lisp_Object lret;
+  gnutls_session_t state;
+  int *algs;
+  size_t len;
+  int ret;
+  int i;
+  
+  proc = args[0];
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  for (i = 1; i < nargs; i++)
+      CHECK_NUMBER (args[i]);
+
+  len = nargs * sizeof(int);
+  algs = xmalloc (len);
+  for (i = 1; i < nargs; i++)
+      algs[i-1] = XFASTINT(args[i]);
+  algs[i-1] = 0;
+  ret = (*func) (state, algs);
+  xfree(algs);
+
+  XSETINT (lret, ret);
+  return lret;
+}
+
+DEFUN ("gnutls-protocol-set-priority", Fgnutls_protocol_set_priority, 
+       Sgnutls_protocol_set_priority, 1, MANY, 0,
+       doc: /* Sets the priority on the protocol versions supported by GNU TLS for PROCESS.
+The first argument must be a process.  Subsequent arguments should
+be integers.  Priority is higher for protocols specified before
+others.  Note that the priority is set on the client.  The server does
+not use the protocols's priority except for disabling protocols that
+were not specified. */)
+  (int nargs, Lisp_Object *args)
+{
+  Lisp_Object ret;
+
+  ret = generic_set_priority (&gnutls_protocol_set_priority, nargs, args);
+  
+  return ret;
+}
+
+DEFUN ("gnutls-cipher-set-priority", Fgnutls_cipher_set_priority, 
+       Sgnutls_cipher_set_priority, 1, MANY, 0,
+       doc: /* Sets the priority on the bulk ciphers supported by GNU TLS for PROCESS.
+The first argument must be a process.  Subsequent arguments should
+be integers.  Priority is higher for protocols specified before
+others.  Note that the priority is set on the client.  The server does
+not use the protocols's priority except for disabling protocols that
+were not specified. */)
+  (int nargs, Lisp_Object *args)
+{
+  Lisp_Object ret;
+
+  ret = generic_set_priority (&gnutls_cipher_set_priority, nargs, args);
+  
+  return ret;
+}
+
+DEFUN ("gnutls-compression-set-priority", Fgnutls_compression_set_priority, 
+       Sgnutls_compression_set_priority, 1, MANY, 0,
+       doc: /* Sets the priority on compression algorithms supported by GNU TLS for PROCESS.
+The first argument must be a process.  Subsequent arguments should
+be integers.  Priority is higher for protocols specified before
+others.  Note that the priority is set on the client.  The server does
+not use the protocols's priority except for disabling protocols that
+were not specified. */)
+  (int nargs, Lisp_Object *args)
+{
+  Lisp_Object ret;
+
+  ret = generic_set_priority (&gnutls_compression_set_priority, nargs, args);
+  
+  return ret;
+}
+
+DEFUN ("gnutls-kx-set-priority", Fgnutls_kx_set_priority, 
+       Sgnutls_kx_set_priority, 1, MANY, 0,
+       doc: /* Sets the priority on key exchange algorithms supported by GNU TLS for PROCESS.
+The first argument must be a process.  Subsequent arguments should
+be integers.  Priority is higher for protocols specified before
+others.  Note that the priority is set on the client.  The server does
+not use the protocols's priority except for disabling protocols that
+were not specified. */)
+  (int nargs, Lisp_Object *args)
+{
+  Lisp_Object ret;
+
+  ret = generic_set_priority (&gnutls_kx_set_priority, nargs, args);
+
+  return ret;
+}
+
+DEFUN ("gnutls-mac-set-priority", Fgnutls_mac_set_priority, 
+       Sgnutls_mac_set_priority, 1, MANY, 0,
+       doc: /* Sets the priority on MAC algorithms supported by GNU TLS for PROCESS.
+The first argument must be a process.  Subsequent arguments should
+be integers.  Priority is higher for protocols specified before
+others.  Note that the priority is set on the client.  The server does
+not use the protocols's priority except for disabling protocols that
+were not specified. */)
+  (int nargs, Lisp_Object *args)
+{
+  Lisp_Object ret;
+
+  ret = generic_set_priority (&gnutls_mac_set_priority, nargs, args);
+  
+  return ret;
+}
+
+/* BROKEN: can't figure out how to use this */
+// DEFUN ("gnutls-x509pki-set-client-cert-callback", 
+//	  Fgnutls_x509pki_set_client_cert_callback, 
+//	  Sgnutls_x509pki_set_client_cert_callback, 2, 2, 0,
+//	  doc: /* XXX Not completely implemented yet. */)
+//	(proc, callback)
+//	Lisp_Object proc, callback;
+// {
+//   gnutls_certificate_credentials_t x509_cred;
+//   Lisp_Object lret;
+//   int ret;
+
+//   CHECK_PROCESS (proc);
+//   x509_cred = (gnutls_certificate_credentials_t) XPROCESS(proc)->x509_cred;
+
+//   XPROCESS(proc)->x509_callback = callback;
+//   gnutls_x509pki_set_client_cert_callback (x509_cred, &gnutls_callback);
+
+//   return Qnil;
+// }
+
+DEFUN ("gnutls-x509pki-set-client-key-file", 
+       Fgnutls_x509pki_set_client_key_file,
+       Sgnutls_x509pki_set_client_key_file, 3, 3, 0,
+       doc: /* Set X.509 client credentials for PROCESS
+CERTFILE is a PEM encoded file containing the certificate list (path)
+for the specified private key. KEYFILE is a PEM encoded file
+containing a private key.  Returns zero on success.
+
+This function may be called more than once (in case multiple
+keys/certificates exist for the server).
+
+Currently only PKCS-1 PEM encoded RSA private keys are accepted by
+this function. */)
+  (Lisp_Object proc, Lisp_Object certfile, Lisp_Object keyfile)
+{
+  gnutls_session_t state;
+  gnutls_certificate_credentials_t x509_cred;
+  Lisp_Object lret;
+  int ret;
+
+  CHECK_STRING(certfile);
+  CHECK_STRING(keyfile);
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  x509_cred = (gnutls_certificate_credentials_t) XPROCESS(proc)->x509_cred;
+
+  ret = gnutls_x509pki_set_client_key_file (x509_cred, 
+					    XSTRING (certfile)->data, 
+					    XSTRING (keyfile)->data);
+
+  XSETINT (lret, ret);
+  return lret;
+}
+
+DEFUN ("gnutls-x509pki-set-client-trust-file", 
+       Fgnutls_x509pki_set_client_trust_file,
+       Sgnutls_x509pki_set_client_trust_file, 3, 3, 0,
+       doc: /* Set X.509 trusted credentials for PROCESS
+CAFILE is a PEM encoded file containing trusted CAs. CRLFILE is a PEM
+encoded file containing CRLs (ignored for now). Returns zero on
+success. */)
+  (Lisp_Object proc, Lisp_Object cafile, Lisp_Object crlfile)
+{
+  gnutls_session_t state;
+  gnutls_certificate_credentials_t x509_cred;
+  Lisp_Object lret;
+  int ret;
+
+  CHECK_STRING(cafile);
+  CHECK_STRING(crlfile);
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  x509_cred = (gnutls_certificate_credentials_t) XPROCESS(proc)->x509_cred;
+
+  ret = gnutls_x509pki_set_client_trust_file (x509_cred, 
+					    NILP (cafile) ? NULL : 
+					    XSTRING (cafile)->data,
+					    NILP (crlfile) ? NULL : 
+					    XSTRING (crlfile)->data);
+
+  XSETINT (lret, ret);
+  return lret;
+}
+
+DEFUN ("gnutls-srp-set-client-cred", Fgnutls_srp_set_client_cred,
+       Sgnutls_srp_set_client_cred, 3, 3, 0,
+       doc: /* Set SRP username and password for PROCESS.  
+PROCESS must be a process. USERNAME is the user's userid. PASSWORD is
+the user's password. Returns zero on success. */)
+  (Lisp_Object proc, Lisp_Object username, Lisp_Object password)
+{
+  gnutls_session_t state;
+  gnutls_srp_client_credentials_t srp_cred;
+  Lisp_Object lret;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  srp_cred = (gnutls_srp_client_credentials_t) XPROCESS(proc)->srp_cred;
+
+  ret = gnutls_srp_set_client_credentials (srp_cred,
+					   NILP (username) ? NULL :
+					   XSTRING(username)->data, 
+					   NILP (password) ? NULL :
+					   XSTRING(password)->data);
+
+  XSETINT (lret, ret);
+  return lret;
+}
+
+DEFUN ("gnutls-anon-set-client-cred", Fgnutls_anon_set_client_cred,
+       Sgnutls_anon_set_client_cred, 2, 2, 0,
+       doc: /* Set the number of bits to use in anonymous Diffie-Hellman exchange for PROCESS.
+DH_BITS is the number of bits in DH key exchange. Returns zero on
+success. */)
+  (Lisp_Object proc, Lisp_Object dh_bits)
+{
+  gnutls_session_t state;
+  gnutls_anon_client_credentials_t anon_cred;
+  Lisp_Object lret;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  anon_cred = (gnutls_anon_client_credentials_t) XPROCESS(proc)->anon_cred;
+
+  ret = gnutls_anon_set_client_dh_params (anon_cred, XINT(dh_bits));
+
+  XSETINT (lret, ret);
+  return lret;
+}
+
+DEFUN ("gnutls-cred-set", Fgnutls_cred_set, 
+       Sgnutls_cred_set, 2, 2, 0,
+       doc: /* Enables GNU TLS authentication for PROCESS.
+TYPE is an integer indicating the type of the credentials, either
+`gnutls-anon', `gnutls-srp' or `gnutls-x509pki'.
+
+Each authentication type may need additional information in order to
+work.  For anonymous (`gnutls-anon'), see also
+`gnutls-anon-set-client-cred'.  For SRP (`gnutls-srp'), see also
+`gnutls-srp-set-client-cred'.  For X.509 PKI (`gnutls-x509pki'), see
+also `gnutls-x509pki-set-client-trust-file',
+`gnutls-x509pki-set-client-key-file', and
+`gnutls-x509pki-set-cert-callback'. */)
+  (Lisp_Object proc, Lisp_Object type)
+{
+  gnutls_session_t state;
+  gnutls_certificate_credentials_t x509_cred;
+  gnutls_anon_client_credentials_t anon_cred;
+  gnutls_srp_client_credentials_t srp_cred;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  x509_cred = (gnutls_certificate_client_credentials) XPROCESS(proc)->x509_cred;
+  anon_cred = (gnutls_anon_client_credentials_t) XPROCESS(proc)->anon_cred;
+  srp_cred = (gnutls_srp_client_credentials_t) XPROCESS(proc)->srp_cred;
+
+  switch (XINT (type))
+    {
+    case GNUTLS_CRD_CERTIFICATE: 
+      if (gnutls_crd_allocate_client_credentials (&x509_cred, 1) < 0)
+	memory_full ();
+      ret = gnutls_cred_set (state, GNUTLS_CRD_CERTIFICATE, x509_cred);
+      break;
+
+    case GNUTLS_CRD_ANON:
+      if (gnutls_anon_allocate_client_credentials (&anon_cred) < 0)
+	memory_full ();
+      ret = gnutls_cred_set (state, GNUTLS_CRD_ANON, anon_cred);
+      break;
+
+    case GNUTLS_CRD_SRP:
+      if (gnutls_srp_allocate_client_credentials (&srp_cred) < 0)
+	memory_full ();
+      ret = gnutls_cred_set (state, GNUTLS_CRD_SRP, srp_cred);
+      break;
+    }
+
+  return XINT(ret);
+}
+
+DEFUN ("gnutls-bye", Fgnutls_bye, 
+       Sgnutls_bye, 2, 2, 0,
+       doc: /* Terminate current GNU TLS connection for PROCESS.
+The connection should have been initiated using gnutls_handshake().
+HOW should be one of `gnutls-shut-rdwr', `gnutls-shut-wr'.
+
+In case of `gnutls-shut-rdwr' then the TLS connection gets terminated
+and further receives and sends will be disallowed. If the return value
+is zero you may continue using the connection.  `gnutls-shut-rdwr'
+actually sends an alert containing a close request and waits for the
+peer to reply with the same message.
+  
+In case of `gnutls-shut-wr' then the TLS connection gets terminated
+and further sends will be disallowed. In order to reuse the connection
+you should wait for an EOF from the peer.  `gnutls-shut-wr' sends an
+alert containing a close request.
+  
+This function may also return `gnutls-e-again', or
+`gnutls-e-interrupted'. */)
+  (Lisp_Object proc, Lisp_Object how)
+{
+  gnutls_session_t state;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  CHECK_NUMBER (how);
+
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  ret = gnutls_bye(state, XFASTINT(how));
+  
+  return XINT(ret);
+}
+
+DEFUN ("gnutls-handshake", Fgnutls_handshake, 
+       Sgnutls_handshake, 1, 1, 0,
+       doc: /* Perform GNU TLS handshake for PROCESS.
+The identity of the peer is checked automatically.  This function will
+fail if any problem is encountered, and will return a negative error
+code. In case of a client, if it has been asked to resume a session,
+but the server didn't, then a full handshake will be performed.
+  
+This function may also return the non-fatal errors `gnutls-e-again',
+or `gnutls-e-interrupted'. In that case you may resume the handshake
+(by calling this function again). */)
+  (Lisp_Object proc)
+{
+  gnutls_session_t state;
+  Lisp_Object lret;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  gnutls_transport_set_ptr( state, XPROCESS(proc)->infd);
+  ret = gnutls_handshake( state);
+  XSETINT(lret, ret);
+  
+  return lret;
+}
+
+DEFUN ("gnutls-rehandshake", Fgnutls_rehandshake, 
+       Sgnutls_rehandshake, 1, 1, 0,
+       doc: /* Renegotiate GNU TLS security parameters for PROCESS.
+This function will renegotiate security parameters with the
+client. This should only be called in case of a server.
+
+This message informs the peer that we want to renegotiate parameters
+\(perform a handshake).
+  
+If this function succeeds (returns 0), you must call the
+gnutls_handshake() function in order to negotiate the new parameters.
+  
+If the client does not wish to renegotiate parameters he will reply
+with an alert message, thus the return code will be
+`gnutls-e-warning-alert-received' and the alert will be
+`gnutls-e-no-renegotiation'. */)
+  (Lisp_Object proc)
+{
+  gnutls_session_t state;
+  Lisp_Object lret;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  gnutls_transport_set_ptr( state, XPROCESS(proc)->infd);
+  ret = gnutls_rehandshake( state);
+  XSETINT(lret, ret);
+  
+  return lret;
+}
+#endif
+
+\f
+
 static int add_gpm_wait_descriptor_called_flag;
 
 void
@@ -7708,6 +8272,25 @@
   defsubr (&Sprocess_coding_system);
   defsubr (&Sset_process_filter_multibyte);
   defsubr (&Sprocess_filter_multibyte_p);
+#ifdef HAVE_GNUTLS
+  defsubr (&Sgnutls_global_init);
+  defsubr (&Sgnutls_global_deinit);
+  defsubr (&Sgnutls_init);
+  defsubr (&Sgnutls_deinit);
+  defsubr (&Sgnutls_protocol_set_priority);
+  defsubr (&Sgnutls_cipher_set_priority);
+  defsubr (&Sgnutls_compression_set_priority);
+  defsubr (&Sgnutls_kx_set_priority);
+  defsubr (&Sgnutls_mac_set_priority);
+  defsubr (&Sgnutls_cred_set);
+  defsubr (&Sgnutls_handshake);
+  defsubr (&Sgnutls_rehandshake);
+  defsubr (&Sgnutls_x509pki_set_client_key_file);
+  defsubr (&Sgnutls_x509pki_set_client_trust_file);
+  defsubr (&Sgnutls_srp_set_client_cred);
+  defsubr (&Sgnutls_anon_set_client_cred);
+  defsubr (&Sgnutls_bye);
+#endif /* HAVE_GNUTLS */
 
 #endif	/* subprocesses */
 

=== modified file 'src/process.h'
--- src/process.h	2010-08-11 12:34:46 +0000
+++ src/process.h	2010-08-12 22:35:18 +0000
@@ -121,6 +121,14 @@
        needs to be synced to `status'.  */
     unsigned int raw_status_new : 1;
     int raw_status;
+
+#ifdef HAVE_GNUTLS
+    /* XXX Store GNU TLS state and auth mechanisms in Lisp_Objects. */
+    Lisp_Object gnutls_state;
+    Lisp_Object x509_cred, x509_callback;
+    Lisp_Object anon_cred;
+    Lisp_Object srp_cred;
+#endif
 };
 
 /* Every field in the preceding structure except for the first two


[-- Attachment #3: gnutls.el --]
[-- Type: application/emacs-lisp, Size: 5389 bytes --]

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-08-13 17:25                   ` Ted Zlatanov
@ 2010-08-14  0:15                     ` Chong Yidong
  2010-09-05  4:57                       ` Ted Zlatanov
  0 siblings, 1 reply; 93+ messages in thread
From: Chong Yidong @ 2010-08-14  0:15 UTC (permalink / raw)
  To: Ted Zlatanov; +Cc: emacs-devel

Ted Zlatanov <tzz@lifelogs.com> writes:

> Simon's code included a gnutls.el library, attached here.  It shows how
> to use it.

OK, that makes sense.  Though I feel queasy about this:

  (defconst gnutls-cipher-null 1)
  (defconst gnutls-cipher-arcfour 2)
  ...

being intended to map to

  typedef enum gnutls_cipher_algorithm
  {
    GNUTLS_CIPHER_UNKNOWN = 0,
    GNUTLS_CIPHER_NULL = 1,
    GNUTLS_CIPHER_ARCFOUR_128,
    ...

from gnutls.h.  The more Emacs-Lisp-y approach is to let the gnutls-*
built-in functions accept symbols rather than integers, i.e. instead of

   (gnutls-protocol-set-priority proc gnutls-tls1 gnutls-ssl3)

it should be called as

   (gnutls-protocol-set-priority proc 'gnutls-tls1 'gnutls-ssl3),

and `gnutls-protocol-set-priority' should internally convert those
symbol arguments to GNUTLS_SSL3 and GNUTLS_TLS1, and pass them to the
GnuTLS function gnutls_protocol_set_priority.

I think this can be done by taking Fsymbol_name of each argument, and
using the accessor functionss provided by the GnuTLS library, e.g.
`gnutls_protocol_get_id'.  (We thus avoid defining many dozens of Lisp
symbols beforehand, like Qssl3, Qtls1, etc.).  We can also be fancy, by
not requiring the `gnutls' part of the symbol argument and appending it
in the C code:

   (gnutls-protocol-set-priority proc 'tls1 'ssl3)

I realize this is a rather invasive change to the patch.  I suggest
separating the GnuTLS code into a separate file, gnutls.c, adding it to
the Emacs repository, and work from there.  Then you don't have to keep
sending the patch to the mailing list.



^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-08-13 14:50               ` Ted Zlatanov
@ 2010-08-14 19:20                 ` Leo
  0 siblings, 0 replies; 93+ messages in thread
From: Leo @ 2010-08-14 19:20 UTC (permalink / raw)
  To: emacs-devel

On 2010-08-13 15:50 +0100, Ted Zlatanov wrote:
> L> BTW, I remembered seeing rms OK the ffi feature. I wonder if
> L> there's a plan for this. It would open up a new world of
> L> applications for emacs. For example, at the moment emacs lacks a
> L> (good) English grammar checker.
>
> I would not want SSL support to be pluggable :) But yes, I think
> generally it will make Emacs much better to have binary extensions.

I am glad this is receiving more attention ;)

Regards,
Leo




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-08-14  0:15                     ` Chong Yidong
@ 2010-09-05  4:57                       ` Ted Zlatanov
  2010-09-05  8:06                         ` Andreas Schwab
  2010-09-05 22:47                         ` Stefan Monnier
  0 siblings, 2 replies; 93+ messages in thread
From: Ted Zlatanov @ 2010-09-05  4:57 UTC (permalink / raw)
  To: emacs-devel; +Cc: gnutls-devel

[-- Attachment #1: Type: text/plain, Size: 2054 bytes --]

On Fri, 13 Aug 2010 20:15:30 -0400 Chong Yidong <cyd@stupidchicken.com> wrote: 

CY> instead of

CY>    (gnutls-protocol-set-priority proc gnutls-tls1 gnutls-ssl3)

CY> it should be called as

CY>    (gnutls-protocol-set-priority proc 'gnutls-tls1 'gnutls-ssl3),
...
CY> I realize this is a rather invasive change to the patch.  I suggest
CY> separating the GnuTLS code into a separate file, gnutls.c, adding it to
CY> the Emacs repository, and work from there.

CY> Then you don't have to keep sending the patch to the mailing list.

Simon Josefsson had the suggestion that I use the string version of the
priority set and I did.  That reduces the need for this change greatly;
please take a look at gnutls.el.  There's only 

(defconst gnutls-x509pki 1)
(defconst gnutls-anon 2)
(defconst gnutls-srp 3)

for which there's actually no get_id function to look the credentials
type by name in GnuTLS.  So if that's the only thing we need to #define,
I'd rather not do anything fancy and just handle it explicitly in
`gnutls-cred-set'.

Note I've never worked with the Emacs internals at this depth so I did
not commit any of my changes to the Emacs repo and will not until you or
Stefan Monnier say it's OK.

I changed lisp.h and emacs.c to call syms_of_gnutls() and made other
changes so the patch compiles cleanly and the functions are available.
It's far from ready (it won't do anything but crash emacs) but at least
it won't break the build and doesn't affect anything else.  So it's
attached here for structural review more than any real testing.

Everything in gnutls.c that's commented out is for reference only and I
don't think will be back.  I think we should start without SRP support
and generally do just enough to get SSL and TLS to work in the simplest
cases.  When those cases work we can proceed to the fancier uses.  So
that's the current aim of the patch.

Also I think trying to make gnutls.el a drop-in replacement for
starttls.el is not a good idea.  I'd rather make it a standalone library
so we can make the API fit better.

Ted


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: tls.patch --]
[-- Type: text/x-diff, Size: 27942 bytes --]

=== modified file 'configure.in'
--- configure.in	2010-08-23 12:54:09 +0000
+++ configure.in	2010-09-05 04:42:32 +0000
@@ -170,6 +170,7 @@
 OPTION_DEFAULT_ON([dbus],[don't compile with D-Bus support])
 OPTION_DEFAULT_ON([gconf],[don't compile with GConf support])
 OPTION_DEFAULT_ON([selinux],[don't compile with SELinux support])
+OPTION_DEFAULT_ON([gnutls],[don't use -lgnutls for SSL/TLS support])
 
 ## For the times when you want to build Emacs but don't have
 ## a suitable makeinfo, and can live without the manuals.
@@ -1998,6 +1999,13 @@
 fi
 AC_SUBST(LIBSELINUX_LIBS)
 
+HAVE_GNUTLS=no
+if test "${with_gnutls}" = "yes" ; then
+  PKG_CHECK_MODULES([LIBGNUTLS], [gnutls >= 2.2.4])
+  AC_DEFINE(HAVE_GNUTLS)
+  HAVE_GNUTLS=yes
+fi
+
 dnl Do not put whitespace before the #include statements below.
 dnl Older compilers (eg sunos4 cc) choke on it.
 HAVE_XAW3D=no
@@ -3682,6 +3690,7 @@
 echo "  Does Emacs use -ldbus?                                  ${HAVE_DBUS}"
 echo "  Does Emacs use -lgconf?                                 ${HAVE_GCONF}"
 echo "  Does Emacs use -lselinux?                               ${HAVE_LIBSELINUX}"
+echo "  Does Emacs use Gnu TLS?                                 ${HAVE_GNUTLS}"
 
 echo "  Does Emacs use -lfreetype?                              ${HAVE_FREETYPE}"
 echo "  Does Emacs use -lm17n-flt?                              ${HAVE_M17N_FLT}"

=== added file 'lisp/net/gnutls.el'
--- lisp/net/gnutls.el	1970-01-01 00:00:00 +0000
+++ lisp/net/gnutls.el	2010-09-05 04:42:32 +0000
@@ -0,0 +1,120 @@
+;; By Simon Josefsson 2001-12-01
+;; See http://josefsson.org/emacs-security/
+
+;; Simple test:
+;;
+;; (setq jas (open-ssl-stream "ssl" (current-buffer) "www.pdc.kth.se" 443))
+;; (process-send-string jas "GET /\r\n\r\n")
+
+(defconst gnutls-version "0.3.1")
+
+(defconst gnutls-server 1)
+(defconst gnutls-client 2)
+
+(defconst gnutls-x509pki 1)
+(defconst gnutls-anon 2)
+(defconst gnutls-srp 3)
+
+(defconst gnutls-shut-rdwr 0)
+(defconst gnutls-shut-wr 1)
+
+(defconst gnutls-e-interrupted -52)
+(defconst gnutls-e-again -28)
+
+(defun open-ssl-stream (name buffer host service)
+  "Open a SSL connection for a service to a host.
+Returns a subprocess-object to represent the connection.
+Input and output work as for subprocesses; `delete-process' closes it.
+Args are NAME BUFFER HOST SERVICE.
+NAME is name for process.  It is modified if necessary to make it unique.
+BUFFER is the buffer (or buffer-name) to associate with the process.
+ Process output goes at end of that buffer, unless you specify
+ an output stream or filter function to handle the output.
+ BUFFER may be also nil, meaning that this process is not associated
+ with any buffer
+Third arg is name of the host to connect to, or its IP address.
+Fourth arg SERVICE is name of the service desired, or an integer
+specifying a port number to connect to."
+  (let ((proc (open-network-stream name buffer host service)))
+    (starttls-negotiate proc)))
+
+(defvar starttls-host nil)
+
+(defun starttls-negotiate (proc &optional priority-string
+                                credentials credentials-file)
+  "Negotiate a SSL or TLS connection.
+PRIORITY-STRING is as per the GnuTLS docs.
+CREDENTIALS is `gnutls-x509pki', `gnutls-anon', or `gnutls-srp'.
+CREDENTIALS-FILE is a filename with meaning dependent on CREDENTIALS."
+  (let* ((credentials (or credentials gnutls-anon))
+         (priority-string (or priority-string
+                              (cond
+                               ((eq credentials gnutls-anon)
+                                "PERFORMANCE:+ANON-DH:!ARCFOUR-128")
+                               ((eq credentials gnutls-x509pki)
+                               "PERFORMANCE")))))
+    (gnutls-message-maybe
+     (gnutls-global-init)
+     "global_init: err=%s")
+
+    (gnutls-message-maybe
+     (gnutls-init proc gnutls-client)
+     "init: err=%s")
+
+    (gnutls-message-maybe
+     (gnutls-priority-set-direct proc priority-string)
+     "priority_set: err=%s")
+
+    (gnutls-message-maybe
+     (gnutls-cred-set proc credentials)
+     "credential_set: err=%s")
+
+    (cond
+     ((eq credentials gnutls-x509pki)
+      (gnutls-message-maybe
+       (gnutls-cert-set-x509-trust-file proc credentials-file)
+       "x509_trustfile: err=%s")))
+
+    (let ((ret gnutls-e-again))
+      (while (or (eq ret gnutls-e-again)
+                 (eq ret gnutls-e-interrupted))
+        (gnutls-message-maybe
+         (setq ret (gnutls-handshake proc))
+         "handshake: err=%s"))
+      (if (< ret 0)
+          (progn
+            (message "Ouch, error return %d" ret)
+            (setq proc nil))
+        (message "Handshake complete %d." ret)))
+     proc))
+
+(defun starttls-open-stream (name buffer host service)
+  "Open a TLS connection for a service to a host.
+Returns a subprocess-object to represent the connection.
+Input and output work as for subprocesses; `delete-process' closes it.
+Args are NAME BUFFER HOST SERVICE.
+NAME is name for process.  It is modified if necessary to make it unique.
+BUFFER is the buffer (or `buffer-name') to associate with the process.
+ Process output goes at end of that buffer, unless you specify
+ an output stream or filter function to handle the output.
+ BUFFER may be also nil, meaning that this process is not associated
+ with any buffer
+Third arg is name of the host to connect to, or its IP address.
+Fourth arg SERVICE is name of the service desired, or an integer
+specifying a port number to connect to."
+  (prog1
+      (open-network-stream name buffer host service)
+    (set (make-variable-buffer-local 'starttls-host) host)))
+
+(defun gnutls-message-maybe (doit format &rest params)
+  "When DOIT, message with the caller name followed by FORMAT on PARAMS."
+  (message "%s: (err=%s) %s"
+           (nth 1 (backtrace-frame 4))
+           doit
+           (apply 'format format params)))
+
+(provide 'ssl)
+(provide 'gnutls)
+(provide 'starttls)
+
+;;; gnutls.el ends here

=== modified file 'src/Makefile.in'
--- src/Makefile.in	2010-08-17 21:19:11 +0000
+++ src/Makefile.in	2010-09-05 04:42:32 +0000
@@ -285,6 +285,9 @@
 
 LIBSELINUX_LIBS = @LIBSELINUX_LIBS@
 
+LIBGNUTLS_LIBS = @LIBGNUTLS_LIBS@
+LIBGNUTLS_CFLAGS = @LIBGNUTLS_CFLAGS@
+
 INTERVALS_H = dispextern.h intervals.h composite.h
 
 GETLOADAVG_LIBS = @GETLOADAVG_LIBS@
@@ -323,6 +326,7 @@
   ${C_SWITCH_X_SYSTEM} ${CFLAGS_SOUND} ${RSVG_CFLAGS} ${IMAGEMAGICK_CFLAGS} ${DBUS_CFLAGS} \
   ${GCONF_CFLAGS} ${FREETYPE_CFLAGS} ${FONTCONFIG_CFLAGS} \
   ${LIBOTF_CFLAGS} ${M17N_FLT_CFLAGS} ${DEPFLAGS} ${PROFILING_CFLAGS} \
+  $(LIBGNUTLS_CFLAGS) \
   ${C_WARNINGS_SWITCH} ${CFLAGS}
 ALL_OBJC_CFLAGS=$(ALL_CFLAGS) $(GNU_OBJC_CFLAGS)
 
@@ -347,7 +351,7 @@
 	alloc.o data.o doc.o editfns.o callint.o \
 	eval.o floatfns.o fns.o font.o print.o lread.o \
 	syntax.o $(UNEXEC_OBJ) bytecode.o \
-	process.o callproc.o \
+	process.o gnutls.o callproc.o \
 	region-cache.o sound.o atimer.o \
 	doprnt.o strftime.o intervals.o textprop.o composite.o md5.o \
 	$(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ)
@@ -598,6 +602,7 @@
    $(RSVG_LIBS) ${IMAGEMAGICK_LIBS}  $(DBUS_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \
    $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) ${GCONF_LIBS} ${LIBSELINUX_LIBS} \
    $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
+   $(LIBGNUTLS_LIBS) \
    $(LIB_GCC) $(LIB_MATH) $(LIB_STANDARD) $(LIB_GCC)
 
 all: emacs${EXEEXT} $(OTHER_FILES)

=== modified file 'src/config.in'
--- src/config.in	2010-08-17 21:19:11 +0000
+++ src/config.in	2010-09-05 04:42:32 +0000
@@ -255,6 +255,9 @@
 /* Define to 1 if you have a gif (or ungif) library. */
 #undef HAVE_GIF
 
+/* Define if we have the GNU TLS library.  */
+#undef HAVE_GNUTLS
+
 /* Define to 1 if you have the gpm library (-lgpm). */
 #undef HAVE_GPM
 
@@ -1091,6 +1094,12 @@
 #include config_opsysfile
 #include config_machfile
 
+#if HAVE_GNUTLS
+#define LIBGNUTLS $(LIBGNUTLS_LIBS)
+#else /* not HAVE_GNUTLS */
+#define LIBGNUTLS
+#endif /* not HAVE_GNUTLS */
+
 /* Set up some defines, C and LD flags for NeXTstep interface on GNUstep.
   (There is probably a better place to do this, but right now the Cocoa
    side does this in s/darwin.h and we cannot

=== modified file 'src/emacs.c'
--- src/emacs.c	2010-08-22 21:15:20 +0000
+++ src/emacs.c	2010-09-05 04:42:32 +0000
@@ -63,6 +63,10 @@
 #include "keyboard.h"
 #include "keymap.h"
 
+#ifdef HAVE_GNUTLS
+#include "gnutls.h"
+#endif
+
 #ifdef HAVE_NS
 #include "nsterm.h"
 #endif
@@ -1569,6 +1573,10 @@
       syms_of_fontset ();
 #endif /* HAVE_NS */
 
+#ifdef HAVE_GNUTLS
+      syms_of_gnutls ();
+#endif
+
 #ifdef HAVE_DBUS
       syms_of_dbusbind ();
 #endif /* HAVE_DBUS */

=== added file 'src/gnutls.c'
--- src/gnutls.c	1970-01-01 00:00:00 +0000
+++ src/gnutls.c	2010-09-05 04:42:32 +0000
@@ -0,0 +1,503 @@
+#include <config.h>
+#include <errno.h>
+#include <setjmp.h>
+
+#include "lisp.h"
+#include "process.h"
+
+#ifdef HAVE_GNUTLS
+#include <gnutls/gnutls.h>
+
+int
+emacs_gnutls_write (int fildes, gnutls_session_t state, char *buf,
+                    unsigned int nbyte)
+{
+  register int rtnval, bytes_written;
+
+  puts("emacs_gnutls_write");
+
+  bytes_written = 0;
+
+  while (nbyte > 0)
+    {
+      rtnval = gnutls_write (state, buf, nbyte);
+
+      if (rtnval == -1)
+	{
+	  if (errno == EINTR)
+	    continue;
+	  else
+	    return (bytes_written ? bytes_written : -1);
+	}
+
+      buf += rtnval;
+      nbyte -= rtnval;
+      bytes_written += rtnval;
+    }
+  printf("wrote %d bytes\n", bytes_written);
+  fsync(STDOUT_FILENO);
+
+  return (bytes_written);
+}
+
+int
+emacs_gnutls_read (int fildes, gnutls_session_t state, char *buf,
+                   unsigned int nbyte)
+{
+  register int rtnval;
+
+  puts("emacs_gnutls_read");
+
+  do {
+    rtnval = gnutls_read( state, buf, nbyte);
+    printf("read %d bytes\n", rtnval);
+  } while( rtnval==GNUTLS_E_INTERRUPTED || rtnval==GNUTLS_E_AGAIN);
+  printf("read %d bytes\n", rtnval);
+  fsync(STDOUT_FILENO);
+
+  return (rtnval);
+}
+
+int gnutls_callback (gnutls_session_t state, const gnutls_datum *client_certs,
+                     int ncerts, const gnutls_datum* req_ca_cert, int nreqs)
+{
+  if (client_certs == NULL) {
+    /* means the we will only be called again if the library cannot
+     * determine which certificate to send
+     */
+    return 0;
+  }
+
+  puts("In callback");
+
+  return -1; /* send no certificate to the peer */
+}
+
+DEFUN ("gnutls-init", Fgnutls_init, Sgnutls_init, 2, 2, 0,
+       doc: /* Initializes GNU TLS for process PROC for use as CONNECTION-END.
+CONNECTION-END is used to indicate if this process is as a server or
+client. Can be one of `gnutls-client' and `gnutls-server'.  Currently
+only `gnutls-client' is supported.
+
+Processes must be initialized with this function before other GNU TLS
+functions are used.  This function allocates resources which can only
+be deallocated by calling `gnutls-deinit'. Returns zero on success. */)
+    (Lisp_Object proc, Lisp_Object connection_end)
+{
+  int ret;
+  
+  CHECK_PROCESS (proc);
+
+  ret = gnutls_init((gnutls_session_t*)&(XPROCESS(proc)->gnutls_state), 
+		    connection_end);
+
+  return XINT(ret);
+}
+
+DEFUN ("gnutls-deinit", Fgnutls_deinit, Sgnutls_deinit, 1, 1, 0,
+       doc: /* Deallocate GNU TLS resources associated with PROCESS.
+See also `gnutls-init'. */)
+    (Lisp_Object proc)
+{
+  int ret;
+  gnutls_session_t state;
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  gnutls_deinit(state);
+
+  return Qnil;
+}
+
+DEFUN ("gnutls-global-init", Fgnutls_global_init, 
+       Sgnutls_global_init, 0, 0, 0,
+       doc: /* Initializes global GNU TLS state to defaults.
+Call `gnutls-global-deinit' when GNU TLS usage is no longer needed.
+Returns zero on success. */)
+     (void)
+{
+  Lisp_Object lret;
+  int ret;
+
+  ret = gnutls_global_init();
+  XSETINT (lret, ret);
+
+  return lret;
+}
+
+DEFUN ("gnutls-global-deinit", Fgnutls_global_deinit, 
+       Sgnutls_global_deinit, 0, 0, 0,
+       doc: /* Deinitializes global GNU TLS state.
+See also `gnutls-global-init'. */)
+     (void)
+{
+  gnutls_global_deinit();
+
+  return Qnil;
+}
+
+Lisp_Object
+generic_set_priority (int (*func)( gnutls_session_t state, const char*, const char**),
+                      Lisp_Object proc, Lisp_Object priority_string)
+{
+  Lisp_Object lret;
+  gnutls_session_t state;
+  int ret;
+  
+  CHECK_PROCESS (proc);
+  CHECK_STRING(priority_string);
+  
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  ret = (*func) (state, (char*) SDATA (priority_string), NULL);
+
+  XSETINT (lret, ret);
+  return lret;
+}
+
+DEFUN ("gnutls-priority-set-direct", Fgnutls_priority_set_direct, 
+       Sgnutls_priority_set_direct, 2, 2, 0,
+       doc: /* Sets the priority on the protocol versions supported by GNU TLS for PROCESS.
+
+The first parameter must be a process. Second parameter is a string
+describing the priority.  Note that the priority is set on the client.
+The server does not use the protocols's priority except for disabling
+protocols that were not specified. */)
+    (Lisp_Object process, Lisp_Object priority_string)
+{
+  Lisp_Object ret;
+
+  ret = generic_set_priority (&gnutls_priority_set_direct, process, priority_string);
+  
+  return ret;
+}
+
+DEFUN ("gnutls-cert-set-x509-trust-file", 
+       Fgnutls_cert_set_x509_trust_file,
+       Sgnutls_cert_set_x509_trust_file, 2, 2, 0,
+       doc: /* Set X.509 client trust file for PROCESS
+CERTFILE is a PEM encoded file.  Returns zero on success.
+*/)
+    (Lisp_Object proc, Lisp_Object certfile)
+{
+  gnutls_session_t state;
+  gnutls_certificate_credentials_t x509_cred;
+  Lisp_Object lret;
+  int ret;
+
+  CHECK_STRING(certfile);
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  x509_cred = (gnutls_certificate_credentials_t) XPROCESS(proc)->x509_cred;
+
+  ret = gnutls_certificate_set_x509_trust_file (x509_cred, XSTRING (certfile)->data, GNUTLS_X509_FMT_PEM);
+
+  XSETINT (lret, ret);
+  return lret;
+}
+
+DEFUN ("gnutls-cred-set", Fgnutls_cred_set, 
+       Sgnutls_cred_set, 2, 2, 0,
+       doc: /* Enables GNU TLS authentication for PROCESS.
+TYPE is an integer indicating the type of the credentials, either
+`gnutls-anon', `gnutls-srp' or `gnutls-x509pki'.
+
+Each authentication type may need additional information in order to
+work.  For anonymous (`gnutls-anon'), see also
+`gnutls-anon-set-client-cred'.	For SRP (`gnutls-srp'), see also
+`gnutls-srp-set-client-cred'.  For X.509 PKI (`gnutls-x509pki'), see
+also `gnutls-x509pki-set-client-trust-file',
+`gnutls-x509pki-set-client-key-file', and
+`gnutls-x509pki-set-cert-callback'. */)
+    (Lisp_Object proc, Lisp_Object type)
+{
+  gnutls_session_t state;
+  gnutls_certificate_credentials_t x509_cred;
+  gnutls_anon_client_credentials_t anon_cred;
+  gnutls_srp_client_credentials_t srp_cred;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  x509_cred = (gnutls_certificate_client_credentials) XPROCESS(proc)->x509_cred;
+  anon_cred = (gnutls_anon_client_credentials_t) XPROCESS(proc)->anon_cred;
+  srp_cred = (gnutls_srp_client_credentials_t) XPROCESS(proc)->srp_cred;
+
+  switch (XINT (type))
+    {
+    case GNUTLS_CRD_CERTIFICATE: 
+      if (gnutls_certificate_allocate_credentials (&x509_cred) < 0)
+	memory_full ();
+      ret = gnutls_cred_set (state, GNUTLS_CRD_CERTIFICATE, x509_cred);
+      break;
+
+    case GNUTLS_CRD_ANON:
+      if (gnutls_anon_allocate_client_credentials (&anon_cred) < 0)
+	memory_full ();
+      ret = gnutls_cred_set (state, GNUTLS_CRD_ANON, anon_cred);
+      break;
+
+    // case GNUTLS_CRD_SRP:
+    //   if (gnutls_srp_allocate_client_credentials (&srp_cred) < 0)
+    //     memory_full ();
+    //   ret = gnutls_cred_set (state, GNUTLS_CRD_SRP, srp_cred);
+    //   break;
+    }
+
+  return XINT(ret);
+}
+
+DEFUN ("gnutls-bye", Fgnutls_bye, 
+       Sgnutls_bye, 2, 2, 0,
+       doc: /* Terminate current GNU TLS connection for PROCESS.
+The connection should have been initiated using gnutls_handshake().
+HOW should be one of `gnutls-shut-rdwr', `gnutls-shut-wr'.
+
+In case of `gnutls-shut-rdwr' then the TLS connection gets terminated
+and further receives and sends will be disallowed. If the return value
+is zero you may continue using the connection.	`gnutls-shut-rdwr'
+actually sends an alert containing a close request and waits for the
+peer to reply with the same message.
+  
+In case of `gnutls-shut-wr' then the TLS connection gets terminated
+and further sends will be disallowed. In order to reuse the connection
+you should wait for an EOF from the peer.  `gnutls-shut-wr' sends an
+alert containing a close request.
+  
+This function may also return `gnutls-e-again', or
+`gnutls-e-interrupted'. */)
+    (Lisp_Object proc, Lisp_Object how)
+{
+  gnutls_session_t state;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  CHECK_NUMBER (how);
+
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  ret = gnutls_bye(state, XFASTINT(how));
+  
+  return XINT(ret);
+}
+
+DEFUN ("gnutls-handshake", Fgnutls_handshake, 
+       Sgnutls_handshake, 1, 1, 0,
+       doc: /* Perform GNU TLS handshake for PROCESS.
+The identity of the peer is checked automatically.  This function will
+fail if any problem is encountered, and will return a negative error
+code. In case of a client, if it has been asked to resume a session,
+but the server didn't, then a full handshake will be performed.
+  
+This function may also return the non-fatal errors `gnutls-e-again',
+or `gnutls-e-interrupted'. In that case you may resume the handshake
+(by calling this function again). */)
+    (Lisp_Object proc)
+{
+  gnutls_session_t state;
+  Lisp_Object lret;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  gnutls_transport_set_ptr( state, XPROCESS(proc)->infd);
+  ret = gnutls_handshake( state);
+  XSETINT(lret, ret);
+  
+  return lret;
+}
+
+DEFUN ("gnutls-rehandshake", Fgnutls_rehandshake, 
+       Sgnutls_rehandshake, 1, 1, 0,
+       doc: /* Renegotiate GNU TLS security parameters for PROCESS.
+This function will renegotiate security parameters with the
+client. This should only be called in case of a server.
+
+This message informs the peer that we want to renegotiate parameters
+\(perform a handshake).
+  
+If this function succeeds (returns 0), you must call the
+gnutls_handshake() function in order to negotiate the new parameters.
+  
+If the client does not wish to renegotiate parameters he will reply
+with an alert message, thus the return code will be
+`gnutls-e-warning-alert-received' and the alert will be
+`gnutls-e-no-renegotiation'. */)
+    (Lisp_Object proc)
+{
+  gnutls_session_t state;
+  Lisp_Object lret;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+  gnutls_transport_set_ptr( state, XPROCESS(proc)->infd);
+  ret = gnutls_rehandshake( state);
+  XSETINT(lret, ret);
+  
+  return lret;
+}
+
+// DEFUN ("gnutls-x509pki-set-client-cert-callback", 
+//	  Fgnutls_x509pki_set_client_cert_callback, 
+//	  Sgnutls_x509pki_set_client_cert_callback, 2, 2, 0,
+//	  doc: /* XXX Not completely implemented yet. */)
+//	(proc, callback)
+//	Lisp_Object proc, callback;
+// {
+//   gnutls_certificate_credentials_t x509_cred;
+//   Lisp_Object lret;
+//   int ret;
+
+//   CHECK_PROCESS (proc);
+//   x509_cred = (gnutls_certificate_credentials_t) XPROCESS(proc)->x509_cred;
+
+//   XPROCESS(proc)->x509_callback = callback;
+//   gnutls_x509pki_set_client_cert_callback (x509_cred, &gnutls_callback);
+
+//   return Qnil;
+// }
+
+// DEFUN ("gnutls-x509pki-set-client-key-file", 
+//        Fgnutls_x509pki_set_client_key_file,
+//        Sgnutls_x509pki_set_client_key_file, 3, 3, 0,
+//        doc: /* Set X.509 client credentials for PROCESS
+// CERTFILE is a PEM encoded file containing the certificate list (path)
+// for the specified private key. KEYFILE is a PEM encoded file
+// containing a private key.  Returns zero on success.
+
+// This function may be called more than once (in case multiple
+// keys/certificates exist for the server).
+
+// Currently only PKCS-1 PEM encoded RSA private keys are accepted by
+// this function. */)
+//     (Lisp_Object proc, Lisp_Object certfile, Lisp_Object keyfile)
+// {
+//   gnutls_session_t state;
+//   gnutls_certificate_credentials_t x509_cred;
+//   Lisp_Object lret;
+//   int ret;
+
+//   CHECK_STRING(certfile);
+//   CHECK_STRING(keyfile);
+
+//   CHECK_PROCESS (proc);
+//   state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+//   x509_cred = (gnutls_certificate_credentials_t) XPROCESS(proc)->x509_cred;
+
+//   ret = gnutls_x509pki_set_client_key_file (x509_cred, 
+// 					    XSTRING (certfile)->data, 
+// 					    XSTRING (keyfile)->data);
+
+//   XSETINT (lret, ret);
+//   return lret;
+// }
+
+// DEFUN ("gnutls-x509pki-set-client-trust-file", 
+//        Fgnutls_x509pki_set_client_trust_file,
+//        Sgnutls_x509pki_set_client_trust_file, 3, 3, 0,
+//        doc: /* Set X.509 trusted credentials for PROCESS
+// CAFILE is a PEM encoded file containing trusted CAs. CRLFILE is a PEM
+// encoded file containing CRLs (ignored for now). Returns zero on
+// success. */)
+//     (Lisp_Object proc, Lisp_Object cafile, Lisp_Object crlfile)
+// {
+//   gnutls_session_t state;
+//   gnutls_certificate_credentials_t x509_cred;
+//   Lisp_Object lret;
+//   int ret;
+
+//   CHECK_STRING(cafile);
+//   CHECK_STRING(crlfile);
+
+//   CHECK_PROCESS (proc);
+//   state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+//   x509_cred = (gnutls_certificate_credentials_t) XPROCESS(proc)->x509_cred;
+
+//   ret = gnutls_x509pki_set_client_trust_file (x509_cred, 
+// 					    NILP (cafile) ? NULL : 
+// 					    XSTRING (cafile)->data,
+// 					    NILP (crlfile) ? NULL : 
+// 					    XSTRING (crlfile)->data);
+
+//   XSETINT (lret, ret);
+//   return lret;
+// }
+
+// DEFUN ("gnutls-srp-set-client-cred", Fgnutls_srp_set_client_cred,
+//        Sgnutls_srp_set_client_cred, 3, 3, 0,
+//        doc: /* Set SRP username and password for PROCESS.  
+// PROCESS must be a process. USERNAME is the user's userid. PASSWORD is
+// the user's password. Returns zero on success. */)
+//     (Lisp_Object proc, Lisp_Object username, Lisp_Object password)
+// {
+//   gnutls_session_t state;
+//   gnutls_srp_client_credentials_t srp_cred;
+//   Lisp_Object lret;
+//   int ret;
+
+//   CHECK_PROCESS (proc);
+//   state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+//   srp_cred = (gnutls_srp_client_credentials_t) XPROCESS(proc)->srp_cred;
+
+//   ret = gnutls_srp_set_client_credentials (srp_cred,
+// 					   NILP (username) ? NULL :
+// 					   XSTRING(username)->data, 
+// 					   NILP (password) ? NULL :
+// 					   XSTRING(password)->data);
+
+//   XSETINT (lret, ret);
+//   return lret;
+// }
+
+// DEFUN ("gnutls-anon-set-client-cred", Fgnutls_anon_set_client_cred,
+//        Sgnutls_anon_set_client_cred, 2, 2, 0,
+//        doc: /* Set the number of bits to use in anonymous Diffie-Hellman exchange for PROCESS.
+// DH_BITS is the number of bits in DH key exchange. Returns zero on 
+// success. */)
+//     (Lisp_Object proc, Lisp_Object dh_bits)
+// {
+//   gnutls_session_t state;
+//   gnutls_anon_client_credentials_t anon_cred;
+//   Lisp_Object lret;
+//   int ret;
+
+//   CHECK_PROCESS (proc);
+//   state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
+
+//   anon_cred = (gnutls_anon_client_credentials_t) XPROCESS(proc)->anon_cred;
+
+//   ret = gnutls_anon_set_client_dh_params (anon_cred, XINT(dh_bits));
+
+//   XSETINT (lret, ret);
+//   return lret;
+// }
+
+void
+syms_of_gnutls (void)
+{
+  defsubr (&Sgnutls_global_init);
+  defsubr (&Sgnutls_global_deinit);
+  defsubr (&Sgnutls_init);
+  defsubr (&Sgnutls_deinit);
+  defsubr (&Sgnutls_priority_set_direct);
+  defsubr (&Sgnutls_cred_set);
+  defsubr (&Sgnutls_handshake);
+  defsubr (&Sgnutls_rehandshake);
+  defsubr (&Sgnutls_cert_set_x509_trust_file);
+  // defsubr (&Sgnutls_x509pki_set_client_key_file);
+  // defsubr (&Sgnutls_x509pki_set_client_trust_file);
+  // defsubr (&Sgnutls_srp_set_client_cred);
+  // defsubr (&Sgnutls_anon_set_client_cred);
+  defsubr (&Sgnutls_bye);
+}
+#endif

=== added file 'src/gnutls.h'
--- src/gnutls.h	1970-01-01 00:00:00 +0000
+++ src/gnutls.h	2010-09-05 04:42:32 +0000
@@ -0,0 +1,4 @@
+#ifdef HAVE_GNUTLS
+#include <gnutls/gnutls.h>
+
+#endif

=== modified file 'src/lisp.h'
--- src/lisp.h	2010-08-09 19:25:41 +0000
+++ src/lisp.h	2010-09-05 04:42:32 +0000
@@ -3350,6 +3350,7 @@
 extern void syms_of_process (void);
 extern void setup_process_coding_systems (Lisp_Object);
 
+
 /* Defined in callproc.c */
 extern Lisp_Object Vexec_path, Vexec_suffixes,
                    Vexec_directory, Vdata_directory;
@@ -3589,6 +3590,11 @@
 void syms_of_dbusbind (void);
 #endif
 
+#ifdef HAVE_GNUTLS
+/* Defined in gnutls.c */
+extern void syms_of_gnutls (void);
+#endif
+
 #ifdef DOS_NT
 /* Defined in msdos.c, w32.c */
 extern char *emacs_root_dir (void);

=== modified file 'src/process.c'
--- src/process.c	2010-08-22 15:14:37 +0000
+++ src/process.c	2010-09-05 04:42:32 +0000
@@ -105,6 +105,9 @@
 #include "sysselect.h"
 #include "syssignal.h"
 #include "syswait.h"
+#ifdef HAVE_GNUTLS
+#include "gnutls.h"
+#endif
 
 #if defined (USE_GTK) || defined (HAVE_GCONF)
 #include "xgselect.h"
@@ -1526,6 +1529,10 @@
   XPROCESS (proc)->filter = Qnil;
   XPROCESS (proc)->command = Flist (nargs - 2, args + 2);
 
+#ifdef HAVE_GNUTLS
+  XPROCESS (proc)->gnutls_state = Qnil;
+#endif
+
 #ifdef ADAPTIVE_READ_BUFFERING
   XPROCESS (proc)->adaptive_read_buffering
     = (NILP (Vprocess_adaptive_read_buffering) ? 0
@@ -5097,7 +5104,12 @@
 #endif
   if (proc_buffered_char[channel] < 0)
     {
-      nbytes = emacs_read (channel, chars + carryover, readmax);
+#ifdef HAVE_GNUTLS
+      if (NETCONN_P(proc) && !NILP (XPROCESS(proc)->gnutls_state))
+	nbytes = emacs_gnutls_read (channel, XPROCESS(proc)->gnutls_state, chars + carryover, readmax);
+      else
+#endif
+	nbytes = emacs_read (channel, chars + carryover, readmax);
 #ifdef ADAPTIVE_READ_BUFFERING
       if (nbytes > 0 && p->adaptive_read_buffering)
 	{
@@ -5130,7 +5142,12 @@
     {
       chars[carryover] = proc_buffered_char[channel];
       proc_buffered_char[channel] = -1;
-      nbytes = emacs_read (channel, chars + carryover + 1,  readmax - 1);
+#ifdef HAVE_GNUTLS
+      if (NETCONN_P(proc) && !NILP (XPROCESS(proc)->gnutls_state))
+	nbytes = emacs_gnutls_read (channel, XPROCESS(proc)->gnutls_state, chars + carryover + 1, readmax - 1);
+      else
+#endif
+	nbytes = emacs_read (channel, chars + carryover + 1,  readmax - 1);
       if (nbytes < 0)
 	nbytes = 1;
       else
@@ -5540,7 +5557,14 @@
 	      else
 #endif
 		{
-		  rv = emacs_write (outfd, (char *) buf, this);
+#ifdef HAVE_GNUTLS
+		  if (NETCONN_P(proc) && !NILP (XPROCESS(proc)->gnutls_state))
+		    rv = emacs_gnutls_write (outfd,
+					     XPROCESS(proc)->gnutls_state, 
+					     (char *) buf, this);
+		  else
+#endif
+		    rv = emacs_write (outfd, (char *) buf, this);
 #ifdef ADAPTIVE_READ_BUFFERING
 		  if (p->read_output_delay > 0
 		      && p->adaptive_read_buffering == 1)

=== modified file 'src/process.h'
--- src/process.h	2010-08-11 12:34:46 +0000
+++ src/process.h	2010-09-05 04:42:32 +0000
@@ -121,6 +121,14 @@
        needs to be synced to `status'.  */
     unsigned int raw_status_new : 1;
     int raw_status;
+
+#ifdef HAVE_GNUTLS
+    /* XXX Store GNU TLS state and auth mechanisms in Lisp_Objects. */
+    Lisp_Object gnutls_state;
+    Lisp_Object x509_cred, x509_callback;
+    Lisp_Object anon_cred;
+    Lisp_Object srp_cred;
+#endif
 };
 
 /* Every field in the preceding structure except for the first two


^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-05  4:57                       ` Ted Zlatanov
@ 2010-09-05  8:06                         ` Andreas Schwab
  2010-09-05 22:47                         ` Stefan Monnier
  1 sibling, 0 replies; 93+ messages in thread
From: Andreas Schwab @ 2010-09-05  8:06 UTC (permalink / raw)
  To: Ted Zlatanov; +Cc: gnutls-devel, emacs-devel

Ted Zlatanov <tzz@lifelogs.com> writes:

> +int
> +emacs_gnutls_write (int fildes, gnutls_session_t state, char *buf,
> +                    unsigned int nbyte)
> +{
> +  register int rtnval, bytes_written;
> +
> +  puts("emacs_gnutls_write");

You should remove the debugging output.

> +DEFUN ("gnutls-init", Fgnutls_init, Sgnutls_init, 2, 2, 0,
> +       doc: /* Initializes GNU TLS for process PROC for use as CONNECTION-END.
> +CONNECTION-END is used to indicate if this process is as a server or
> +client. Can be one of `gnutls-client' and `gnutls-server'.  Currently
> +only `gnutls-client' is supported.
> +
> +Processes must be initialized with this function before other GNU TLS
> +functions are used.  This function allocates resources which can only
> +be deallocated by calling `gnutls-deinit'. Returns zero on success. */)
> +    (Lisp_Object proc, Lisp_Object connection_end)
> +{
> +  int ret;
> +  
> +  CHECK_PROCESS (proc);
> +
> +  ret = gnutls_init((gnutls_session_t*)&(XPROCESS(proc)->gnutls_state), 

Aliasing violation.

> +		    connection_end);
> +
> +  return XINT(ret);

IMHO all your functions should return t on success and either some error
symbol on failure or even raise an error.

> +DEFUN ("gnutls-cred-set", Fgnutls_cred_set, 
> +       Sgnutls_cred_set, 2, 2, 0,
> +       doc: /* Enables GNU TLS authentication for PROCESS.
> +TYPE is an integer indicating the type of the credentials, either
> +`gnutls-anon', `gnutls-srp' or `gnutls-x509pki'.
> +
> +Each authentication type may need additional information in order to
> +work.  For anonymous (`gnutls-anon'), see also
> +`gnutls-anon-set-client-cred'.	For SRP (`gnutls-srp'), see also
> +`gnutls-srp-set-client-cred'.  For X.509 PKI (`gnutls-x509pki'), see
> +also `gnutls-x509pki-set-client-trust-file',
> +`gnutls-x509pki-set-client-key-file', and
> +`gnutls-x509pki-set-cert-callback'. */)
> +    (Lisp_Object proc, Lisp_Object type)
> +{
> +  gnutls_session_t state;
> +  gnutls_certificate_credentials_t x509_cred;
> +  gnutls_anon_client_credentials_t anon_cred;
> +  gnutls_srp_client_credentials_t srp_cred;
> +  int ret;
> +
> +  CHECK_PROCESS (proc);
> +  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
> +
> +  x509_cred = (gnutls_certificate_client_credentials) XPROCESS(proc)->x509_cred;
> +  anon_cred = (gnutls_anon_client_credentials_t) XPROCESS(proc)->anon_cred;
> +  srp_cred = (gnutls_srp_client_credentials_t) XPROCESS(proc)->srp_cred;
> +
> +  switch (XINT (type))

Need to check type.

> +  return XINT(ret);

     return make_number (ret);

> +  // defsubr (&Sgnutls_x509pki_set_client_key_file);
> +  // defsubr (&Sgnutls_x509pki_set_client_trust_file);
> +  // defsubr (&Sgnutls_srp_set_client_cred);
> +  // defsubr (&Sgnutls_anon_set_client_cred);

No C99.

> === added file 'src/gnutls.h'
> --- src/gnutls.h	1970-01-01 00:00:00 +0000
> +++ src/gnutls.h	2010-09-05 04:42:32 +0000
> @@ -0,0 +1,4 @@
> +#ifdef HAVE_GNUTLS
> +#include <gnutls/gnutls.h>
> +
> +#endif

I don't see the point of this header.

> === modified file 'src/process.h'
> --- src/process.h	2010-08-11 12:34:46 +0000
> +++ src/process.h	2010-09-05 04:42:32 +0000
> @@ -121,6 +121,14 @@
>         needs to be synced to `status'.  */
>      unsigned int raw_status_new : 1;
>      int raw_status;
> +
> +#ifdef HAVE_GNUTLS
> +    /* XXX Store GNU TLS state and auth mechanisms in Lisp_Objects. */
> +    Lisp_Object gnutls_state;
> +    Lisp_Object x509_cred, x509_callback;
> +    Lisp_Object anon_cred;
> +    Lisp_Object srp_cred;
> +#endif

None of them should be Lisp_Objects.  Also make sure the resources are
properly released when the process object is deleted.

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."



^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-05  4:57                       ` Ted Zlatanov
  2010-09-05  8:06                         ` Andreas Schwab
@ 2010-09-05 22:47                         ` Stefan Monnier
  2010-09-06  7:47                           ` Andreas Schwab
  2010-09-06 14:31                           ` Ted Zlatanov
  1 sibling, 2 replies; 93+ messages in thread
From: Stefan Monnier @ 2010-09-05 22:47 UTC (permalink / raw)
  To: Ted Zlatanov; +Cc: gnutls-devel, emacs-devel

Overall, it looks good.
Some comments on your code.

> @@ -3682,6 +3690,7 @@
>  echo "  Does Emacs use -ldbus?                                  ${HAVE_DBUS}"
>  echo "  Does Emacs use -lgconf?                                 ${HAVE_GCONF}"
>  echo "  Does Emacs use -lselinux?                               ${HAVE_LIBSELINUX}"
> +echo "  Does Emacs use Gnu TLS?                                 ${HAVE_GNUTLS}"

For symmetry, I'd say "Does Emacs use -lgnutls?".
 
> --- lisp/net/gnutls.el	1970-01-01 00:00:00 +0000
> +++ lisp/net/gnutls.el	2010-09-05 04:42:32 +0000
> @@ -0,0 +1,120 @@
> +;; By Simon Josefsson 2001-12-01
> +;; See http://josefsson.org/emacs-security/

Use C-u M-x checkdoc-current-buffer which will help you follow the usual
coding conventions (e.g. inserting the GPL blurb).

> +(defvar starttls-host nil)

What is this for?  It seems to only ever be set and never read.
Making it global doesn't make sense, and making it buffer-local only
makes sense if you presume there's never going to be more than a single
TLS process per buffer, which can't guarantee.
For that reason, any needed aux data should be kept in process
properties, I think.

> +    (set (make-variable-buffer-local 'starttls-host) host)))

Hpefully the byte-compiler flags this which should use
`make-local-variable' instead (or move the (make-variable-buffer-local
'starttls-host) to the toplevel right after the defvar).
Tho, as mentioned above, probably the real solution doesn't use such
a variable.

> +DEFUN ("gnutls-init", Fgnutls_init, Sgnutls_init, 2, 2, 0,
> +       doc: /* Initializes GNU TLS for process PROC for use as CONNECTION-END.
> +CONNECTION-END is used to indicate if this process is as a server or
> +client. Can be one of `gnutls-client' and `gnutls-server'.  Currently
> +only `gnutls-client' is supported.

This formulation means that the symbols (rather than the value of the
corresponding variables) `gnutls-client' and `gnutls-server' are the
valid values.

> +Processes must be initialized with this function before other GNU TLS
> +functions are used.  This function allocates resources which can only
> +be deallocated by calling `gnutls-deinit'. Returns zero on success. */)
> +    (Lisp_Object proc, Lisp_Object connection_end)
> +{
> +  int ret;
> +  
> +  CHECK_PROCESS (proc);
> +
> +  ret = gnutls_init((gnutls_session_t*)&(XPROCESS(proc)->gnutls_state), 
> +		    connection_end);

I recommend you compile your Emacs with -DUSE_LISP_UNION_TYPE which will
catch errors such as the one above: clearly gnutls_init doesn't take
a Lisp_Object as second argument.  You probably meant to add an XINT
(...), and you'll want to add a CHECK_NUMBER for it beforehand as well.

This said, while I understand the general desire to just bring the C API
of GNU TLS into Elisp, as long as you do it by hand, you might as well
use here a Lisp boolean for connection_end.

> +  return XINT(ret);

-DUSE_LISP_UNION_TYPE will also catch this error.

> +  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
> +  gnutls_deinit(state);

Please always put a space before the open paren of a macro or
function call.  Applies to the rest of the code as well, of course.

> +  int ret;
> +  ret = gnutls_global_init();

Uninitialized variables are dangerous, so it's a good habit to
initialize vars when you declare them, especially when it's trivial to
do so.  It's also more concise:

  int ret = gnutls_global_init();

> +  XSETINT (lret, ret);
> +  return lret;
> +}

   return make_number (lret);

will save you the uninitialized lret as well.

> +DEFUN ("gnutls-cert-set-x509-trust-file", 
> +       Fgnutls_cert_set_x509_trust_file,
> +       Sgnutls_cert_set_x509_trust_file, 2, 2, 0,
> +       doc: /* Set X.509 client trust file for PROCESS
> +CERTFILE is a PEM encoded file.  Returns zero on success.
> +*/)

By convention we keep the closing */) at the end of the previous line.

> +    (Lisp_Object proc, Lisp_Object certfile)
> +{
> +  gnutls_session_t state;
> +  gnutls_certificate_credentials_t x509_cred;
> +  Lisp_Object lret;
> +  int ret;
> +
> +  CHECK_STRING(certfile);
> +
> +  CHECK_PROCESS (proc);
> +  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
> +
> +  x509_cred = (gnutls_certificate_credentials_t) XPROCESS(proc)->x509_cred;
> +
> +  ret = gnutls_certificate_set_x509_trust_file (x509_cred, XSTRING (certfile)->data, GNUTLS_X509_FMT_PEM);
> +
> +  XSETINT (lret, ret);
> +  return lret;
> +}
> +
> +DEFUN ("gnutls-cred-set", Fgnutls_cred_set, 
> +       Sgnutls_cred_set, 2, 2, 0,
> +       doc: /* Enables GNU TLS authentication for PROCESS.
> +TYPE is an integer indicating the type of the credentials, either
> +`gnutls-anon', `gnutls-srp' or `gnutls-x509pki'.

Again, the above formulation means that the caller should pass those
symbols rather than value associated with the corresponding variables.

> +  switch (XINT (type))

Here, you extract the integer value without having checked that `type'
is indeed an integer.

> +    {
> +    case GNUTLS_CRD_CERTIFICATE:
> +      if (gnutls_certificate_allocate_credentials (&x509_cred) < 0)
> +	memory_full ();

Can it really only mean "memory is full"?

> === added file 'src/gnutls.h'
> --- src/gnutls.h	1970-01-01 00:00:00 +0000
> +++ src/gnutls.h	2010-09-05 04:42:32 +0000
> @@ -0,0 +1,4 @@
> +#ifdef HAVE_GNUTLS
> +#include <gnutls/gnutls.h>
> +
> +#endif

Why add this file?  Doesn't seem worth the trouble.

> +#ifdef HAVE_GNUTLS
> +/* Defined in gnutls.c */
> +extern void syms_of_gnutls (void);
> +#endif

If you have a src/gnutls.h, then the above should be moved to there.

> +#ifdef HAVE_GNUTLS
> +    /* XXX Store GNU TLS state and auth mechanisms in Lisp_Objects. */
> +    Lisp_Object gnutls_state;
> +    Lisp_Object x509_cred, x509_callback;
> +    Lisp_Object anon_cred;
> +    Lisp_Object srp_cred;
> +#endif

Rather than hardcode variables in gnutls.el, an alternative could be to
define those variables in gnutls.c so you can initialize them to the
values taken from gnutls/gnutls.h.


        Stefan




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-05 22:47                         ` Stefan Monnier
@ 2010-09-06  7:47                           ` Andreas Schwab
  2010-09-06 14:31                           ` Ted Zlatanov
  1 sibling, 0 replies; 93+ messages in thread
From: Andreas Schwab @ 2010-09-06  7:47 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Ted Zlatanov, gnutls-devel, emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> I recommend you compile your Emacs with -DUSE_LISP_UNION_TYPE which will

Or configure with --enable-use-lisp-union-type.

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-05 22:47                         ` Stefan Monnier
  2010-09-06  7:47                           ` Andreas Schwab
@ 2010-09-06 14:31                           ` Ted Zlatanov
  2010-09-06 15:53                             ` Andreas Schwab
                                               ` (2 more replies)
  1 sibling, 3 replies; 93+ messages in thread
From: Ted Zlatanov @ 2010-09-06 14:31 UTC (permalink / raw)
  To: emacs-devel; +Cc: gnutls-devel

[-- Attachment #1: Type: text/plain, Size: 5197 bytes --]

On Mon, 06 Sep 2010 00:47:39 +0200 Stefan Monnier <monnier@iro.umontreal.ca> wrote: 

SM> For symmetry, I'd say "Does Emacs use -lgnutls?".

Fixed.
 
SM> Use C-u M-x checkdoc-current-buffer which will help you follow the usual
SM> coding conventions (e.g. inserting the GPL blurb).

Fixed.

>> +(defvar starttls-host nil)

SM> What is this for?  It seems to only ever be set and never read.

I think Simon Josefsson intended to do more with it but you're right,
right now it's unused.  I removed it.

>> +DEFUN ("gnutls-init", Fgnutls_init, Sgnutls_init, 2, 2, 0,
>> +       doc: /* Initializes GNU TLS for process PROC for use as CONNECTION-END.
>> +CONNECTION-END is used to indicate if this process is as a server or
>> +client. Can be one of `gnutls-client' and `gnutls-server'.  Currently
>> +only `gnutls-client' is supported.

SM> This formulation means that the symbols (rather than the value of the
SM> corresponding variables) `gnutls-client' and `gnutls-server' are the
SM> valid values.

We don't support server mode anyhow so I removed the connection-end
argument altogether (hardcoding the init to GNUTLS_CLIENT).

`gnutls-bye' still mentions `gnutls-e-again' and `gnutls-e-interrupted'.
I'm not sure if I should return a symbol or the numeric value there.

SM> This said, while I understand the general desire to just bring the C API
SM> of GNU TLS into Elisp, as long as you do it by hand, you might as well
SM> use here a Lisp boolean for connection_end.

Yeah, I'll do that for `gnutls-bye' with a CONT parameter.  It's just a
NILP check to handle booleans IIUC (there's no CHECK_BOOLEAN, so it's
either NILP or EQ to Qt).

>> +  state = (gnutls_session_t) XPROCESS(proc)->gnutls_state;
>> +  gnutls_deinit(state);

SM> Please always put a space before the open paren of a macro or
SM> function call.  Applies to the rest of the code as well, of course.

Fixed.

SM>    return make_number (lret);

Fixed everywhere, I think, and I condensed the code when possible (argh,
no C99 :)

>> +CERTFILE is a PEM encoded file.  Returns zero on success.
>> +*/)

SM> By convention we keep the closing */) at the end of the previous line.

Fixed.

>> +DEFUN ("gnutls-cred-set", Fgnutls_cred_set, 
>> +       Sgnutls_cred_set, 2, 2, 0,
>> +       doc: /* Enables GNU TLS authentication for PROCESS.
>> +TYPE is an integer indicating the type of the credentials, either
>> +`gnutls-anon', `gnutls-srp' or `gnutls-x509pki'.

SM> Again, the above formulation means that the caller should pass those
SM> symbols rather than value associated with the corresponding variables.

In this case I think that's the right approach actually so we shouldn't
have defconsts.  See new definition, it uses two local Lisp_Objects for
the symbol names.  Where should I allocate those constant Lisp_Objects
globally properly?  And should I default to anonymous?

>> +      if (gnutls_certificate_allocate_credentials (&x509_cred) < 0)
>> +	memory_full ();

SM> Can it really only mean "memory is full"?

I think so.

>> === added file 'src/gnutls.h'
SM> Why add this file?  Doesn't seem worth the trouble.

As gnutls.c grows, I think it will be necessary.  It can be removed now
if you want.

>> +#ifdef HAVE_GNUTLS
>> +    /* XXX Store GNU TLS state and auth mechanisms in Lisp_Objects. */
>> +    Lisp_Object gnutls_state;
>> +    Lisp_Object x509_cred, x509_callback;
>> +    Lisp_Object anon_cred;
>> +    Lisp_Object srp_cred;
>> +#endif

SM> Rather than hardcode variables in gnutls.el, an alternative could be to
SM> define those variables in gnutls.c so you can initialize them to the
SM> values taken from gnutls/gnutls.h.

I'd like to take the direction of a more Lisp-y API on top of the GnuTLS
API.  So any constants should be limited to the function bodies and I'd
like to stick to symbols (as with gnutls-cred-set in the new patch).

On Sun, 05 Sep 2010 10:06:09 +0200 Andreas Schwab <schwab@linux-m68k.org> wrote: 

AS> You should remove the debugging output.

Fixed.

>> +DEFUN ("gnutls-init", Fgnutls_init, Sgnutls_init, 2, 2, 0,
...
>> +  ret = gnutls_init((gnutls_session_t*)&(XPROCESS(proc)->gnutls_state), 

AS> Aliasing violation.

Can you explain please?

AS> IMHO all your functions should return t on success and either some error
AS> symbol on failure or even raise an error.

Yes, but I'm not sure which one.  Can you recommend?

AS> No C99.

Yes, sorry for leaving that in the patch.  Removed.

>> === modified file 'src/process.h'
>> +
>> +#ifdef HAVE_GNUTLS
>> +    /* XXX Store GNU TLS state and auth mechanisms in Lisp_Objects. */
>> +    Lisp_Object gnutls_state;
>> +    Lisp_Object x509_cred, x509_callback;
>> +    Lisp_Object anon_cred;
>> +    Lisp_Object srp_cred;
>> +#endif

AS> None of them should be Lisp_Objects.  Also make sure the resources are
AS> properly released when the process object is deleted.

I don't know enough (the choice of using Lisp_Objects was in the
original patch) to know what to do instead of using Lisp_Objects.  Why
not, first of all?

Revised patch is attached (it compiles but the changes are mostly
cosmetic so it's still not usable).  Thank you for the comments, they
were very helpful.  I hope to get this in a usable state ASAP.

Ted


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: tls.patch --]
[-- Type: text/x-diff, Size: 22967 bytes --]

=== modified file 'configure.in'
--- configure.in	2010-08-23 12:54:09 +0000
+++ configure.in	2010-09-06 14:25:55 +0000
@@ -170,6 +170,7 @@
 OPTION_DEFAULT_ON([dbus],[don't compile with D-Bus support])
 OPTION_DEFAULT_ON([gconf],[don't compile with GConf support])
 OPTION_DEFAULT_ON([selinux],[don't compile with SELinux support])
+OPTION_DEFAULT_ON([gnutls],[don't use -lgnutls for SSL/TLS support])
 
 ## For the times when you want to build Emacs but don't have
 ## a suitable makeinfo, and can live without the manuals.
@@ -1998,6 +1999,13 @@
 fi
 AC_SUBST(LIBSELINUX_LIBS)
 
+HAVE_GNUTLS=no
+if test "${with_gnutls}" = "yes" ; then
+  PKG_CHECK_MODULES([LIBGNUTLS], [gnutls >= 2.2.4])
+  AC_DEFINE(HAVE_GNUTLS)
+  HAVE_GNUTLS=yes
+fi
+
 dnl Do not put whitespace before the #include statements below.
 dnl Older compilers (eg sunos4 cc) choke on it.
 HAVE_XAW3D=no
@@ -3682,6 +3690,7 @@
 echo "  Does Emacs use -ldbus?                                  ${HAVE_DBUS}"
 echo "  Does Emacs use -lgconf?                                 ${HAVE_GCONF}"
 echo "  Does Emacs use -lselinux?                               ${HAVE_LIBSELINUX}"
+echo "  Does Emacs use -lgnutls?                                ${HAVE_GNUTLS}"
 
 echo "  Does Emacs use -lfreetype?                              ${HAVE_FREETYPE}"
 echo "  Does Emacs use -lm17n-flt?                              ${HAVE_M17N_FLT}"

=== added file 'lisp/net/gnutls.el'
--- lisp/net/gnutls.el	1970-01-01 00:00:00 +0000
+++ lisp/net/gnutls.el	2010-09-06 14:25:55 +0000
@@ -0,0 +1,134 @@
+;;; gnutls.el --- Support SSL and TLS connections through GnuTLS
+;; Copyright (C) 2010 Free Software Foundation, Inc.
+
+;; Author: Ted Zlatanov <tzz@lifelogs.com>
+;; Keywords: comm, tls, ssl, encryption
+;; Originally-By: Simon Josefsson (See http://josefsson.org/emacs-security/)
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This package provides language bindings for the GnuTLS library
+;; using the corresponding core functions in gnutls.c.
+
+;; Simple test:
+;;
+;; (setq jas (open-ssl-stream "ssl" (current-buffer) "www.pdc.kth.se" 443))
+;; (process-send-string jas "GET /\r\n\r\n")
+
+;;; Code:
+
+(defconst gnutls-version "0.3.1")
+
+(defconst gnutls-e-interrupted -52)
+(defconst gnutls-e-again -28)
+
+(defun open-ssl-stream (name buffer host service)
+  "Open a SSL connection for a service to a host.
+Returns a subprocess-object to represent the connection.
+Input and output work as for subprocesses; `delete-process' closes it.
+Args are NAME BUFFER HOST SERVICE.
+NAME is name for process.  It is modified if necessary to make it unique.
+BUFFER is the buffer (or `buffer-name') to associate with the process.
+ Process output goes at end of that buffer, unless you specify
+ an output stream or filter function to handle the output.
+ BUFFER may be also nil, meaning that this process is not associated
+ with any buffer
+Third arg is name of the host to connect to, or its IP address.
+Fourth arg SERVICE is name of the service desired, or an integer
+specifying a port number to connect to."
+  (let ((proc (open-network-stream name buffer host service)))
+    (starttls-negotiate proc)))
+
+(defun starttls-negotiate (proc &optional priority-string
+                                credentials credentials-file)
+  "Negotiate a SSL or TLS connection.
+PROC is the process returned by `starttls-open-stream'.
+PRIORITY-STRING is as per the GnuTLS docs.
+CREDENTIALS is `gnutls-x509pki', `gnutls-anon', or `gnutls-srp'.
+CREDENTIALS-FILE is a filename with meaning dependent on CREDENTIALS."
+  (let* ((credentials (or credentials 'gnutls-anon))
+         (priority-string (or priority-string
+                              (cond
+                               ((eq credentials 'gnutls-anon)
+                                "PERFORMANCE:+ANON-DH:!ARCFOUR-128")
+                               ((eq credentials 'gnutls-x509pki)
+                               "PERFORMANCE")))))
+    (gnutls-message-maybe
+     (gnutls-global-init)
+     "global_init: err=%s")
+
+    (gnutls-message-maybe
+     (gnutls-init proc)
+     "init: err=%s")
+
+    (gnutls-message-maybe
+     (gnutls-priority-set-direct proc priority-string)
+     "priority_set: err=%s")
+
+    (gnutls-message-maybe
+     (gnutls-cred-set proc credentials)
+     "credential_set: err=%s")
+
+    (cond
+     ((eq credentials 'gnutls-x509pki)
+      (gnutls-message-maybe
+       (gnutls-cert-set-x509-trust-file proc credentials-file)
+       "x509_trustfile: err=%s")))
+
+    (let ((ret gnutls-e-again))
+      (while (or (eq ret gnutls-e-again)
+                 (eq ret gnutls-e-interrupted))
+        (gnutls-message-maybe
+         (setq ret (gnutls-handshake proc))
+         "handshake: err=%s"))
+      (if (< ret 0)
+          (progn
+            (message "Ouch, error return %d" ret)
+            (setq proc nil))
+        (message "Handshake complete %d." ret)))
+     proc))
+
+(defun starttls-open-stream (name buffer host service)
+  "Open a TLS connection for a service to a host.
+Returns a subprocess-object to represent the connection.
+Input and output work as for subprocesses; `delete-process' closes it.
+Args are NAME BUFFER HOST SERVICE.
+NAME is name for process.  It is modified if necessary to make it unique.
+BUFFER is the buffer (or `buffer-name') to associate with the process.
+ Process output goes at end of that buffer, unless you specify
+ an output stream or filter function to handle the output.
+ BUFFER may be also nil, meaning that this process is not associated
+ with any buffer
+Third arg is name of the host to connect to, or its IP address.
+Fourth arg SERVICE is name of the service desired, or an integer
+specifying a port number to connect to."
+  (open-network-stream name buffer host service))
+
+(defun gnutls-message-maybe (doit format &rest params)
+  "When DOIT, message with the caller name followed by FORMAT on PARAMS."
+  (when doit
+    (message "%s: (err=%s) %s"
+             (nth 1 (backtrace-frame 4))
+             doit
+             (apply 'format format params))))
+
+(provide 'ssl)
+(provide 'gnutls)
+(provide 'starttls)
+
+;;; gnutls.el ends here

=== modified file 'src/Makefile.in'
--- src/Makefile.in	2010-08-17 21:19:11 +0000
+++ src/Makefile.in	2010-09-06 14:25:55 +0000
@@ -285,6 +285,9 @@
 
 LIBSELINUX_LIBS = @LIBSELINUX_LIBS@
 
+LIBGNUTLS_LIBS = @LIBGNUTLS_LIBS@
+LIBGNUTLS_CFLAGS = @LIBGNUTLS_CFLAGS@
+
 INTERVALS_H = dispextern.h intervals.h composite.h
 
 GETLOADAVG_LIBS = @GETLOADAVG_LIBS@
@@ -323,6 +326,7 @@
   ${C_SWITCH_X_SYSTEM} ${CFLAGS_SOUND} ${RSVG_CFLAGS} ${IMAGEMAGICK_CFLAGS} ${DBUS_CFLAGS} \
   ${GCONF_CFLAGS} ${FREETYPE_CFLAGS} ${FONTCONFIG_CFLAGS} \
   ${LIBOTF_CFLAGS} ${M17N_FLT_CFLAGS} ${DEPFLAGS} ${PROFILING_CFLAGS} \
+  $(LIBGNUTLS_CFLAGS) \
   ${C_WARNINGS_SWITCH} ${CFLAGS}
 ALL_OBJC_CFLAGS=$(ALL_CFLAGS) $(GNU_OBJC_CFLAGS)
 
@@ -347,7 +351,7 @@
 	alloc.o data.o doc.o editfns.o callint.o \
 	eval.o floatfns.o fns.o font.o print.o lread.o \
 	syntax.o $(UNEXEC_OBJ) bytecode.o \
-	process.o callproc.o \
+	process.o gnutls.o callproc.o \
 	region-cache.o sound.o atimer.o \
 	doprnt.o strftime.o intervals.o textprop.o composite.o md5.o \
 	$(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ)
@@ -598,6 +602,7 @@
    $(RSVG_LIBS) ${IMAGEMAGICK_LIBS}  $(DBUS_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \
    $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) ${GCONF_LIBS} ${LIBSELINUX_LIBS} \
    $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
+   $(LIBGNUTLS_LIBS) \
    $(LIB_GCC) $(LIB_MATH) $(LIB_STANDARD) $(LIB_GCC)
 
 all: emacs${EXEEXT} $(OTHER_FILES)

=== modified file 'src/config.in'
--- src/config.in	2010-08-17 21:19:11 +0000
+++ src/config.in	2010-09-06 14:25:55 +0000
@@ -255,6 +255,9 @@
 /* Define to 1 if you have a gif (or ungif) library. */
 #undef HAVE_GIF
 
+/* Define if we have the GNU TLS library.  */
+#undef HAVE_GNUTLS
+
 /* Define to 1 if you have the gpm library (-lgpm). */
 #undef HAVE_GPM
 
@@ -1091,6 +1094,12 @@
 #include config_opsysfile
 #include config_machfile
 
+#if HAVE_GNUTLS
+#define LIBGNUTLS $(LIBGNUTLS_LIBS)
+#else /* not HAVE_GNUTLS */
+#define LIBGNUTLS
+#endif /* not HAVE_GNUTLS */
+
 /* Set up some defines, C and LD flags for NeXTstep interface on GNUstep.
   (There is probably a better place to do this, but right now the Cocoa
    side does this in s/darwin.h and we cannot

=== modified file 'src/emacs.c'
--- src/emacs.c	2010-08-22 21:15:20 +0000
+++ src/emacs.c	2010-09-06 14:25:55 +0000
@@ -63,6 +63,10 @@
 #include "keyboard.h"
 #include "keymap.h"
 
+#ifdef HAVE_GNUTLS
+#include "gnutls.h"
+#endif
+
 #ifdef HAVE_NS
 #include "nsterm.h"
 #endif
@@ -1569,6 +1573,10 @@
       syms_of_fontset ();
 #endif /* HAVE_NS */
 
+#ifdef HAVE_GNUTLS
+      syms_of_gnutls ();
+#endif
+
 #ifdef HAVE_DBUS
       syms_of_dbusbind ();
 #endif /* HAVE_DBUS */

=== added file 'src/gnutls.c'
--- src/gnutls.c	1970-01-01 00:00:00 +0000
+++ src/gnutls.c	2010-09-06 14:25:55 +0000
@@ -0,0 +1,327 @@
+#include <config.h>
+#include <errno.h>
+#include <setjmp.h>
+
+#include "lisp.h"
+#include "process.h"
+
+#ifdef HAVE_GNUTLS
+#include <gnutls/gnutls.h>
+
+int
+emacs_gnutls_write (int fildes, gnutls_session_t state, char *buf,
+                    unsigned int nbyte)
+{
+  register int rtnval, bytes_written;
+
+  bytes_written = 0;
+
+  while (nbyte > 0)
+    {
+      rtnval = gnutls_write (state, buf, nbyte);
+
+      if (rtnval == -1)
+	{
+	  if (errno == EINTR)
+	    continue;
+	  else
+	    return (bytes_written ? bytes_written : -1);
+	}
+
+      buf += rtnval;
+      nbyte -= rtnval;
+      bytes_written += rtnval;
+    }
+  fsync (STDOUT_FILENO);
+
+  return (bytes_written);
+}
+
+int
+emacs_gnutls_read (int fildes, gnutls_session_t state, char *buf,
+                   unsigned int nbyte)
+{
+  register int rtnval;
+
+  do {
+    rtnval = gnutls_read (state, buf, nbyte);
+  } while( rtnval==GNUTLS_E_INTERRUPTED || rtnval==GNUTLS_E_AGAIN);
+  fsync(STDOUT_FILENO);
+
+  return (rtnval);
+}
+
+int gnutls_callback (gnutls_session_t state, const gnutls_datum *client_certs,
+                     int ncerts, const gnutls_datum* req_ca_cert, int nreqs)
+{
+  if (client_certs == NULL) {
+    /* means the we will only be called again if the library cannot
+     * determine which certificate to send
+     */
+    return 0;
+  }
+
+  return -1; /* send no certificate to the peer */
+}
+
+DEFUN ("gnutls-init", Fgnutls_init, Sgnutls_init, 1, 1, 0,
+       doc: /* Initializes client-mode GnuTLS for process PROC.
+Currently only client mode is supported.
+
+Processes must be initialized with this function before other GNU TLS
+functions are used.  This function allocates resources which can only
+be deallocated by calling `gnutls-deinit'. Returns zero on success. */)
+    (Lisp_Object proc)
+{
+  int ret;
+  
+  CHECK_PROCESS (proc);
+
+  ret = gnutls_init ((gnutls_session_t*)&(XPROCESS (proc)->gnutls_state), 
+                     GNUTLS_CLIENT);
+
+  return make_number (ret);
+}
+
+DEFUN ("gnutls-deinit", Fgnutls_deinit, Sgnutls_deinit, 1, 1, 0,
+       doc: /* Deallocate GNU TLS resources associated with PROCESS.
+See also `gnutls-init'. */)
+    (Lisp_Object proc)
+{
+  int ret;
+  gnutls_session_t state;
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS (proc)->gnutls_state;
+
+  gnutls_deinit (state);
+
+  return Qnil;
+}
+
+DEFUN ("gnutls-global-init", Fgnutls_global_init, 
+       Sgnutls_global_init, 0, 0, 0,
+       doc: /* Initializes global GNU TLS state to defaults.
+Call `gnutls-global-deinit' when GNU TLS usage is no longer needed.
+Returns zero on success. */)
+     (void)
+{
+  int ret = gnutls_global_init ();
+
+  return make_number (ret);
+}
+
+DEFUN ("gnutls-global-deinit", Fgnutls_global_deinit, 
+       Sgnutls_global_deinit, 0, 0, 0,
+       doc: /* Deinitializes global GNU TLS state.
+See also `gnutls-global-init'. */)
+     (void)
+{
+  gnutls_global_deinit ();
+
+  return Qnil;
+}
+
+Lisp_Object
+generic_set_priority (int (*func)( gnutls_session_t state, const char*, const char**),
+                      Lisp_Object proc, Lisp_Object priority_string)
+{
+  gnutls_session_t state;
+  int ret;
+  
+  CHECK_PROCESS (proc);
+  CHECK_STRING (priority_string);
+  
+  state = (gnutls_session_t) XPROCESS (proc)->gnutls_state;
+
+  ret = (*func) (state, (char*) SDATA (priority_string), NULL);
+
+  return make_number (ret);
+}
+
+DEFUN ("gnutls-priority-set-direct", Fgnutls_priority_set_direct, 
+       Sgnutls_priority_set_direct, 2, 2, 0,
+       doc: /* Sets the priority on the protocol versions supported by GNU TLS for PROCESS.
+
+The first parameter must be a process. Second parameter is a string
+describing the priority.  Note that the priority is set on the client.
+The server does not use the protocols's priority except for disabling
+protocols that were not specified. */)
+    (Lisp_Object process, Lisp_Object priority_string)
+{
+  Lisp_Object ret = generic_set_priority (&gnutls_priority_set_direct, process, priority_string);
+  
+  return ret;
+}
+
+DEFUN ("gnutls-cert-set-x509-trust-file", 
+       Fgnutls_cert_set_x509_trust_file,
+       Sgnutls_cert_set_x509_trust_file, 2, 2, 0,
+       doc: /* Set X.509 client trust file for PROCESS
+CERTFILE is a PEM encoded file.  Returns zero on success. */)
+    (Lisp_Object proc, Lisp_Object certfile)
+{
+  gnutls_session_t state;
+  gnutls_certificate_credentials_t x509_cred;
+  int ret;
+
+  CHECK_STRING (certfile);
+  CHECK_PROCESS (proc);
+  
+  state = (gnutls_session_t) XPROCESS (proc)->gnutls_state;
+
+  x509_cred = (gnutls_certificate_credentials_t) XPROCESS (proc)->x509_cred;
+
+  ret = gnutls_certificate_set_x509_trust_file (x509_cred, XSTRING (certfile)->data, GNUTLS_X509_FMT_PEM);
+
+  return make_number (ret);
+}
+
+DEFUN ("gnutls-cred-set", Fgnutls_cred_set, 
+       Sgnutls_cred_set, 2, 2, 0,
+       doc: /* Enables GNU TLS authentication for PROCESS.
+TYPE is either `gnutls-anon' or `gnutls-x509pki'.
+
+Each authentication type may need additional information in order to
+work.  For anonymous (`gnutls-anon'), see also
+`gnutls-anon-set-client-cred'. For X.509 PKI (`gnutls-x509pki'), see
+also `gnutls-x509pki-set-client-trust-file',
+`gnutls-x509pki-set-client-key-file', and
+`gnutls-x509pki-set-cert-callback'. */)
+    (Lisp_Object proc, Lisp_Object type)
+{
+  Lisp_Object Qgnutls_anon = intern_c_string ("gnutls-anon");
+  Lisp_Object Qgnutls_x509 = intern_c_string ("gnutls-x509pki");
+  gnutls_session_t state;
+  gnutls_certificate_credentials_t x509_cred;
+  gnutls_anon_client_credentials_t anon_cred;
+  gnutls_srp_client_credentials_t srp_cred;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  
+  state = (gnutls_session_t) XPROCESS (proc)->gnutls_state;
+
+  x509_cred = (gnutls_certificate_client_credentials) XPROCESS (proc)->x509_cred;
+  anon_cred = (gnutls_anon_client_credentials_t) XPROCESS (proc)->anon_cred;
+  srp_cred = (gnutls_srp_client_credentials_t) XPROCESS (proc)->srp_cred;
+
+  if (EQ (type, Qgnutls_x509))
+  {
+      if (gnutls_certificate_allocate_credentials (&x509_cred) < 0)
+	memory_full ();
+      ret = gnutls_cred_set (state, GNUTLS_CRD_CERTIFICATE, x509_cred);
+  }
+  else if (EQ (type, Qgnutls_anon))
+  {
+      if (gnutls_anon_allocate_client_credentials (&anon_cred) < 0)
+	memory_full ();
+      ret = gnutls_cred_set (state, GNUTLS_CRD_ANON, anon_cred);
+  }
+  else
+  {
+   /* should this be an error or fold to gnutls-anon? */
+  }
+
+  return make_number (ret);
+}
+
+DEFUN ("gnutls-bye", Fgnutls_bye, 
+       Sgnutls_bye, 2, 2, 0,
+       doc: /* Terminate current GNU TLS connection for PROCESS.
+The connection should have been initiated using gnutls_handshake().
+
+If CONT is not nil the TLS connection gets terminated and further
+receives and sends will be disallowed. If the return value is zero you
+may continue using the connection.  If CONT is nil, GnuTLS actually
+sends an alert containing a close request and waits for the peer to
+reply with the same message.  In order to reuse the connection you
+should wait for an EOF from the peer.
+  
+This function may also return `gnutls-e-again', or
+`gnutls-e-interrupted'. */)
+    (Lisp_Object proc, Lisp_Object cont)
+{
+  gnutls_session_t state;
+  int ret;
+
+  CHECK_PROCESS (proc);
+
+  state = (gnutls_session_t) XPROCESS (proc)->gnutls_state;
+
+  ret = gnutls_bye (state,
+                    NILP (cont) ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR);
+  
+  return make_number (ret);
+}
+
+DEFUN ("gnutls-handshake", Fgnutls_handshake, 
+       Sgnutls_handshake, 1, 1, 0,
+       doc: /* Perform GNU TLS handshake for PROCESS.
+The identity of the peer is checked automatically.  This function will
+fail if any problem is encountered, and will return a negative error
+code. In case of a client, if it has been asked to resume a session,
+but the server didn't, then a full handshake will be performed.
+  
+This function may also return the non-fatal errors `gnutls-e-again',
+or `gnutls-e-interrupted'. In that case you may resume the handshake
+(by calling this function again). */)
+    (Lisp_Object proc)
+{
+  gnutls_session_t state;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS (proc)->gnutls_state;
+
+  gnutls_transport_set_ptr (state, XPROCESS (proc)->infd);
+  ret = gnutls_handshake (state);
+
+  return make_number (ret);
+}
+
+DEFUN ("gnutls-rehandshake", Fgnutls_rehandshake, 
+       Sgnutls_rehandshake, 1, 1, 0,
+       doc: /* Renegotiate GNU TLS security parameters for PROCESS.
+This function will renegotiate security parameters with the
+client. This should only be called in case of a server.
+
+This message informs the peer that we want to renegotiate parameters
+\(perform a handshake).
+  
+If this function succeeds (returns 0), you must call the
+gnutls_handshake() function in order to negotiate the new parameters.
+  
+If the client does not wish to renegotiate parameters he will reply
+with an alert message, thus the return code will be
+`gnutls-e-warning-alert-received' and the alert will be
+`gnutls-e-no-renegotiation'. */)
+    (Lisp_Object proc)
+{
+  gnutls_session_t state;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  state = (gnutls_session_t) XPROCESS (proc)->gnutls_state;
+
+  gnutls_transport_set_ptr (state, XPROCESS (proc)->infd);
+  ret = gnutls_rehandshake (state);
+
+  return make_number (ret);
+}
+
+void
+syms_of_gnutls (void)
+{
+  defsubr (&Sgnutls_global_init);
+  defsubr (&Sgnutls_global_deinit);
+  defsubr (&Sgnutls_init);
+  defsubr (&Sgnutls_deinit);
+  defsubr (&Sgnutls_priority_set_direct);
+  defsubr (&Sgnutls_cred_set);
+  defsubr (&Sgnutls_handshake);
+  defsubr (&Sgnutls_rehandshake);
+  defsubr (&Sgnutls_cert_set_x509_trust_file);
+  defsubr (&Sgnutls_bye);
+}
+#endif

=== added file 'src/gnutls.h'
--- src/gnutls.h	1970-01-01 00:00:00 +0000
+++ src/gnutls.h	2010-09-06 14:25:55 +0000
@@ -0,0 +1,4 @@
+#ifdef HAVE_GNUTLS
+#include <gnutls/gnutls.h>
+
+#endif

=== modified file 'src/lisp.h'
--- src/lisp.h	2010-08-09 19:25:41 +0000
+++ src/lisp.h	2010-09-06 14:25:55 +0000
@@ -3350,6 +3350,7 @@
 extern void syms_of_process (void);
 extern void setup_process_coding_systems (Lisp_Object);
 
+
 /* Defined in callproc.c */
 extern Lisp_Object Vexec_path, Vexec_suffixes,
                    Vexec_directory, Vdata_directory;
@@ -3589,6 +3590,11 @@
 void syms_of_dbusbind (void);
 #endif
 
+#ifdef HAVE_GNUTLS
+/* Defined in gnutls.c */
+extern void syms_of_gnutls (void);
+#endif
+
 #ifdef DOS_NT
 /* Defined in msdos.c, w32.c */
 extern char *emacs_root_dir (void);

=== modified file 'src/process.c'
--- src/process.c	2010-08-22 15:14:37 +0000
+++ src/process.c	2010-09-06 14:25:55 +0000
@@ -105,6 +105,9 @@
 #include "sysselect.h"
 #include "syssignal.h"
 #include "syswait.h"
+#ifdef HAVE_GNUTLS
+#include "gnutls.h"
+#endif
 
 #if defined (USE_GTK) || defined (HAVE_GCONF)
 #include "xgselect.h"
@@ -1526,6 +1529,10 @@
   XPROCESS (proc)->filter = Qnil;
   XPROCESS (proc)->command = Flist (nargs - 2, args + 2);
 
+#ifdef HAVE_GNUTLS
+  XPROCESS (proc)->gnutls_state = Qnil;
+#endif
+
 #ifdef ADAPTIVE_READ_BUFFERING
   XPROCESS (proc)->adaptive_read_buffering
     = (NILP (Vprocess_adaptive_read_buffering) ? 0
@@ -5097,7 +5104,12 @@
 #endif
   if (proc_buffered_char[channel] < 0)
     {
-      nbytes = emacs_read (channel, chars + carryover, readmax);
+#ifdef HAVE_GNUTLS
+      if (NETCONN_P(proc) && !NILP (XPROCESS(proc)->gnutls_state))
+	nbytes = emacs_gnutls_read (channel, XPROCESS(proc)->gnutls_state, chars + carryover, readmax);
+      else
+#endif
+	nbytes = emacs_read (channel, chars + carryover, readmax);
 #ifdef ADAPTIVE_READ_BUFFERING
       if (nbytes > 0 && p->adaptive_read_buffering)
 	{
@@ -5130,7 +5142,12 @@
     {
       chars[carryover] = proc_buffered_char[channel];
       proc_buffered_char[channel] = -1;
-      nbytes = emacs_read (channel, chars + carryover + 1,  readmax - 1);
+#ifdef HAVE_GNUTLS
+      if (NETCONN_P(proc) && !NILP (XPROCESS(proc)->gnutls_state))
+	nbytes = emacs_gnutls_read (channel, XPROCESS(proc)->gnutls_state, chars + carryover + 1, readmax - 1);
+      else
+#endif
+	nbytes = emacs_read (channel, chars + carryover + 1,  readmax - 1);
       if (nbytes < 0)
 	nbytes = 1;
       else
@@ -5540,7 +5557,14 @@
 	      else
 #endif
 		{
-		  rv = emacs_write (outfd, (char *) buf, this);
+#ifdef HAVE_GNUTLS
+		  if (NETCONN_P(proc) && !NILP (XPROCESS(proc)->gnutls_state))
+		    rv = emacs_gnutls_write (outfd,
+					     XPROCESS(proc)->gnutls_state, 
+					     (char *) buf, this);
+		  else
+#endif
+		    rv = emacs_write (outfd, (char *) buf, this);
 #ifdef ADAPTIVE_READ_BUFFERING
 		  if (p->read_output_delay > 0
 		      && p->adaptive_read_buffering == 1)

=== modified file 'src/process.h'
--- src/process.h	2010-08-11 12:34:46 +0000
+++ src/process.h	2010-09-06 14:25:55 +0000
@@ -121,6 +121,14 @@
        needs to be synced to `status'.  */
     unsigned int raw_status_new : 1;
     int raw_status;
+
+#ifdef HAVE_GNUTLS
+    /* XXX Store GNU TLS state and auth mechanisms in Lisp_Objects. */
+    Lisp_Object gnutls_state;
+    Lisp_Object x509_cred, x509_callback;
+    Lisp_Object anon_cred;
+    Lisp_Object srp_cred;
+#endif
 };
 
 /* Every field in the preceding structure except for the first two


^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-06 14:31                           ` Ted Zlatanov
@ 2010-09-06 15:53                             ` Andreas Schwab
  2010-09-06 17:18                             ` Andreas Schwab
  2010-09-06 21:00                             ` Stefan Monnier
  2 siblings, 0 replies; 93+ messages in thread
From: Andreas Schwab @ 2010-09-06 15:53 UTC (permalink / raw)
  To: Ted Zlatanov; +Cc: gnutls-devel, emacs-devel

Ted Zlatanov <tzz@lifelogs.com> writes:

>>> +DEFUN ("gnutls-init", Fgnutls_init, Sgnutls_init, 2, 2, 0,
> ...
>>> +  ret = gnutls_init((gnutls_session_t*)&(XPROCESS(proc)->gnutls_state), 
>
> AS> Aliasing violation.
>
> Can you explain please?

The function wants to store a value of one type into an object of a
different type.  BAD.  The compiler is allowed to assume the object was
never changed.

> AS> IMHO all your functions should return t on success and either some error
> AS> symbol on failure or even raise an error.
>
> Yes, but I'm not sure which one.  Can you recommend?

Take your pick.  I don't know anything about gnutls.

>>> === modified file 'src/process.h'
>>> +
>>> +#ifdef HAVE_GNUTLS
>>> +    /* XXX Store GNU TLS state and auth mechanisms in Lisp_Objects. */
>>> +    Lisp_Object gnutls_state;
>>> +    Lisp_Object x509_cred, x509_callback;
>>> +    Lisp_Object anon_cred;
>>> +    Lisp_Object srp_cred;
>>> +#endif
>
> AS> None of them should be Lisp_Objects.  Also make sure the resources are
> AS> properly released when the process object is deleted.
>
> I don't know enough (the choice of using Lisp_Objects was in the
> original patch) to know what to do instead of using Lisp_Objects.  Why
> not, first of all?

You never store Lisp_Object values in there, so what's the point?
x509_callback is never used, btw.

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-06 14:31                           ` Ted Zlatanov
  2010-09-06 15:53                             ` Andreas Schwab
@ 2010-09-06 17:18                             ` Andreas Schwab
  2010-09-09 15:12                               ` Ted Zlatanov
  2010-09-06 21:00                             ` Stefan Monnier
  2 siblings, 1 reply; 93+ messages in thread
From: Andreas Schwab @ 2010-09-06 17:18 UTC (permalink / raw)
  To: Ted Zlatanov; +Cc: gnutls-devel, emacs-devel

Ted Zlatanov <tzz@lifelogs.com> writes:

> @@ -1998,6 +1999,13 @@
>  fi
>  AC_SUBST(LIBSELINUX_LIBS)
>  
> +HAVE_GNUTLS=no
> +if test "${with_gnutls}" = "yes" ; then
> +  PKG_CHECK_MODULES([LIBGNUTLS], [gnutls >= 2.2.4])

Are you sure you want to make gnutls a required dependency of Emacs?

> +  AC_DEFINE(HAVE_GNUTLS)

$ autoreconf
autoheader: warning: missing template: HAVE_GNUTLS
autoheader: Use AC_DEFINE([HAVE_GNUTLS], [], [Description])
autoreconf: /usr/bin/autoheader failed with exit status: 1

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."



^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-06 14:31                           ` Ted Zlatanov
  2010-09-06 15:53                             ` Andreas Schwab
  2010-09-06 17:18                             ` Andreas Schwab
@ 2010-09-06 21:00                             ` Stefan Monnier
  2010-09-06 23:13                               ` Ted Zlatanov
  2 siblings, 1 reply; 93+ messages in thread
From: Stefan Monnier @ 2010-09-06 21:00 UTC (permalink / raw)
  To: Ted Zlatanov; +Cc: gnutls-devel, emacs-devel

> Yeah, I'll do that for `gnutls-bye' with a CONT parameter.  It's just a
> NILP check to handle booleans IIUC (there's no CHECK_BOOLEAN, so it's
> either NILP or EQ to Qt).

Yes, NILP is the way to test it (anything that's not nil is considered
as a way to say "true").

>>> +DEFUN ("gnutls-cred-set", Fgnutls_cred_set, 
>>> +       Sgnutls_cred_set, 2, 2, 0,
>>> +       doc: /* Enables GNU TLS authentication for PROCESS.
>>> +TYPE is an integer indicating the type of the credentials, either
>>> +`gnutls-anon', `gnutls-srp' or `gnutls-x509pki'.
SM> Again, the above formulation means that the caller should pass those
SM> symbols rather than value associated with the corresponding variables.

> In this case I think that's the right approach actually so we shouldn't
> have defconsts.  See new definition, it uses two local Lisp_Objects for
> the symbol names.
> Where should I allocate those constant Lisp_Objects
> globally properly?

It's typically declared as global (static or not, depending on whether
it's used in other files) and initialized in syms_of_<foo>.
Look at other syms_of_<foo> to see what it looks like.

> And should I default to anonymous?

I don't know what that means.

>>> +#ifdef HAVE_GNUTLS
>>> +    /* XXX Store GNU TLS state and auth mechanisms in Lisp_Objects. */
>>> +    Lisp_Object gnutls_state;
>>> +    Lisp_Object x509_cred, x509_callback;
>>> +    Lisp_Object anon_cred;
>>> +    Lisp_Object srp_cred;
>>> +#endif

These extra slots don't actually Lisp objects, so this type is wrong
(and it forces you to use casts: any use of cast is a sign of
a problem, tho admittedly C often makes problems unavoidable).
If you check the "struct Lisp_Process" in process.h you'll see this:

    /* After this point, there are no Lisp_Objects any more.  */
    /* alloc.c assumes that `pid' is the first such non-Lisp slot.  */

so the slots you add at the end are ignored by the GC (which is what
you want in your case, since they're not Lisp objects and hence the GC
wouldn't know what to do with them) and can be of any type.  So just use
the types you need here such that casts aren't needed.

> I'd like to take the direction of a more Lisp-y API on top of the GnuTLS
> API.  So any constants should be limited to the function bodies and I'd
> like to stick to symbols (as with gnutls-cred-set in the new patch).

BTW, if it makes the code simpler, you can use the following trick: use
symbols, but associate an integer to each symbol by way of
symbol properties.
I.e. something like

   static Lisp_Object Qgnutls_foo;

   gnutls_function (Lisp_Object arg1, ...)
   {
      arg1 = Fget (arg1, Qgnutls_code);
      int op = INTEGERP (arg1) ? XINT (arg1) : ....;
      if (op < n1 || op > n2)
         error ("Invalid op code");
      gnutls_foo (..., op, ...);
   }

   syms_of_gnutls ()
   {
      ...
      Qgnutls_foo = intern ("gnutls-foo");
      ...
      Fput (Qgnutls_foo, Qgnutls_code, make_number (GNUTLS_FOO));
   }

It's not super-lightweight, but it can be more convenient than a bunch
of (EQ (foo, Qgnutls_bar)) if there are many different possible values.

>>> +  ret = gnutls_init((gnutls_session_t*)&(XPROCESS(proc)->gnutls_state), 
AS> Aliasing violation.
> Can you explain please?

Casts are evil, try real hard to stay away from them (he said, and then
added a few casts).

AS> IMHO all your functions should return t on success and either some error
AS> symbol on failure or even raise an error.
> Yes, but I'm not sure which one.  Can you recommend?

 error ("some informative string");

> I don't know enough (the choice of using Lisp_Objects was in the
> original patch) to know what to do instead of using Lisp_Objects.  Why
> not, first of all?

The type you declare should correspond to the type of the objects you
store there.  Always.  If you stick to this principle and avoid freeing
live objects (and stay within array bounds, and a few more such things)
your code will be more portable and won't dump core (hence will be
generally easier to debug).


        Stefan

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-06 21:00                             ` Stefan Monnier
@ 2010-09-06 23:13                               ` Ted Zlatanov
  2010-09-11 14:59                                 ` Ted Zlatanov
  0 siblings, 1 reply; 93+ messages in thread
From: Ted Zlatanov @ 2010-09-06 23:13 UTC (permalink / raw)
  To: gnutls-devel; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 5145 bytes --]

On Mon, 06 Sep 2010 23:00:51 +0200 Stefan Monnier <monnier@iro.umontreal.ca> wrote: 

>> In this case I think that's the right approach actually so we
>> shouldn't have defconsts.  See new definition, it uses two local
>> Lisp_Objects for the symbol names.  Where should I allocate those
>> constant Lisp_Objects globally properly?

SM> It's typically declared as global (static or not, depending on whether
SM> it's used in other files) and initialized in syms_of_<foo>.
SM> Look at other syms_of_<foo> to see what it looks like.

Done, thanks.

>> And should I default to anonymous?

SM> I don't know what that means.

If the user passes an unknown symbol to `gnutls-cred-set', should it be
treated as `gnutls_anon' or generate an error?  It could work either
way.  I'm leaning towards an error but it seems kind of rude to the
user.  OTOH it could be a serious problem to use encryption the user did
not intend because of a typo.

SM> the slots you add at the end are ignored by the GC (which is what
SM> you want in your case, since they're not Lisp objects and hence the
SM> GC wouldn't know what to do with them) and can be of any type.  So
SM> just use the types you need here such that casts aren't needed.

OK.  I introduced a new field `gnutls_state_usable' to indicate the
session has been initialized.  I could have made it a byte but it may be
useful to hold Lisp-related state for this patch as it evolves.  It's
before the GC marker field "pid" so it will be noticed by alloc.c.

SM> BTW, if it makes the code simpler, you can use the following trick: use
SM> symbols, but associate an integer to each symbol by way of
SM> symbol properties.

I don't like the properties because they are loosely bound to the symbol
(for errors I think it's better to bind meaning to value tightly).  Is
it OK to do the current approach, where I have the function
`gnutls_make_error' to return the right thing, whether it's a known
integer-as-symbol or a generic integer?  I think it's the right approach
and it seems semantically sensible.  Plus it's easy to extend
`gnutls_make_error' as we need more errors by name.

SM> The type you declare should correspond to the type of the objects you
SM> store there.  Always.  If you stick to this principle and avoid freeing
SM> live objects (and stay within array bounds, and a few more such things)
SM> your code will be more portable and won't dump core (hence will be
SM> generally easier to debug).

Got it.  I think I'm doing it more correctly now and there will be no GC
issues, as I mentioned above.

On Mon, 06 Sep 2010 19:18:01 +0200 Andreas Schwab <schwab@linux-m68k.org> wrote: 

AS> Ted Zlatanov <tzz@lifelogs.com> writes:

>> +HAVE_GNUTLS=no
>> +if test "${with_gnutls}" = "yes" ; then
>> +  PKG_CHECK_MODULES([LIBGNUTLS], [gnutls >= 2.2.4])

AS> Are you sure you want to make gnutls a required dependency of Emacs?

>> +  AC_DEFINE(HAVE_GNUTLS)

AS> $ autoreconf
AS> autoheader: warning: missing template: HAVE_GNUTLS
AS> autoheader: Use AC_DEFINE([HAVE_GNUTLS], [], [Description])
AS> autoreconf: /usr/bin/autoheader failed with exit status: 1

No.  What would you suggest?

On Mon, 06 Sep 2010 17:53:46 +0200 Andreas Schwab <schwab@linux-m68k.org> wrote: 

AS> Ted Zlatanov <tzz@lifelogs.com> writes:
>>>> +DEFUN ("gnutls-init", Fgnutls_init, Sgnutls_init, 2, 2, 0,
>> ...
>>>> +  ret = gnutls_init((gnutls_session_t*)&(XPROCESS(proc)->gnutls_state), 
>> 
AS> Aliasing violation.
>> 
>> Can you explain please?

AS> The function wants to store a value of one type into an object of a
AS> different type.  BAD.  The compiler is allowed to assume the object was
AS> never changed.

OK, you mean the cast is wrong.  I fixed that.  That leaves only the
transport cast from int in gnutls_{handshake,rehandshake} which I
believe is right from the original patch.

AS> IMHO all your functions should return t on success and either some error
AS> symbol on failure or even raise an error.
>> 
>> Yes, but I'm not sure which one.  Can you recommend?

AS> Take your pick.  I don't know anything about gnutls.

Well, none of the failures are fatal and there's a lot of ways to retry
the connection.  I think it's better to return the integer error value
or t to simplify the usage.  I changed the patch accordingly.

>>>> === modified file 'src/process.h'
>>>> +
>>>> +#ifdef HAVE_GNUTLS
>>>> +    /* XXX Store GNU TLS state and auth mechanisms in Lisp_Objects. */
>>>> +    Lisp_Object gnutls_state;
>>>> +    Lisp_Object x509_cred, x509_callback;
>>>> +    Lisp_Object anon_cred;
>>>> +    Lisp_Object srp_cred;
>>>> +#endif
>> 
AS> None of them should be Lisp_Objects.  Also make sure the resources are
AS> properly released when the process object is deleted.
>> 
>> I don't know enough (the choice of using Lisp_Objects was in the
>> original patch) to know what to do instead of using Lisp_Objects.  Why
>> not, first of all?

AS> You never store Lisp_Object values in there, so what's the point?
AS> x509_callback is never used, btw.

Fixed (also see my response above to Stefan Monnier).  I've attached the
patch as it stands.

Thanks again for all your comments.  Getting there...

Ted


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: tls.patch --]
[-- Type: text/x-diff, Size: 24470 bytes --]

=== modified file 'configure.in'
--- configure.in	2010-08-23 12:54:09 +0000
+++ configure.in	2010-09-06 23:12:37 +0000
@@ -170,6 +170,7 @@
 OPTION_DEFAULT_ON([dbus],[don't compile with D-Bus support])
 OPTION_DEFAULT_ON([gconf],[don't compile with GConf support])
 OPTION_DEFAULT_ON([selinux],[don't compile with SELinux support])
+OPTION_DEFAULT_ON([gnutls],[don't use -lgnutls for SSL/TLS support])
 
 ## For the times when you want to build Emacs but don't have
 ## a suitable makeinfo, and can live without the manuals.
@@ -1998,6 +1999,13 @@
 fi
 AC_SUBST(LIBSELINUX_LIBS)
 
+HAVE_GNUTLS=no
+if test "${with_gnutls}" = "yes" ; then
+  PKG_CHECK_MODULES([LIBGNUTLS], [gnutls >= 2.2.4])
+  AC_DEFINE(HAVE_GNUTLS)
+  HAVE_GNUTLS=yes
+fi
+
 dnl Do not put whitespace before the #include statements below.
 dnl Older compilers (eg sunos4 cc) choke on it.
 HAVE_XAW3D=no
@@ -3682,6 +3690,7 @@
 echo "  Does Emacs use -ldbus?                                  ${HAVE_DBUS}"
 echo "  Does Emacs use -lgconf?                                 ${HAVE_GCONF}"
 echo "  Does Emacs use -lselinux?                               ${HAVE_LIBSELINUX}"
+echo "  Does Emacs use -lgnutls?                                ${HAVE_GNUTLS}"
 
 echo "  Does Emacs use -lfreetype?                              ${HAVE_FREETYPE}"
 echo "  Does Emacs use -lm17n-flt?                              ${HAVE_M17N_FLT}"

=== added file 'lisp/net/gnutls.el'
--- lisp/net/gnutls.el	1970-01-01 00:00:00 +0000
+++ lisp/net/gnutls.el	2010-09-06 23:12:37 +0000
@@ -0,0 +1,131 @@
+;;; gnutls.el --- Support SSL and TLS connections through GnuTLS
+;; Copyright (C) 2010 Free Software Foundation, Inc.
+
+;; Author: Ted Zlatanov <tzz@lifelogs.com>
+;; Keywords: comm, tls, ssl, encryption
+;; Originally-By: Simon Josefsson (See http://josefsson.org/emacs-security/)
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This package provides language bindings for the GnuTLS library
+;; using the corresponding core functions in gnutls.c.
+
+;; Simple test:
+;;
+;; (setq jas (open-ssl-stream "ssl" (current-buffer) "www.pdc.kth.se" 443))
+;; (process-send-string jas "GET /\r\n\r\n")
+
+;;; Code:
+
+(defconst gnutls-version "0.3.1")
+
+(defun open-ssl-stream (name buffer host service)
+  "Open a SSL connection for a service to a host.
+Returns a subprocess-object to represent the connection.
+Input and output work as for subprocesses; `delete-process' closes it.
+Args are NAME BUFFER HOST SERVICE.
+NAME is name for process.  It is modified if necessary to make it unique.
+BUFFER is the buffer (or `buffer-name') to associate with the process.
+ Process output goes at end of that buffer, unless you specify
+ an output stream or filter function to handle the output.
+ BUFFER may be also nil, meaning that this process is not associated
+ with any buffer
+Third arg is name of the host to connect to, or its IP address.
+Fourth arg SERVICE is name of the service desired, or an integer
+specifying a port number to connect to."
+  (let ((proc (open-network-stream name buffer host service)))
+    (starttls-negotiate proc)))
+
+(defun starttls-negotiate (proc &optional priority-string
+                                credentials credentials-file)
+  "Negotiate a SSL or TLS connection.
+PROC is the process returned by `starttls-open-stream'.
+PRIORITY-STRING is as per the GnuTLS docs.
+CREDENTIALS is `gnutls-x509pki', `gnutls-anon', or `gnutls-srp'.
+CREDENTIALS-FILE is a filename with meaning dependent on CREDENTIALS."
+  (let* ((credentials (or credentials 'gnutls-anon))
+         (priority-string (or priority-string
+                              (cond
+                               ((eq credentials 'gnutls-anon)
+                                "PERFORMANCE:+ANON-DH:!ARCFOUR-128")
+                               ((eq credentials 'gnutls-x509pki)
+                               "PERFORMANCE")))))
+    (gnutls-message-maybe
+     (gnutls-global-init)
+     "global_init: err=%s")
+
+    (gnutls-message-maybe
+     (gnutls-init proc)
+     "init: err=%s")
+
+    (gnutls-message-maybe
+     (gnutls-priority-set-direct proc priority-string)
+     "priority_set: err=%s")
+
+    (gnutls-message-maybe
+     (gnutls-cred-set proc credentials)
+     "credential_set: err=%s")
+
+    (cond
+     ((eq credentials 'gnutls-x509pki)
+      (gnutls-message-maybe
+       (gnutls-cert-set-x509-trust-file proc credentials-file)
+       "x509_trustfile: err=%s")))
+
+    (let ((ret 'gnutls-e-again))
+      (while (or (eq ret 'gnutls-e-again)
+                 (eq ret 'gnutls-e-interrupted))
+        (gnutls-message-maybe
+         (setq ret (gnutls-handshake proc))
+         "handshake: err=%s"))
+      (if (gnutls-errorp (ret))
+          (progn
+            (message "Ouch, error return %d" ret)
+            (setq proc nil))
+        (message "Handshake complete %d." ret)))
+     proc))
+
+(defun starttls-open-stream (name buffer host service)
+  "Open a TLS connection for a service to a host.
+Returns a subprocess-object to represent the connection.
+Input and output work as for subprocesses; `delete-process' closes it.
+Args are NAME BUFFER HOST SERVICE.
+NAME is name for process.  It is modified if necessary to make it unique.
+BUFFER is the buffer (or `buffer-name') to associate with the process.
+ Process output goes at end of that buffer, unless you specify
+ an output stream or filter function to handle the output.
+ BUFFER may be also nil, meaning that this process is not associated
+ with any buffer
+Third arg is name of the host to connect to, or its IP address.
+Fourth arg SERVICE is name of the service desired, or an integer
+specifying a port number to connect to."
+  (open-network-stream name buffer host service))
+
+(defun gnutls-message-maybe (doit format &rest params)
+  "When DOIT, message with the caller name followed by FORMAT on PARAMS."
+  (when doit
+    (message "%s: (err=%s) %s"
+             (nth 1 (backtrace-frame 4))
+             doit
+             (apply 'format format params))))
+
+(provide 'ssl)
+(provide 'gnutls)
+(provide 'starttls)
+
+;;; gnutls.el ends here

=== modified file 'src/Makefile.in'
--- src/Makefile.in	2010-08-17 21:19:11 +0000
+++ src/Makefile.in	2010-09-06 23:12:37 +0000
@@ -285,6 +285,9 @@
 
 LIBSELINUX_LIBS = @LIBSELINUX_LIBS@
 
+LIBGNUTLS_LIBS = @LIBGNUTLS_LIBS@
+LIBGNUTLS_CFLAGS = @LIBGNUTLS_CFLAGS@
+
 INTERVALS_H = dispextern.h intervals.h composite.h
 
 GETLOADAVG_LIBS = @GETLOADAVG_LIBS@
@@ -323,6 +326,7 @@
   ${C_SWITCH_X_SYSTEM} ${CFLAGS_SOUND} ${RSVG_CFLAGS} ${IMAGEMAGICK_CFLAGS} ${DBUS_CFLAGS} \
   ${GCONF_CFLAGS} ${FREETYPE_CFLAGS} ${FONTCONFIG_CFLAGS} \
   ${LIBOTF_CFLAGS} ${M17N_FLT_CFLAGS} ${DEPFLAGS} ${PROFILING_CFLAGS} \
+  $(LIBGNUTLS_CFLAGS) \
   ${C_WARNINGS_SWITCH} ${CFLAGS}
 ALL_OBJC_CFLAGS=$(ALL_CFLAGS) $(GNU_OBJC_CFLAGS)
 
@@ -347,7 +351,7 @@
 	alloc.o data.o doc.o editfns.o callint.o \
 	eval.o floatfns.o fns.o font.o print.o lread.o \
 	syntax.o $(UNEXEC_OBJ) bytecode.o \
-	process.o callproc.o \
+	process.o gnutls.o callproc.o \
 	region-cache.o sound.o atimer.o \
 	doprnt.o strftime.o intervals.o textprop.o composite.o md5.o \
 	$(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ)
@@ -598,6 +602,7 @@
    $(RSVG_LIBS) ${IMAGEMAGICK_LIBS}  $(DBUS_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \
    $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) ${GCONF_LIBS} ${LIBSELINUX_LIBS} \
    $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
+   $(LIBGNUTLS_LIBS) \
    $(LIB_GCC) $(LIB_MATH) $(LIB_STANDARD) $(LIB_GCC)
 
 all: emacs${EXEEXT} $(OTHER_FILES)

=== modified file 'src/config.in'
--- src/config.in	2010-08-17 21:19:11 +0000
+++ src/config.in	2010-09-06 23:12:37 +0000
@@ -255,6 +255,9 @@
 /* Define to 1 if you have a gif (or ungif) library. */
 #undef HAVE_GIF
 
+/* Define if we have the GNU TLS library.  */
+#undef HAVE_GNUTLS
+
 /* Define to 1 if you have the gpm library (-lgpm). */
 #undef HAVE_GPM
 
@@ -1091,6 +1094,12 @@
 #include config_opsysfile
 #include config_machfile
 
+#if HAVE_GNUTLS
+#define LIBGNUTLS $(LIBGNUTLS_LIBS)
+#else /* not HAVE_GNUTLS */
+#define LIBGNUTLS
+#endif /* not HAVE_GNUTLS */
+
 /* Set up some defines, C and LD flags for NeXTstep interface on GNUstep.
   (There is probably a better place to do this, but right now the Cocoa
    side does this in s/darwin.h and we cannot

=== modified file 'src/emacs.c'
--- src/emacs.c	2010-08-22 21:15:20 +0000
+++ src/emacs.c	2010-09-06 23:12:37 +0000
@@ -63,6 +63,10 @@
 #include "keyboard.h"
 #include "keymap.h"
 
+#ifdef HAVE_GNUTLS
+#include "gnutls.h"
+#endif
+
 #ifdef HAVE_NS
 #include "nsterm.h"
 #endif
@@ -1569,6 +1573,10 @@
       syms_of_fontset ();
 #endif /* HAVE_NS */
 
+#ifdef HAVE_GNUTLS
+      syms_of_gnutls ();
+#endif
+
 #ifdef HAVE_DBUS
       syms_of_dbusbind ();
 #endif /* HAVE_DBUS */

=== added file 'src/gnutls.c'
--- src/gnutls.c	1970-01-01 00:00:00 +0000
+++ src/gnutls.c	2010-09-06 23:12:37 +0000
@@ -0,0 +1,373 @@
+#include <config.h>
+#include <errno.h>
+#include <setjmp.h>
+
+#include "lisp.h"
+#include "process.h"
+
+#ifdef HAVE_GNUTLS
+#include <gnutls/gnutls.h>
+
+Lisp_Object Qgnutls_anon, Qgnutls_x509pki;
+Lisp_Object Qgnutls_e_interrupted, Qgnutls_e_again;
+
+int
+emacs_gnutls_write (int fildes, gnutls_session_t state, char *buf,
+                    unsigned int nbyte)
+{
+  register int rtnval, bytes_written;
+
+  bytes_written = 0;
+
+  while (nbyte > 0)
+    {
+      rtnval = gnutls_write (state, buf, nbyte);
+
+      if (rtnval == -1)
+	{
+	  if (errno == EINTR)
+	    continue;
+	  else
+	    return (bytes_written ? bytes_written : -1);
+	}
+
+      buf += rtnval;
+      nbyte -= rtnval;
+      bytes_written += rtnval;
+    }
+  fsync (STDOUT_FILENO);
+
+  return (bytes_written);
+}
+
+int
+emacs_gnutls_read (int fildes, gnutls_session_t state, char *buf,
+                   unsigned int nbyte)
+{
+  register int rtnval;
+
+  do {
+    rtnval = gnutls_read (state, buf, nbyte);
+  } while( rtnval==GNUTLS_E_INTERRUPTED || rtnval==GNUTLS_E_AGAIN);
+  fsync(STDOUT_FILENO);
+
+  return (rtnval);
+}
+
+int gnutls_callback (gnutls_session_t state, const gnutls_datum *client_certs,
+                     int ncerts, const gnutls_datum* req_ca_cert, int nreqs)
+{
+  if (client_certs == NULL) {
+    /* means the we will only be called again if the library cannot
+     * determine which certificate to send
+     */
+    return 0;
+  }
+
+  return -1; /* send no certificate to the peer */
+}
+
+/* convert an integer error to a Lisp_Object; it will be either a
+   known symbol like `gnutls_e_interrupted' and `gnutls_e_again' or
+   simply the integer value of the error.  GNUTLS_E_SUCCESS is mapped
+   to Qt.
+*/
+
+Lisp_Object gnutls_make_error (int error)
+{
+  switch (error)
+  {
+  case GNUTLS_E_SUCCESS:
+    return Qt;
+  case GNUTLS_E_AGAIN:
+    return Qgnutls_e_again;
+  case GNUTLS_E_INTERRUPTED:
+    return Qgnutls_e_interrupted;
+  }
+  
+  return make_number (error);
+}
+
+DEFUN ("gnutls-errorp", Fgnutls_errorp, Sgnutls_errorp, 1, 1, 0,
+       doc: /* Returns t if ERROR (as generated by gnutls_make_error)
+indicates a GnuTLS problem.*/)
+    (Lisp_Object error)
+{
+  if (EQ (error, Qt)) return Qnil;
+
+  return Qt;
+}
+
+DEFUN ("gnutls-init", Fgnutls_init, Sgnutls_init, 1, 1, 0,
+       doc: /* Initializes client-mode GnuTLS for process PROC.
+Currently only client mode is supported.
+
+Processes must be initialized with this function before other GNU TLS
+functions are used.  This function allocates resources which can only
+be deallocated by calling `gnutls-deinit'. Returns zero on success. */)
+    (Lisp_Object proc)
+{
+  int ret;
+  
+  CHECK_PROCESS (proc);
+
+  ret = gnutls_init (&(XPROCESS (proc)->gnutls_state), 
+                     GNUTLS_CLIENT);
+
+  XPROCESS (proc)->gnutls_state_usable = Qt;
+  
+  return gnutls_make_error (ret);
+}
+
+DEFUN ("gnutls-deinit", Fgnutls_deinit, Sgnutls_deinit, 1, 1, 0,
+       doc: /* Deallocate GNU TLS resources associated with PROCESS.
+See also `gnutls-init'. */)
+    (Lisp_Object proc)
+{
+  int ret;
+  gnutls_session_t state;
+
+  CHECK_PROCESS (proc);
+  state = XPROCESS (proc)->gnutls_state;
+
+  gnutls_deinit (state);
+  XPROCESS (proc)->gnutls_state_usable = Qnil;
+
+  return Qnil;
+}
+
+DEFUN ("gnutls-global-init", Fgnutls_global_init, 
+       Sgnutls_global_init, 0, 0, 0,
+       doc: /* Initializes global GNU TLS state to defaults.
+Call `gnutls-global-deinit' when GNU TLS usage is no longer needed.
+Returns zero on success. */)
+     (void)
+{
+  int ret = gnutls_global_init ();
+
+  return gnutls_make_error (ret);
+}
+
+DEFUN ("gnutls-global-deinit", Fgnutls_global_deinit, 
+       Sgnutls_global_deinit, 0, 0, 0,
+       doc: /* Deinitializes global GNU TLS state.
+See also `gnutls-global-init'. */)
+     (void)
+{
+  gnutls_global_deinit ();
+
+  return Qnil;
+}
+
+Lisp_Object
+generic_set_priority (int (*func)( gnutls_session_t state, const char*, const char**),
+                      Lisp_Object proc, Lisp_Object priority_string)
+{
+  gnutls_session_t state;
+  int ret;
+  
+  CHECK_PROCESS (proc);
+  CHECK_STRING (priority_string);
+  
+  state = XPROCESS (proc)->gnutls_state;
+
+  ret = (*func) (state, (char*) SDATA (priority_string), NULL);
+
+  return gnutls_make_error (ret);
+}
+
+DEFUN ("gnutls-priority-set-direct", Fgnutls_priority_set_direct, 
+       Sgnutls_priority_set_direct, 2, 2, 0,
+       doc: /* Sets the priority on the protocol versions supported by GNU TLS for PROCESS.
+
+The first parameter must be a process. Second parameter is a string
+describing the priority.  Note that the priority is set on the client.
+The server does not use the protocols's priority except for disabling
+protocols that were not specified. */)
+    (Lisp_Object process, Lisp_Object priority_string)
+{
+  Lisp_Object ret = generic_set_priority (&gnutls_priority_set_direct,
+                                          process, priority_string);
+  
+  return ret;
+}
+
+DEFUN ("gnutls-cert-set-x509-trust-file", 
+       Fgnutls_cert_set_x509_trust_file,
+       Sgnutls_cert_set_x509_trust_file, 2, 2, 0,
+       doc: /* Set X.509 client trust file for PROCESS
+CERTFILE is a PEM encoded file.  Returns zero on success. */)
+    (Lisp_Object proc, Lisp_Object certfile)
+{
+  gnutls_session_t state;
+  gnutls_certificate_credentials_t x509_cred;
+  int ret;
+
+  CHECK_STRING (certfile);
+  CHECK_PROCESS (proc);
+  
+  state = XPROCESS (proc)->gnutls_state;
+
+  x509_cred = (gnutls_certificate_credentials_t) XPROCESS (proc)->x509_cred;
+
+  ret = gnutls_certificate_set_x509_trust_file (x509_cred,
+                                                XSTRING (certfile)->data,
+                                                GNUTLS_X509_FMT_PEM);
+
+  return gnutls_make_error (ret);
+}
+
+DEFUN ("gnutls-cred-set", Fgnutls_cred_set, 
+       Sgnutls_cred_set, 2, 2, 0,
+       doc: /* Enables GNU TLS authentication for PROCESS.
+TYPE is either `gnutls-anon' or `gnutls-x509pki'.
+
+Each authentication type may need additional information in order to
+work.  For anonymous (`gnutls-anon'), see also
+`gnutls-anon-set-client-cred'. For X.509 PKI (`gnutls-x509pki'), see
+also `gnutls-x509pki-set-client-trust-file',
+`gnutls-x509pki-set-client-key-file', and
+`gnutls-x509pki-set-cert-callback'. */)
+    (Lisp_Object proc, Lisp_Object type)
+{
+  gnutls_session_t state;
+  gnutls_certificate_credentials_t x509_cred;
+  gnutls_anon_client_credentials_t anon_cred;
+  gnutls_srp_client_credentials_t srp_cred;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  
+  state = XPROCESS (proc)->gnutls_state;
+
+  if (EQ (type, Qgnutls_x509pki))
+  {
+      x509_cred = XPROCESS (proc)->x509_cred;
+      if (gnutls_certificate_allocate_credentials (&x509_cred) < 0)
+	memory_full ();
+      ret = gnutls_cred_set (state, GNUTLS_CRD_CERTIFICATE, x509_cred);
+  }
+  else if (EQ (type, Qgnutls_anon))
+  {
+      anon_cred = XPROCESS (proc)->anon_cred;
+      if (gnutls_anon_allocate_client_credentials (&anon_cred) < 0)
+	memory_full ();
+      ret = gnutls_cred_set (state, GNUTLS_CRD_ANON, anon_cred);
+  }
+  else
+  {
+   /* should this be an error or fold to gnutls-anon? */
+  }
+
+  return gnutls_make_error (ret);
+}
+
+DEFUN ("gnutls-bye", Fgnutls_bye, 
+       Sgnutls_bye, 2, 2, 0,
+       doc: /* Terminate current GNU TLS connection for PROCESS.
+The connection should have been initiated using gnutls_handshake().
+
+If CONT is not nil the TLS connection gets terminated and further
+receives and sends will be disallowed. If the return value is zero you
+may continue using the connection.  If CONT is nil, GnuTLS actually
+sends an alert containing a close request and waits for the peer to
+reply with the same message.  In order to reuse the connection you
+should wait for an EOF from the peer.
+  
+This function may also return `gnutls-e-again', or
+`gnutls-e-interrupted'. */)
+    (Lisp_Object proc, Lisp_Object cont)
+{
+  gnutls_session_t state;
+  int ret;
+
+  CHECK_PROCESS (proc);
+
+  state = XPROCESS (proc)->gnutls_state;
+
+  ret = gnutls_bye (state,
+                    NILP (cont) ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR);
+  
+  return gnutls_make_error (ret);
+}
+
+DEFUN ("gnutls-handshake", Fgnutls_handshake, 
+       Sgnutls_handshake, 1, 1, 0,
+       doc: /* Perform GNU TLS handshake for PROCESS.
+The identity of the peer is checked automatically.  This function will
+fail if any problem is encountered, and will return a negative error
+code. In case of a client, if it has been asked to resume a session,
+but the server didn't, then a full handshake will be performed.
+  
+This function may also return the non-fatal errors `gnutls-e-again',
+or `gnutls-e-interrupted'. In that case you may resume the handshake
+(by calling this function again). */)
+    (Lisp_Object proc)
+{
+  gnutls_session_t state;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  state = XPROCESS (proc)->gnutls_state;
+
+  gnutls_transport_set_ptr (state, XPROCESS (proc)->infd);
+  ret = gnutls_handshake (state);
+
+  return gnutls_make_error (ret);
+}
+
+DEFUN ("gnutls-rehandshake", Fgnutls_rehandshake, 
+       Sgnutls_rehandshake, 1, 1, 0,
+       doc: /* Renegotiate GNU TLS security parameters for PROCESS.
+This function will renegotiate security parameters with the
+client. This should only be called in case of a server.
+
+This message informs the peer that we want to renegotiate parameters
+\(perform a handshake).
+  
+If this function succeeds (returns 0), you must call the
+gnutls_handshake() function in order to negotiate the new parameters.
+  
+If the client does not wish to renegotiate parameters he will reply
+with an alert message, thus the return code will be
+`gnutls-e-warning-alert-received' and the alert will be
+`gnutls-e-no-renegotiation'. */)
+    (Lisp_Object proc)
+{
+  gnutls_session_t state;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  state = XPROCESS (proc)->gnutls_state;
+
+  gnutls_transport_set_ptr (state, XPROCESS (proc)->infd);
+  ret = gnutls_rehandshake (state);
+
+  return gnutls_make_error (ret);
+}
+
+void
+syms_of_gnutls (void)
+{
+  Qgnutls_anon = intern_c_string ("gnutls-anon");
+  staticpro (&Qgnutls_anon);
+  Qgnutls_x509pki = intern_c_string ("gnutls-x509pki");
+  staticpro (&Qgnutls_x509pki);
+  Qgnutls_e_interrupted = make_number(GNUTLS_E_INTERRUPTED);
+  staticpro (&Qgnutls_e_interrupted);
+  Qgnutls_e_again = make_number(GNUTLS_E_AGAIN);
+  staticpro (&Qgnutls_e_again);
+
+  defsubr (&Sgnutls_errorp);
+  defsubr (&Sgnutls_global_init);
+  defsubr (&Sgnutls_global_deinit);
+  defsubr (&Sgnutls_init);
+  defsubr (&Sgnutls_deinit);
+  defsubr (&Sgnutls_priority_set_direct);
+  defsubr (&Sgnutls_cred_set);
+  defsubr (&Sgnutls_handshake);
+  defsubr (&Sgnutls_rehandshake);
+  defsubr (&Sgnutls_cert_set_x509_trust_file);
+  defsubr (&Sgnutls_bye);
+}
+#endif

=== added file 'src/gnutls.h'
--- src/gnutls.h	1970-01-01 00:00:00 +0000
+++ src/gnutls.h	2010-09-06 23:12:37 +0000
@@ -0,0 +1,4 @@
+#ifdef HAVE_GNUTLS
+#include <gnutls/gnutls.h>
+
+#endif

=== modified file 'src/lisp.h'
--- src/lisp.h	2010-08-09 19:25:41 +0000
+++ src/lisp.h	2010-09-06 23:12:37 +0000
@@ -3350,6 +3350,7 @@
 extern void syms_of_process (void);
 extern void setup_process_coding_systems (Lisp_Object);
 
+
 /* Defined in callproc.c */
 extern Lisp_Object Vexec_path, Vexec_suffixes,
                    Vexec_directory, Vdata_directory;
@@ -3589,6 +3590,11 @@
 void syms_of_dbusbind (void);
 #endif
 
+#ifdef HAVE_GNUTLS
+/* Defined in gnutls.c */
+extern void syms_of_gnutls (void);
+#endif
+
 #ifdef DOS_NT
 /* Defined in msdos.c, w32.c */
 extern char *emacs_root_dir (void);

=== modified file 'src/process.c'
--- src/process.c	2010-08-22 15:14:37 +0000
+++ src/process.c	2010-09-06 23:12:37 +0000
@@ -105,6 +105,9 @@
 #include "sysselect.h"
 #include "syssignal.h"
 #include "syswait.h"
+#ifdef HAVE_GNUTLS
+#include "gnutls.h"
+#endif
 
 #if defined (USE_GTK) || defined (HAVE_GCONF)
 #include "xgselect.h"
@@ -1526,6 +1529,10 @@
   XPROCESS (proc)->filter = Qnil;
   XPROCESS (proc)->command = Flist (nargs - 2, args + 2);
 
+#ifdef HAVE_GNUTLS
+  XPROCESS (proc)->gnutls_state_usable = Qnil;
+#endif
+
 #ifdef ADAPTIVE_READ_BUFFERING
   XPROCESS (proc)->adaptive_read_buffering
     = (NILP (Vprocess_adaptive_read_buffering) ? 0
@@ -5097,7 +5104,12 @@
 #endif
   if (proc_buffered_char[channel] < 0)
     {
-      nbytes = emacs_read (channel, chars + carryover, readmax);
+#ifdef HAVE_GNUTLS
+      if (NETCONN_P(proc) && !NILP (XPROCESS(proc)->gnutls_state_usable))
+	nbytes = emacs_gnutls_read (channel, XPROCESS(proc)->gnutls_state, chars + carryover, readmax);
+      else
+#endif
+	nbytes = emacs_read (channel, chars + carryover, readmax);
 #ifdef ADAPTIVE_READ_BUFFERING
       if (nbytes > 0 && p->adaptive_read_buffering)
 	{
@@ -5130,7 +5142,12 @@
     {
       chars[carryover] = proc_buffered_char[channel];
       proc_buffered_char[channel] = -1;
-      nbytes = emacs_read (channel, chars + carryover + 1,  readmax - 1);
+#ifdef HAVE_GNUTLS
+      if (NETCONN_P(proc) && !NILP (XPROCESS(proc)->gnutls_state_usable))
+	nbytes = emacs_gnutls_read (channel, XPROCESS(proc)->gnutls_state, chars + carryover + 1, readmax - 1);
+      else
+#endif
+	nbytes = emacs_read (channel, chars + carryover + 1,  readmax - 1);
       if (nbytes < 0)
 	nbytes = 1;
       else
@@ -5540,7 +5557,14 @@
 	      else
 #endif
 		{
-		  rv = emacs_write (outfd, (char *) buf, this);
+#ifdef HAVE_GNUTLS
+		  if (NETCONN_P(proc) && !NILP (XPROCESS(proc)->gnutls_state_usable))
+		    rv = emacs_gnutls_write (outfd,
+					     XPROCESS(proc)->gnutls_state, 
+					     (char *) buf, this);
+		  else
+#endif
+		    rv = emacs_write (outfd, (char *) buf, this);
 #ifdef ADAPTIVE_READ_BUFFERING
 		  if (p->read_output_delay > 0
 		      && p->adaptive_read_buffering == 1)

=== modified file 'src/process.h'
--- src/process.h	2010-08-11 12:34:46 +0000
+++ src/process.h	2010-09-06 23:12:37 +0000
@@ -24,6 +24,10 @@
 #include <unistd.h>
 #endif
 
+#ifdef HAVE_GNUTLS
+#include "gnutls.h"
+#endif
+
 /* This structure records information about a subprocess
    or network connection.
 
@@ -76,6 +80,10 @@
     /* Working buffer for encoding.  */
     Lisp_Object encoding_buf;
 
+#ifdef HAVE_GNUTLS
+    Lisp_Object gnutls_state_usable;
+#endif
+
     /* After this point, there are no Lisp_Objects any more.  */
     /* alloc.c assumes that `pid' is the first such non-Lisp slot.  */
 
@@ -121,6 +129,12 @@
        needs to be synced to `status'.  */
     unsigned int raw_status_new : 1;
     int raw_status;
+
+#ifdef HAVE_GNUTLS
+    gnutls_session_t gnutls_state;
+    gnutls_certificate_client_credentials x509_cred;
+    gnutls_anon_client_credentials_t anon_cred;
+#endif
 };
 
 /* Every field in the preceding structure except for the first two


[-- Attachment #3: Type: text/plain, Size: 146 bytes --]

_______________________________________________
Gnutls-devel mailing list
Gnutls-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/gnutls-devel

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-06 17:18                             ` Andreas Schwab
@ 2010-09-09 15:12                               ` Ted Zlatanov
  2010-09-09 22:00                                 ` Lars Magne Ingebrigtsen
  0 siblings, 1 reply; 93+ messages in thread
From: Ted Zlatanov @ 2010-09-09 15:12 UTC (permalink / raw)
  To: emacs-devel; +Cc: gnutls-devel

On Mon, 06 Sep 2010 19:18:01 +0200 Andreas Schwab <schwab@linux-m68k.org> wrote: 

AS> Ted Zlatanov <tzz@lifelogs.com> writes:
>> @@ -1998,6 +1999,13 @@
>> fi
>> AC_SUBST(LIBSELINUX_LIBS)
>> 
>> +HAVE_GNUTLS=no
>> +if test "${with_gnutls}" = "yes" ; then
>> +  PKG_CHECK_MODULES([LIBGNUTLS], [gnutls >= 2.2.4])

AS> Are you sure you want to make gnutls a required dependency of Emacs?

>> +  AC_DEFINE(HAVE_GNUTLS)

AS> $ autoreconf
AS> autoheader: warning: missing template: HAVE_GNUTLS
AS> autoheader: Use AC_DEFINE([HAVE_GNUTLS], [], [Description])
AS> autoreconf: /usr/bin/autoheader failed with exit status: 1

(second time, I think the first was buried in too much text)

Can you or Stefan or anyone else please suggest a better solution?

Ted




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-09 15:12                               ` Ted Zlatanov
@ 2010-09-09 22:00                                 ` Lars Magne Ingebrigtsen
  2010-09-10  8:33                                   ` Andreas Schwab
  0 siblings, 1 reply; 93+ messages in thread
From: Lars Magne Ingebrigtsen @ 2010-09-09 22:00 UTC (permalink / raw)
  To: emacs-devel; +Cc: gnutls-devel

Ted Zlatanov <tzz@lifelogs.com> writes:

[...]

>>> +HAVE_GNUTLS=no
>>> +if test "${with_gnutls}" = "yes" ; then
>>> +  PKG_CHECK_MODULES([LIBGNUTLS], [gnutls >= 2.2.4])
>
> AS> Are you sure you want to make gnutls a required dependency of Emacs?

How does this make gnutls a required dependency?  I'm not really very
familiar with the autoconf language, but I thought that this meant that
somebody had said --with-gnutls=yes...

But I think gnutls should be a required dependency.  So much
communication these days require having tsl/ssl functionality that it
seems totally reasonable to me to have that as a requirement.

-- 
(domestic pets only, the antidote for overdose, milk.)
  larsi@gnus.org * Lars Magne Ingebrigtsen




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-09 22:00                                 ` Lars Magne Ingebrigtsen
@ 2010-09-10  8:33                                   ` Andreas Schwab
  2010-09-10 10:59                                     ` Lars Magne Ingebrigtsen
  0 siblings, 1 reply; 93+ messages in thread
From: Andreas Schwab @ 2010-09-10  8:33 UTC (permalink / raw)
  To: emacs-devel

Lars Magne Ingebrigtsen <larsi@gnus.org> writes:

> Ted Zlatanov <tzz@lifelogs.com> writes:
>
> [...]
>
>>>> +HAVE_GNUTLS=no
>>>> +if test "${with_gnutls}" = "yes" ; then
>>>> +  PKG_CHECK_MODULES([LIBGNUTLS], [gnutls >= 2.2.4])
>>
>> AS> Are you sure you want to make gnutls a required dependency of Emacs?
>
> How does this make gnutls a required dependency?

By erroring out by default if gnutls is not available.

>  I'm not really very familiar with the autoconf language, but I
> thought that this meant that somebody had said --with-gnutls=yes...

In the current incarnation --with-gnutls is the default.

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."



^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-10  8:33                                   ` Andreas Schwab
@ 2010-09-10 10:59                                     ` Lars Magne Ingebrigtsen
  2010-09-10 14:06                                       ` Ted Zlatanov
  0 siblings, 1 reply; 93+ messages in thread
From: Lars Magne Ingebrigtsen @ 2010-09-10 10:59 UTC (permalink / raw)
  To: emacs-devel

Andreas Schwab <schwab@linux-m68k.org> writes:

>> How does this make gnutls a required dependency?
>
> By erroring out by default if gnutls is not available.

Ah, right.  So it should be more like:

HAVE_GNUTLS=no
if test "${with_gnutls}" = "yes" ; then
  PKG_CHECK_MODULES(LIBGNUTLS, gnutls >= 2.2.4, HAVE_GNUTLS=yes, HAVE_GNUTLS=no)
  if test "${HAVE_GNUTLS}" = "yes"; then
    AC_DEFINE(HAVE_GNUTLS)
  fi
fi

-- 
(domestic pets only, the antidote for overdose, milk.)
  larsi@gnus.org * Lars Magne Ingebrigtsen




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-10 10:59                                     ` Lars Magne Ingebrigtsen
@ 2010-09-10 14:06                                       ` Ted Zlatanov
  2010-09-11 12:45                                         ` Stefan Monnier
  0 siblings, 1 reply; 93+ messages in thread
From: Ted Zlatanov @ 2010-09-10 14:06 UTC (permalink / raw)
  To: emacs-devel

On Fri, 10 Sep 2010 12:59:50 +0200 Lars Magne Ingebrigtsen <larsi@gnus.org> wrote: 

LMI> Andreas Schwab <schwab@linux-m68k.org> writes:
>>> How does this make gnutls a required dependency?
>> 
>> By erroring out by default if gnutls is not available.

LMI> Ah, right.  So it should be more like:

LMI> HAVE_GNUTLS=no
LMI> if test "${with_gnutls}" = "yes" ; then
LMI>   PKG_CHECK_MODULES(LIBGNUTLS, gnutls >= 2.2.4, HAVE_GNUTLS=yes, HAVE_GNUTLS=no)
LMI>   if test "${HAVE_GNUTLS}" = "yes"; then
LMI>     AC_DEFINE(HAVE_GNUTLS)
LMI>   fi
LMI> fi

Oh, I thought Andreas was saying there's some problem with the
PKG_CHECK_MODULES macros so they only work when libgnutls-dev is
installed.  Thanks for explaining.

I feel (as Lars does) that GnuTLS should be a required part of Emacs,
disabled by choice.  Today it's hard to imagine a system where you would
not want GnuTLS enabled if it was available for the platform.  In any
case, if a maintainer could give me a definite yes or no, I would
appreciate it.  Switching the default to "no" is not a problem
technically.

Ted




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-10 14:06                                       ` Ted Zlatanov
@ 2010-09-11 12:45                                         ` Stefan Monnier
  2010-09-14 15:34                                           ` Ted Zlatanov
  0 siblings, 1 reply; 93+ messages in thread
From: Stefan Monnier @ 2010-09-11 12:45 UTC (permalink / raw)
  To: Ted Zlatanov; +Cc: emacs-devel

> I feel (as Lars does) that GnuTLS should be a required part of Emacs,
> disabled by choice.  Today it's hard to imagine a system where you would
> not want GnuTLS enabled if it was available for the platform.  In any
> case, if a maintainer could give me a definite yes or no, I would
> appreciate it.  Switching the default to "no" is not a problem
> technically.

I think it's OK to let it default to yes.
If it proves to be too much of a problem, we'll revisit this choice.


        Stefan



^ permalink raw reply	[flat|nested] 93+ messages in thread

* re: Emacs core TLS support
  2010-09-06 23:13                               ` Ted Zlatanov
@ 2010-09-11 14:59                                 ` Ted Zlatanov
  2010-09-11 15:00                                   ` Ted Zlatanov
  2010-09-13  7:49                                   ` Nikos Mavrogiannopoulos
  0 siblings, 2 replies; 93+ messages in thread
From: Ted Zlatanov @ 2010-09-11 14:59 UTC (permalink / raw)
  To: gnutls-devel; +Cc: emacs-devel

Nearly ready.  Since the last patch we have:

- full initialization and handshake (no memory issues, etc.)

- everything happens in gnutls-boot, including global initialization;
  all the parameters are either x509 or anon

- use of gnutls_initstage in the process to mark progress of
  initialization and whether the process is done initializing and
  handshaking

- no SRP anywhere, just anon and x509 (I'll add SRP if we need it and
  when the other two are working)

Now I get GNUTLS_E_INSUFFICIENT_CREDENTIALS when I open a x509
connection to an IMAP TLS server so I think there's still work to do.
The trust file seems to be wrong (see lisp/net/gnutls.el, I tried both
"/etc/ssl/certs/ca-certificates.crt" and "/etc/ssl/certs/ca.pem").

The GnuTLS examples don't seem to cover the standard situation of
talking to a web server over SSL and possibly accepting an insecure
connection if the server credentials are bad.  I must have missed
something.  Could the GnuTLS developers look at my patch and help me
out?

Thanks
Ted

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-11 14:59                                 ` Ted Zlatanov
@ 2010-09-11 15:00                                   ` Ted Zlatanov
  2010-09-12 10:58                                     ` Stefan Monnier
  2010-09-13  7:49                                   ` Nikos Mavrogiannopoulos
  1 sibling, 1 reply; 93+ messages in thread
From: Ted Zlatanov @ 2010-09-11 15:00 UTC (permalink / raw)
  To: emacs-devel; +Cc: gnutls-devel

[-- Attachment #1: Type: text/plain, Size: 135 bytes --]

On Sat, 11 Sep 2010 09:59:59 -0500 Ted Zlatanov <tzz@lifelogs.com> wrote: 

TZ> Nearly ready.  Since the last patch we have:

patch++


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: tls.patch --]
[-- Type: text/x-diff, Size: 27483 bytes --]

=== modified file 'configure.in'
--- configure.in	2010-08-23 12:54:09 +0000
+++ configure.in	2010-09-11 14:58:24 +0000
@@ -170,6 +170,7 @@
 OPTION_DEFAULT_ON([dbus],[don't compile with D-Bus support])
 OPTION_DEFAULT_ON([gconf],[don't compile with GConf support])
 OPTION_DEFAULT_ON([selinux],[don't compile with SELinux support])
+OPTION_DEFAULT_ON([gnutls],[don't use -lgnutls for SSL/TLS support])
 
 ## For the times when you want to build Emacs but don't have
 ## a suitable makeinfo, and can live without the manuals.
@@ -1998,6 +1999,13 @@
 fi
 AC_SUBST(LIBSELINUX_LIBS)
 
+HAVE_GNUTLS=no
+if test "${with_gnutls}" = "yes" ; then
+  PKG_CHECK_MODULES([LIBGNUTLS], [gnutls >= 2.2.4])
+  AC_DEFINE(HAVE_GNUTLS)
+  HAVE_GNUTLS=yes
+fi
+
 dnl Do not put whitespace before the #include statements below.
 dnl Older compilers (eg sunos4 cc) choke on it.
 HAVE_XAW3D=no
@@ -3682,6 +3690,7 @@
 echo "  Does Emacs use -ldbus?                                  ${HAVE_DBUS}"
 echo "  Does Emacs use -lgconf?                                 ${HAVE_GCONF}"
 echo "  Does Emacs use -lselinux?                               ${HAVE_LIBSELINUX}"
+echo "  Does Emacs use -lgnutls?                                ${HAVE_GNUTLS}"
 
 echo "  Does Emacs use -lfreetype?                              ${HAVE_FREETYPE}"
 echo "  Does Emacs use -lm17n-flt?                              ${HAVE_M17N_FLT}"

=== added file 'lisp/net/gnutls.el'
--- lisp/net/gnutls.el	1970-01-01 00:00:00 +0000
+++ lisp/net/gnutls.el	2010-09-11 14:58:24 +0000
@@ -0,0 +1,129 @@
+;;; gnutls.el --- Support SSL and TLS connections through GnuTLS
+;; Copyright (C) 2010 Free Software Foundation, Inc.
+
+;; Author: Ted Zlatanov <tzz@lifelogs.com>
+;; Keywords: comm, tls, ssl, encryption
+;; Originally-By: Simon Josefsson (See http://josefsson.org/emacs-security/)
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This package provides language bindings for the GnuTLS library
+;; using the corresponding core functions in gnutls.c.
+
+;; Simple test:
+;;
+;; (setq jas (open-ssl-stream "ssl" (current-buffer) "www.pdc.kth.se" 443))
+;; (process-send-string jas "GET /\r\n\r\n")
+
+;;; Code:
+
+(defconst gnutls-version "0.3.1")
+
+(defun open-ssl-stream (name buffer host service)
+  "Open a SSL connection for a service to a host.
+Returns a subprocess-object to represent the connection.
+Input and output work as for subprocesses; `delete-process' closes it.
+Args are NAME BUFFER HOST SERVICE.
+NAME is name for process.  It is modified if necessary to make it unique.
+BUFFER is the buffer (or `buffer-name') to associate with the process.
+ Process output goes at end of that buffer, unless you specify
+ an output stream or filter function to handle the output.
+ BUFFER may be also nil, meaning that this process is not associated
+ with any buffer
+Third arg is name of the host to connect to, or its IP address.
+Fourth arg SERVICE is name of the service desired, or an integer
+specifying a port number to connect to."
+  (let ((proc (open-network-stream name buffer host service)))
+    (starttls-negotiate proc nil 'gnutls-x509pki)))
+
+;; (open-ssl-stream "tls" "tls-buffer" "yourserver.com" "https")
+(defun starttls-negotiate (proc &optional priority-string
+                                credentials credentials-file)
+  "Negotiate a SSL or TLS connection.
+PROC is the process returned by `starttls-open-stream'.
+PRIORITY-STRING is as per the GnuTLS docs.
+CREDENTIALS is `gnutls-x509pki' or `gnutls-anon'.
+CREDENTIALS-FILE is a filename with meaning dependent on CREDENTIALS."
+  (let* ((credentials (or credentials 'gnutls-x509pki))
+         (credentials-file (or credentials-file
+                               ;"/etc/ssl/certs/ca-certificates.crt"
+                               "/etc/ssl/certs/ca.pem"
+                               ))
+
+         (priority-string (or priority-string
+                              (cond
+                               ((eq credentials 'gnutls-anon)
+                                "PERFORMANCE:+ANON-DH:!ARCFOUR-128")
+                               ((eq credentials 'gnutls-x509pki)
+                                "PERFORMANCE"))))
+         ret)
+
+    (gnutls-message-maybe
+     (setq ret (gnutls-boot proc priority-string credentials credentials-file))
+     "boot: %s")
+
+    (when (gnutls-errorp ret)
+      (error "Could not boot GnuTLS for this process"));
+
+    (let ((ret 'gnutls-e-again)
+          (n 25))
+      (while (and (or (eq ret 'gnutls-e-again)
+                      (eq ret 'gnutls-e-interrupted))
+                  (> n 0))
+        (decf n)
+        (gnutls-message-maybe
+         (setq ret (gnutls-handshake proc))
+         "handshake: %s")
+        (debug "handshake ret" ret))
+      (if (gnutls-errorp ret)
+          (progn
+            (message "Ouch, error return %s" ret)
+            (setq proc nil))
+        (message "Handshake complete %s." ret)))
+     proc))
+
+(defun starttls-open-stream (name buffer host service)
+  "Open a TLS connection for a service to a host.
+Returns a subprocess-object to represent the connection.
+Input and output work as for subprocesses; `delete-process' closes it.
+Args are NAME BUFFER HOST SERVICE.
+NAME is name for process.  It is modified if necessary to make it unique.
+BUFFER is the buffer (or `buffer-name') to associate with the process.
+ Process output goes at end of that buffer, unless you specify
+ an output stream or filter function to handle the output.
+ BUFFER may be also nil, meaning that this process is not associated
+ with any buffer
+Third arg is name of the host to connect to, or its IP address.
+Fourth arg SERVICE is name of the service desired, or an integer
+specifying a port number to connect to."
+  (open-network-stream name buffer host service))
+
+(defun gnutls-message-maybe (doit format &rest params)
+  "When DOIT, message with the caller name followed by FORMAT on PARAMS."
+  ;; (apply 'debug format (or params '(nil)))
+  (when (gnutls-errorp doit)
+    (message "%s: (err=%s) %s"
+             "gnutls.el"
+             doit
+             (apply 'format format (or params '(nil))))))
+
+(provide 'ssl)
+(provide 'gnutls)
+(provide 'starttls)
+
+;;; gnutls.el ends here

=== modified file 'src/Makefile.in'
--- src/Makefile.in	2010-08-17 21:19:11 +0000
+++ src/Makefile.in	2010-09-11 14:58:24 +0000
@@ -285,6 +285,9 @@
 
 LIBSELINUX_LIBS = @LIBSELINUX_LIBS@
 
+LIBGNUTLS_LIBS = @LIBGNUTLS_LIBS@
+LIBGNUTLS_CFLAGS = @LIBGNUTLS_CFLAGS@
+
 INTERVALS_H = dispextern.h intervals.h composite.h
 
 GETLOADAVG_LIBS = @GETLOADAVG_LIBS@
@@ -323,6 +326,7 @@
   ${C_SWITCH_X_SYSTEM} ${CFLAGS_SOUND} ${RSVG_CFLAGS} ${IMAGEMAGICK_CFLAGS} ${DBUS_CFLAGS} \
   ${GCONF_CFLAGS} ${FREETYPE_CFLAGS} ${FONTCONFIG_CFLAGS} \
   ${LIBOTF_CFLAGS} ${M17N_FLT_CFLAGS} ${DEPFLAGS} ${PROFILING_CFLAGS} \
+  $(LIBGNUTLS_CFLAGS) \
   ${C_WARNINGS_SWITCH} ${CFLAGS}
 ALL_OBJC_CFLAGS=$(ALL_CFLAGS) $(GNU_OBJC_CFLAGS)
 
@@ -347,7 +351,7 @@
 	alloc.o data.o doc.o editfns.o callint.o \
 	eval.o floatfns.o fns.o font.o print.o lread.o \
 	syntax.o $(UNEXEC_OBJ) bytecode.o \
-	process.o callproc.o \
+	process.o gnutls.o callproc.o \
 	region-cache.o sound.o atimer.o \
 	doprnt.o strftime.o intervals.o textprop.o composite.o md5.o \
 	$(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ)
@@ -598,6 +602,7 @@
    $(RSVG_LIBS) ${IMAGEMAGICK_LIBS}  $(DBUS_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \
    $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) ${GCONF_LIBS} ${LIBSELINUX_LIBS} \
    $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
+   $(LIBGNUTLS_LIBS) \
    $(LIB_GCC) $(LIB_MATH) $(LIB_STANDARD) $(LIB_GCC)
 
 all: emacs${EXEEXT} $(OTHER_FILES)

=== modified file 'src/config.in'
--- src/config.in	2010-08-17 21:19:11 +0000
+++ src/config.in	2010-09-11 14:58:24 +0000
@@ -255,6 +255,9 @@
 /* Define to 1 if you have a gif (or ungif) library. */
 #undef HAVE_GIF
 
+/* Define if we have the GNU TLS library.  */
+#undef HAVE_GNUTLS
+
 /* Define to 1 if you have the gpm library (-lgpm). */
 #undef HAVE_GPM
 
@@ -1091,6 +1094,12 @@
 #include config_opsysfile
 #include config_machfile
 
+#if HAVE_GNUTLS
+#define LIBGNUTLS $(LIBGNUTLS_LIBS)
+#else /* not HAVE_GNUTLS */
+#define LIBGNUTLS
+#endif /* not HAVE_GNUTLS */
+
 /* Set up some defines, C and LD flags for NeXTstep interface on GNUstep.
   (There is probably a better place to do this, but right now the Cocoa
    side does this in s/darwin.h and we cannot

=== modified file 'src/emacs.c'
--- src/emacs.c	2010-08-22 21:15:20 +0000
+++ src/emacs.c	2010-09-11 14:58:24 +0000
@@ -63,6 +63,10 @@
 #include "keyboard.h"
 #include "keymap.h"
 
+#ifdef HAVE_GNUTLS
+#include "gnutls.h"
+#endif
+
 #ifdef HAVE_NS
 #include "nsterm.h"
 #endif
@@ -1569,6 +1573,10 @@
       syms_of_fontset ();
 #endif /* HAVE_NS */
 
+#ifdef HAVE_GNUTLS
+      syms_of_gnutls ();
+#endif
+
 #ifdef HAVE_DBUS
       syms_of_dbusbind ();
 #endif /* HAVE_DBUS */

=== added file 'src/gnutls.c'
--- src/gnutls.c	1970-01-01 00:00:00 +0000
+++ src/gnutls.c	2010-09-11 14:58:24 +0000
@@ -0,0 +1,436 @@
+#include <config.h>
+#include <errno.h>
+#include <setjmp.h>
+
+#include "lisp.h"
+#include "process.h"
+
+#ifdef HAVE_GNUTLS
+#include <gnutls/gnutls.h>
+
+Lisp_Object Qgnutls_anon, Qgnutls_x509pki;
+Lisp_Object Qgnutls_e_interrupted, Qgnutls_e_again, Qgnutls_e_invalid_session, Qgnutls_e_not_ready_for_handshake;
+int global_initialized;
+
+int
+emacs_gnutls_write (int fildes, gnutls_session_t state, char *buf,
+                    unsigned int nbyte)
+{
+  register int rtnval, bytes_written;
+
+  bytes_written = 0;
+
+  while (nbyte > 0)
+    {
+      rtnval = gnutls_write (state, buf, nbyte);
+
+      if (rtnval == -1)
+	{
+	  if (errno == EINTR)
+	    continue;
+	  else
+	    return (bytes_written ? bytes_written : -1);
+	}
+
+      buf += rtnval;
+      nbyte -= rtnval;
+      bytes_written += rtnval;
+    }
+  fsync (STDOUT_FILENO);
+
+  return (bytes_written);
+}
+
+int
+emacs_gnutls_read (int fildes, gnutls_session_t state, char *buf,
+                   unsigned int nbyte)
+{
+  register int rtnval;
+
+  do {
+    rtnval = gnutls_read (state, buf, nbyte);
+  } while( rtnval==GNUTLS_E_INTERRUPTED || rtnval==GNUTLS_E_AGAIN);
+  fsync(STDOUT_FILENO);
+
+  return (rtnval);
+}
+
+int gnutls_callback (gnutls_session_t state, const gnutls_datum *client_certs,
+                     int ncerts, const gnutls_datum* req_ca_cert, int nreqs)
+{
+  if (client_certs == NULL) {
+    /* means the we will only be called again if the library cannot
+     * determine which certificate to send
+     */
+    return 0;
+  }
+
+  return -1; /* send no certificate to the peer */
+}
+
+/* convert an integer error to a Lisp_Object; it will be either a
+   known symbol like `gnutls_e_interrupted' and `gnutls_e_again' or
+   simply the integer value of the error.  GNUTLS_E_SUCCESS is mapped
+   to Qt.
+*/
+
+Lisp_Object gnutls_make_error (int error)
+{
+  switch (error)
+  {
+  case GNUTLS_E_SUCCESS:
+    return Qt;
+  case GNUTLS_E_AGAIN:
+    return Qgnutls_e_again;
+  case GNUTLS_E_INTERRUPTED:
+    return Qgnutls_e_interrupted;
+  case GNUTLS_E_INVALID_SESSION:
+    return Qgnutls_e_invalid_session;
+  }
+  
+  return make_number (error);
+}
+
+DEFUN ("gnutls-get-initstage", Fgnutls_get_initstage, Sgnutls_get_initstage, 1, 1, 0,
+       doc: /* Return the GnuTLS init stage of PROCESS.
+See also `gnutls-boot'. */)
+    (Lisp_Object proc)
+{
+  CHECK_PROCESS (proc);
+
+  return make_number (GNUTLS_INITSTAGE (proc));
+}
+
+DEFUN ("gnutls-errorp", Fgnutls_errorp, Sgnutls_errorp, 1, 1, 0,
+       doc: /* Returns t if ERROR (as generated by gnutls_make_error)
+indicates a GnuTLS problem.*/)
+    (Lisp_Object error)
+{
+  if (EQ (error, Qt)) return Qnil;
+
+  return Qt;
+}
+
+DEFUN ("gnutls-deinit", Fgnutls_deinit, Sgnutls_deinit, 1, 1, 0,
+       doc: /* Deallocate GNU TLS resources associated with PROCESS.
+See also `gnutls-init'. */)
+    (Lisp_Object proc)
+{
+  gnutls_session_t state;
+
+  CHECK_PROCESS (proc);
+  state = XPROCESS (proc)->gnutls_state;
+
+  if (GNUTLS_INITSTAGE (proc) >= GNUTLS_STAGE_INIT)
+  {
+      gnutls_deinit (state);
+      GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_INIT - 1;
+  }
+
+  return Qt;
+}
+
+DEFUN ("gnutls-global-init", Fgnutls_global_init, 
+       Sgnutls_global_init, 0, 0, 0,
+       doc: /* Initializes global GNU TLS state to defaults.
+Call `gnutls-global-deinit' when GNU TLS usage is no longer needed.
+Returns zero on success. */)
+     (void)
+{
+  int ret = GNUTLS_E_SUCCESS;
+
+  if (!global_initialized)
+    ret = gnutls_global_init ();
+
+  global_initialized = 1;
+    
+  return gnutls_make_error (ret);
+}
+
+DEFUN ("gnutls-global-deinit", Fgnutls_global_deinit, 
+       Sgnutls_global_deinit, 0, 0, 0,
+       doc: /* Deinitializes global GNU TLS state.
+See also `gnutls-global-init'. */)
+     (void)
+{
+  if (global_initialized)
+    gnutls_global_deinit ();
+
+  global_initialized = 0;
+    
+  return gnutls_make_error (GNUTLS_E_SUCCESS);
+}
+
+DEFUN ("gnutls-boot", Fgnutls_boot, Sgnutls_boot, 3, 6, 0,
+       doc: /* Initializes client-mode GnuTLS for process PROC.
+Currently only client mode is supported.  Returns a success/failure
+value you can check with `gnutls-errorp'.
+
+PRIORITY_STRING is a string describing the priority.
+TYPE is either `gnutls-anon' or `gnutls-x509pki'.
+TRUSTFILE is a PEM encoded trust file for `gnutls-x509pki'.
+KEYFILE is ... for `gnutls-x509pki' (TODO).
+CALLBACK is ... for `gnutls-x509pki' (TODO).
+
+Note that the priority is set on the client.  The server does not use
+the protocols's priority except for disabling protocols that were not
+specified.
+
+Processes must be initialized with this function before other GNU TLS
+functions are used.  This function allocates resources which can only
+be deallocated by calling `gnutls-deinit' or by calling it again.
+
+Each authentication type may need additional information in order to
+work.  For X.509 PKI (`gnutls-x509pki'), you need TRUSTFILE and
+KEYFILE and optionally CALLBACK. */)
+    (Lisp_Object proc, Lisp_Object priority_string, Lisp_Object type, Lisp_Object trustfile, Lisp_Object keyfile, Lisp_Object callback)
+{
+  int ret = GNUTLS_E_SUCCESS;
+  gnutls_session_t state;
+  gnutls_certificate_credentials_t x509_cred;
+  gnutls_anon_client_credentials_t anon_cred;
+  gnutls_srp_client_credentials_t srp_cred;
+  Lisp_Object global_init;
+  
+  CHECK_PROCESS (proc);
+  CHECK_SYMBOL (type);
+  CHECK_STRING (priority_string);
+
+  state = XPROCESS (proc)->gnutls_state;
+
+  /* always initialize globals */
+  global_init = Fgnutls_global_init ();
+  if (! NILP (Fgnutls_errorp (global_init)))
+    return global_init;
+  
+  /* deinit and free resources */
+  if (GNUTLS_INITSTAGE (proc) >= GNUTLS_STAGE_CRED_ALLOC)
+  {
+      message ("gnutls: deallocating certificates");
+
+      if (EQ (type, Qgnutls_x509pki))
+      {
+          message ("gnutls: deallocating x509 certificates");
+
+          x509_cred = XPROCESS (proc)->x509_cred;
+          gnutls_certificate_free_credentials (x509_cred);
+      }
+      else if (EQ (type, Qgnutls_anon))
+      {
+          message ("gnutls: deallocating anon certificates");
+
+          anon_cred = XPROCESS (proc)->anon_cred;
+          gnutls_anon_free_client_credentials (anon_cred);
+      }
+      else
+      {
+          error ("unknown credential type");
+          ret = GNUTLS_EMACS_ERROR_INVALID_TYPE;
+      }
+      
+      if (GNUTLS_INITSTAGE (proc) >= GNUTLS_STAGE_INIT)
+      {
+          message ("gnutls: deinitializing");
+
+          Fgnutls_deinit (proc);
+      }
+  }
+  
+  GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_EMPTY;
+
+  message ("gnutls: allocating credentials");
+
+  if (EQ (type, Qgnutls_x509pki))
+  {
+      message ("gnutls: allocating x509 credentials");
+
+      x509_cred = XPROCESS (proc)->x509_cred;
+      if (gnutls_certificate_allocate_credentials (&x509_cred) < 0)
+	memory_full ();
+  }
+  else if (EQ (type, Qgnutls_anon))
+  {
+      message ("gnutls: allocating anon credentials");
+      
+      anon_cred = XPROCESS (proc)->anon_cred;
+      if (gnutls_anon_allocate_client_credentials (&anon_cred) < 0)
+	memory_full ();
+  }
+  else
+  {
+      error ("unknown credential type");
+      ret = GNUTLS_EMACS_ERROR_INVALID_TYPE;
+  }
+
+  if (ret != GNUTLS_E_SUCCESS)
+      return gnutls_make_error (ret);
+
+  GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_CRED_ALLOC;
+
+  // message ("gnutls: setting the trustfile");
+
+  // if (EQ (type, Qgnutls_x509pki))
+  // {
+  //     CHECK_STRING (trustfile);
+
+  //     x509_cred = XPROCESS (proc)->x509_cred;
+  //     puts("Setting certificate");
+  //     puts(XSTRING (trustfile)->data);
+  //     ret = gnutls_certificate_set_x509_trust_file (x509_cred,
+  //                                                   XSTRING (trustfile)->data,
+  //                                                   GNUTLS_X509_FMT_PEM);
+  // }
+
+  // if (ret != GNUTLS_E_SUCCESS)
+  //     return gnutls_make_error (ret);
+
+  GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_FILES;
+
+  message ("gnutls: gnutls_init");
+
+  ret = gnutls_init (&state, GNUTLS_CLIENT);
+
+  if (ret != GNUTLS_E_SUCCESS)
+      return gnutls_make_error (ret);
+
+  XPROCESS (proc)->gnutls_state = state;
+
+  GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_INIT;
+  
+  message ("gnutls: setting the priority string");
+
+  ret = gnutls_priority_set_direct(state, (char*) SDATA (priority_string), NULL);
+  
+  if (ret != GNUTLS_E_SUCCESS)
+      return gnutls_make_error (ret);
+
+  GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_PRIORITY;
+
+  message ("gnutls: setting the credentials");
+
+  if (EQ (type, Qgnutls_x509pki))
+  {
+      message ("gnutls: setting the x509 credentials");
+
+      x509_cred = XPROCESS (proc)->x509_cred;
+      ret = gnutls_cred_set (state, GNUTLS_CRD_CERTIFICATE, x509_cred);
+  }
+  else if (EQ (type, Qgnutls_anon))
+  {
+      message ("gnutls: setting the anon credentials");
+
+      anon_cred = XPROCESS (proc)->anon_cred;
+      ret = gnutls_cred_set (state, GNUTLS_CRD_ANON, anon_cred);
+  }
+  else
+  {
+      error ("unknown credential type");
+      ret = GNUTLS_EMACS_ERROR_INVALID_TYPE;
+  }
+
+  if (ret != GNUTLS_E_SUCCESS)
+      return gnutls_make_error (ret);
+
+  XPROCESS (proc)->gnutls_cred_type = type;
+  GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_CRED_SET;
+
+  return gnutls_make_error (GNUTLS_E_SUCCESS);
+}
+
+DEFUN ("gnutls-bye", Fgnutls_bye, 
+       Sgnutls_bye, 2, 2, 0,
+       doc: /* Terminate current GNU TLS connection for PROCESS.
+The connection should have been initiated using gnutls_handshake().
+
+If CONT is not nil the TLS connection gets terminated and further
+receives and sends will be disallowed. If the return value is zero you
+may continue using the connection.  If CONT is nil, GnuTLS actually
+sends an alert containing a close request and waits for the peer to
+reply with the same message.  In order to reuse the connection you
+should wait for an EOF from the peer.
+  
+This function may also return `gnutls-e-again', or
+`gnutls-e-interrupted'. */)
+    (Lisp_Object proc, Lisp_Object cont)
+{
+  gnutls_session_t state;
+  int ret;
+
+  CHECK_PROCESS (proc);
+
+  state = XPROCESS (proc)->gnutls_state;
+
+  ret = gnutls_bye (state,
+                    NILP (cont) ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR);
+  
+  return gnutls_make_error (ret);
+}
+
+DEFUN ("gnutls-handshake", Fgnutls_handshake, 
+       Sgnutls_handshake, 1, 1, 0,
+       doc: /* Perform GNU TLS handshake for PROCESS.
+The identity of the peer is checked automatically.  This function will
+fail if any problem is encountered, and will return a negative error
+code. In case of a client, if it has been asked to resume a session,
+but the server didn't, then a full handshake will be performed.
+
+If the error `gnutls-e-not-ready-for-handshake' is returned, you
+didn't call `gnutls-boot' first.
+
+This function may also return the non-fatal errors `gnutls-e-again',
+or `gnutls-e-interrupted'. In that case you may resume the handshake
+(by calling this function again). */)
+    (Lisp_Object proc)
+{
+  gnutls_session_t state;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  state = XPROCESS (proc)->gnutls_state;
+
+  if (GNUTLS_INITSTAGE (proc) < GNUTLS_STAGE_HANDSHAKE_CANDO)
+    return Qgnutls_e_not_ready_for_handshake;
+
+  /* for a network process in Emacs infd and outfd are the same
+     but this shows our intent more clearly */
+  gnutls_transport_set_ptr2 (state, XPROCESS (proc)->infd, XPROCESS (proc)->outfd);
+  ret = gnutls_handshake (state);
+
+  GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_HANDSHAKE_DONE;
+
+  if (GNUTLS_E_SUCCESS == ret)
+  {
+    /* here we're finally done */
+    GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_READY;
+  }
+  
+  return gnutls_make_error (ret);
+}
+
+void
+syms_of_gnutls (void)
+{
+  global_initialized = 0;
+  Qgnutls_anon = intern_c_string ("gnutls-anon");
+  staticpro (&Qgnutls_anon);
+  Qgnutls_x509pki = intern_c_string ("gnutls-x509pki");
+  staticpro (&Qgnutls_x509pki);
+  Qgnutls_e_interrupted = intern_c_string ("gnutls-e-interrupted");
+  staticpro (&Qgnutls_e_interrupted);
+  Qgnutls_e_again = intern_c_string ("gnutls-e-again");
+  staticpro (&Qgnutls_e_again);
+  Qgnutls_e_invalid_session = intern_c_string ("gnutls-e-invalid-session");
+  staticpro (&Qgnutls_e_invalid_session);
+  Qgnutls_e_not_ready_for_handshake = intern_c_string ("gnutls-e-not-ready-for-handshake");
+  staticpro (&Qgnutls_e_not_ready_for_handshake);
+
+  defsubr (&Sgnutls_get_initstage);
+  defsubr (&Sgnutls_errorp);
+  defsubr (&Sgnutls_global_init);
+  defsubr (&Sgnutls_global_deinit);
+  defsubr (&Sgnutls_boot);
+  defsubr (&Sgnutls_deinit);
+  defsubr (&Sgnutls_handshake);
+  defsubr (&Sgnutls_bye);
+}
+#endif

=== added file 'src/gnutls.h'
--- src/gnutls.h	1970-01-01 00:00:00 +0000
+++ src/gnutls.h	2010-09-11 14:58:24 +0000
@@ -0,0 +1,29 @@
+#ifdef HAVE_GNUTLS
+#include <gnutls/gnutls.h>
+
+#define GNUTLS_STAGE_EMPTY 0
+#define GNUTLS_STAGE_CRED_ALLOC 1
+#define GNUTLS_STAGE_FILES 2
+#define GNUTLS_STAGE_INIT 3
+#define GNUTLS_STAGE_PRIORITY 4
+#define GNUTLS_STAGE_CRED_SET 5
+
+#define GNUTLS_STAGE_HANDSHAKE_CANDO 5
+#define GNUTLS_STAGE_HANDSHAKE_DONE 6
+
+#define GNUTLS_STAGE_READY 100
+
+#define GNUTLS_EMACS_ERROR_INVALID_TYPE GNUTLS_E_APPLICATION_ERROR_MIN
+
+#define GNUTLS_INITSTAGE(proc) ( XPROCESS (proc)->gnutls_initstage )
+
+#define GNUTLS_PROCESS_USABLE(proc) ( GNUTLS_INITSTAGE(proc) >= GNUTLS_STAGE_READY )
+
+int
+emacs_gnutls_write (int fildes, gnutls_session_t state, char *buf,
+                    unsigned int nbyte);
+int
+emacs_gnutls_read (int fildes, gnutls_session_t state, char *buf,
+                   unsigned int nbyte);
+
+#endif

=== modified file 'src/lisp.h'
--- src/lisp.h	2010-08-09 19:25:41 +0000
+++ src/lisp.h	2010-09-11 14:58:24 +0000
@@ -3350,6 +3350,7 @@
 extern void syms_of_process (void);
 extern void setup_process_coding_systems (Lisp_Object);
 
+
 /* Defined in callproc.c */
 extern Lisp_Object Vexec_path, Vexec_suffixes,
                    Vexec_directory, Vdata_directory;
@@ -3589,6 +3590,11 @@
 void syms_of_dbusbind (void);
 #endif
 
+#ifdef HAVE_GNUTLS
+/* Defined in gnutls.c */
+extern void syms_of_gnutls (void);
+#endif
+
 #ifdef DOS_NT
 /* Defined in msdos.c, w32.c */
 extern char *emacs_root_dir (void);

=== modified file 'src/process.c'
--- src/process.c	2010-08-22 15:14:37 +0000
+++ src/process.c	2010-09-11 14:58:24 +0000
@@ -105,6 +105,9 @@
 #include "sysselect.h"
 #include "syssignal.h"
 #include "syswait.h"
+#ifdef HAVE_GNUTLS
+#include "gnutls.h"
+#endif
 
 #if defined (USE_GTK) || defined (HAVE_GCONF)
 #include "xgselect.h"
@@ -583,6 +586,10 @@
   p->read_output_skip = 0;
 #endif
 
+#ifdef HAVE_GNUTLS
+  p->gnutls_initstage = GNUTLS_STAGE_EMPTY;
+#endif
+
   /* If name is already in use, modify it until it is unused.  */
 
   name1 = name;
@@ -1526,6 +1533,12 @@
   XPROCESS (proc)->filter = Qnil;
   XPROCESS (proc)->command = Flist (nargs - 2, args + 2);
 
+#ifdef HAVE_GNUTLS
+  /* AKA GNUTLS_INITSTAGE(proc) */
+  XPROCESS (proc)->gnutls_initstage = GNUTLS_STAGE_EMPTY;
+  XPROCESS (proc)->gnutls_cred_type = Qnil;
+#endif
+
 #ifdef ADAPTIVE_READ_BUFFERING
   XPROCESS (proc)->adaptive_read_buffering
     = (NILP (Vprocess_adaptive_read_buffering) ? 0
@@ -5097,7 +5110,12 @@
 #endif
   if (proc_buffered_char[channel] < 0)
     {
-      nbytes = emacs_read (channel, chars + carryover, readmax);
+#ifdef HAVE_GNUTLS
+      if (NETCONN_P(proc) && GNUTLS_PROCESS_USABLE (proc))
+	nbytes = emacs_gnutls_read (channel, XPROCESS (proc)->gnutls_state, chars + carryover, readmax);
+      else
+#endif
+	nbytes = emacs_read (channel, chars + carryover, readmax);
 #ifdef ADAPTIVE_READ_BUFFERING
       if (nbytes > 0 && p->adaptive_read_buffering)
 	{
@@ -5130,7 +5148,12 @@
     {
       chars[carryover] = proc_buffered_char[channel];
       proc_buffered_char[channel] = -1;
-      nbytes = emacs_read (channel, chars + carryover + 1,  readmax - 1);
+#ifdef HAVE_GNUTLS
+      if (NETCONN_P(proc) && GNUTLS_PROCESS_USABLE (proc))
+	nbytes = emacs_gnutls_read (channel, XPROCESS (proc)->gnutls_state, chars + carryover + 1, readmax - 1);
+      else
+#endif
+	nbytes = emacs_read (channel, chars + carryover + 1,  readmax - 1);
       if (nbytes < 0)
 	nbytes = 1;
       else
@@ -5540,7 +5563,14 @@
 	      else
 #endif
 		{
-		  rv = emacs_write (outfd, (char *) buf, this);
+#ifdef HAVE_GNUTLS
+		  if (NETCONN_P(proc) && GNUTLS_PROCESS_USABLE (proc))
+		    rv = emacs_gnutls_write (outfd,
+					     XPROCESS (proc)->gnutls_state, 
+					     (char *) buf, this);
+		  else
+#endif
+		    rv = emacs_write (outfd, (char *) buf, this);
 #ifdef ADAPTIVE_READ_BUFFERING
 		  if (p->read_output_delay > 0
 		      && p->adaptive_read_buffering == 1)

=== modified file 'src/process.h'
--- src/process.h	2010-08-11 12:34:46 +0000
+++ src/process.h	2010-09-11 14:58:24 +0000
@@ -24,6 +24,10 @@
 #include <unistd.h>
 #endif
 
+#ifdef HAVE_GNUTLS
+#include "gnutls.h"
+#endif
+
 /* This structure records information about a subprocess
    or network connection.
 
@@ -76,6 +80,10 @@
     /* Working buffer for encoding.  */
     Lisp_Object encoding_buf;
 
+#ifdef HAVE_GNUTLS
+    Lisp_Object gnutls_cred_type;
+#endif
+
     /* After this point, there are no Lisp_Objects any more.  */
     /* alloc.c assumes that `pid' is the first such non-Lisp slot.  */
 
@@ -121,6 +129,13 @@
        needs to be synced to `status'.  */
     unsigned int raw_status_new : 1;
     int raw_status;
+
+#ifdef HAVE_GNUTLS
+    int gnutls_initstage;
+    gnutls_session_t gnutls_state;
+    gnutls_certificate_client_credentials x509_cred;
+    gnutls_anon_client_credentials_t anon_cred;
+#endif
 };
 
 /* Every field in the preceding structure except for the first two


^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-11 15:00                                   ` Ted Zlatanov
@ 2010-09-12 10:58                                     ` Stefan Monnier
  2010-09-14 15:45                                       ` Ted Zlatanov
  0 siblings, 1 reply; 93+ messages in thread
From: Stefan Monnier @ 2010-09-12 10:58 UTC (permalink / raw)
  To: Ted Zlatanov; +Cc: gnutls-devel, emacs-devel

> patch++

Looks good, except for a few coding style conventions:

> +  } while( rtnval==GNUTLS_E_INTERRUPTED || rtnval==GNUTLS_E_AGAIN);
> +  fsync(STDOUT_FILENO);

Place a space *before* the open-paren and around infix operators.

> +    /* means the we will only be called again if the library cannot
> +     * determine which certificate to send
> +     */

Put the comment-close at the end of the previous line.

> +  // message ("gnutls: setting the trustfile");
> +
> +  // if (EQ (type, Qgnutls_x509pki))
> +  // {
> +  //     CHECK_STRING (trustfile);
> +
> +  //     x509_cred = XPROCESS (proc)->x509_cred;
> +  //     puts("Setting certificate");
> +  //     puts(XSTRING (trustfile)->data);
> +  //     ret = gnutls_certificate_set_x509_trust_file (x509_cred,
> +  //                                                   XSTRING (trustfile)->data,
> +  //                                                   GNUTLS_X509_FMT_PEM);
> +  // }
> +
> +  // if (ret != GNUTLS_E_SUCCESS)
> +  //     return gnutls_make_error (ret);

We use /*..*/ comments, or "#if 0 ... #endif".

> +       doc: /* Terminate current GNU TLS connection for PROCESS.
> +The connection should have been initiated using gnutls_handshake().

This should mention `gnutls-handshake' rather than gnutls_handshake().

BTW, for functions whose are meant to be "internal" (e.g. only expected
to be used via a wrapper in gnutls.el) you can use a "gnutls--" prefix.
This is not a widely used convention in Elisp, but some packages try to
use it.

> +#define GNUTLS_STAGE_EMPTY 0
> +#define GNUTLS_STAGE_CRED_ALLOC 1
> +#define GNUTLS_STAGE_FILES 2
> +#define GNUTLS_STAGE_INIT 3
> +#define GNUTLS_STAGE_PRIORITY 4
> +#define GNUTLS_STAGE_CRED_SET 5

Please use an enum (and use it for the type of the gnutls_initstage
field, of course).

> +#define GNUTLS_STAGE_HANDSHAKE_CANDO 5

Why is that the same value as GNUTLS_STAGE_CRED_SET?

> +#define GNUTLS_STAGE_HANDSHAKE_DONE 6

> +#define GNUTLS_PROCESS_USABLE(proc) ( GNUTLS_INITSTAGE(proc) >= GNUTLS_STAGE_READY )

No need for spaces after the open and before the close paren.

> +#ifdef HAVE_GNUTLS
> +/* Defined in gnutls.c */
> +extern void syms_of_gnutls (void);
> +#endif

Why here rather than in gnutls.h?

Also gnutls.c and gnutls.h need a GPL notice at the beginning.
See other files for the usual boilerplate.

> +  /* AKA GNUTLS_INITSTAGE(proc) */

Please finish your comments with a full-stop (and follow it by 2 spaces).

> +	nbytes = emacs_gnutls_read (channel, XPROCESS (proc)->gnutls_state, chars + carryover + 1, readmax - 1);

Don't overflow the 80th column.


        Stefan

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-11 14:59                                 ` Ted Zlatanov
  2010-09-11 15:00                                   ` Ted Zlatanov
@ 2010-09-13  7:49                                   ` Nikos Mavrogiannopoulos
  2010-09-14 18:30                                     ` Ted Zlatanov
  2010-09-15 11:01                                     ` Ted Zlatanov
  1 sibling, 2 replies; 93+ messages in thread
From: Nikos Mavrogiannopoulos @ 2010-09-13  7:49 UTC (permalink / raw)
  To: Ted Zlatanov; +Cc: gnutls-devel, emacs-devel

2010/9/11 Ted Zlatanov <tzz@lifelogs.com>:

> - no SRP anywhere, just anon and x509 (I'll add SRP if we need it and
>  when the other two are working)
> Now I get GNUTLS_E_INSUFFICIENT_CREDENTIALS when I open a x509
> connection to an IMAP TLS server so I think there's still work to do.
> The trust file seems to be wrong (see lisp/net/gnutls.el, I tried both
> "/etc/ssl/certs/ca-certificates.crt" and "/etc/ssl/certs/ca.pem").
> The GnuTLS examples don't seem to cover the standard situation of
> talking to a web server over SSL and possibly accepting an insecure
> connection if the server credentials are bad.  I must have missed
> something.  Could the GnuTLS developers look at my patch and help me
> out?

I cannot look at the patch but the example you are looking for is:
http://www.gnu.org/software/gnutls/manual/html_node/Simple-client-example-with-X_002e509-certificate-support.html#Simple-client-example-with-X_002e509-certificate-support
to do the connection, and this one to verify the certificate:
http://www.gnu.org/software/gnutls/manual/html_node/Verifying-peer_0027s-certificate.html#Verifying-peer_0027s-certificate

regards,
Nikos

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-11 12:45                                         ` Stefan Monnier
@ 2010-09-14 15:34                                           ` Ted Zlatanov
  0 siblings, 0 replies; 93+ messages in thread
From: Ted Zlatanov @ 2010-09-14 15:34 UTC (permalink / raw)
  To: emacs-devel

On Sat, 11 Sep 2010 14:45:51 +0200 Stefan Monnier <monnier@iro.umontreal.ca> wrote: 

>> I feel (as Lars does) that GnuTLS should be a required part of Emacs,
>> disabled by choice.  Today it's hard to imagine a system where you would
>> not want GnuTLS enabled if it was available for the platform.  In any
>> case, if a maintainer could give me a definite yes or no, I would
>> appreciate it.  Switching the default to "no" is not a problem
>> technically.

SM> I think it's OK to let it default to yes.
SM> If it proves to be too much of a problem, we'll revisit this choice.

I also get the error Andreas mentioned if I do `autoreconf' but just
`autoconf' works.  I'm not sure if this really is a problem and don't
know Autoconf well enough to solve it.

Ted




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-12 10:58                                     ` Stefan Monnier
@ 2010-09-14 15:45                                       ` Ted Zlatanov
  0 siblings, 0 replies; 93+ messages in thread
From: Ted Zlatanov @ 2010-09-14 15:45 UTC (permalink / raw)
  To: gnutls-devel; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1774 bytes --]

On Sun, 12 Sep 2010 12:58:47 +0200 Stefan Monnier <monnier@iro.umontreal.ca> wrote: 

SM> Place a space *before* the open-paren and around infix operators.
...
SM> Put the comment-close at the end of the previous line.
...
SM> We use /*..*/ comments, or "#if 0 ... #endif".
...
SM> This should mention `gnutls-handshake' rather than gnutls_handshake().
...
SM> Please use an enum (and use it for the type of the gnutls_initstage
SM> field, of course).
...
SM> No need for spaces after the open and before the close paren.
...
SM> Please finish your comments with a full-stop (and follow it by 2 spaces).
...
SM> Don't overflow the 80th column.

All done.  Some were oversights, some my stupidity...  Sorry for the annoyance.

SM> BTW, for functions whose are meant to be "internal" (e.g. only expected
SM> to be used via a wrapper in gnutls.el) you can use a "gnutls--" prefix.
SM> This is not a widely used convention in Elisp, but some packages try to
SM> use it.

>> +#define GNUTLS_STAGE_CRED_SET 5
>> +#define GNUTLS_STAGE_HANDSHAKE_CANDO 5

SM> Why is that the same value as GNUTLS_STAGE_CRED_SET?

Because you can't handshake before credentials are set.  I think that's
the best way to express it (rather than a GNUTLS_CAN_HANDSHAKE macro or
some such).

>> +#ifdef HAVE_GNUTLS
>> +/* Defined in gnutls.c */
>> +extern void syms_of_gnutls (void);
>> +#endif

SM> Why here rather than in gnutls.h?
...
SM> Also gnutls.c and gnutls.h need a GPL notice at the beginning.
SM> See other files for the usual boilerplate.

Fixed.  That also removed lisp.h from the patch.

I also added a convenience gnutls-error-string function so users can
interpret GnuTLS errors.  Almost ready for the trunk commit, just need
to get the handshake working (I keep getting E_AGAIN).

Ted


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: tls.patch --]
[-- Type: text/x-diff, Size: 29544 bytes --]

=== modified file 'configure.in'
--- configure.in	2010-08-23 12:54:09 +0000
+++ configure.in	2010-09-14 15:41:02 +0000
@@ -170,6 +170,7 @@
 OPTION_DEFAULT_ON([dbus],[don't compile with D-Bus support])
 OPTION_DEFAULT_ON([gconf],[don't compile with GConf support])
 OPTION_DEFAULT_ON([selinux],[don't compile with SELinux support])
+OPTION_DEFAULT_ON([gnutls],[don't use -lgnutls for SSL/TLS support])
 
 ## For the times when you want to build Emacs but don't have
 ## a suitable makeinfo, and can live without the manuals.
@@ -1998,6 +1999,13 @@
 fi
 AC_SUBST(LIBSELINUX_LIBS)
 
+HAVE_GNUTLS=no
+if test "${with_gnutls}" = "yes" ; then
+  PKG_CHECK_MODULES([LIBGNUTLS], [gnutls >= 2.2.4])
+  AC_DEFINE(HAVE_GNUTLS)
+  HAVE_GNUTLS=yes
+fi
+
 dnl Do not put whitespace before the #include statements below.
 dnl Older compilers (eg sunos4 cc) choke on it.
 HAVE_XAW3D=no
@@ -3682,6 +3690,7 @@
 echo "  Does Emacs use -ldbus?                                  ${HAVE_DBUS}"
 echo "  Does Emacs use -lgconf?                                 ${HAVE_GCONF}"
 echo "  Does Emacs use -lselinux?                               ${HAVE_LIBSELINUX}"
+echo "  Does Emacs use -lgnutls?                                ${HAVE_GNUTLS}"
 
 echo "  Does Emacs use -lfreetype?                              ${HAVE_FREETYPE}"
 echo "  Does Emacs use -lm17n-flt?                              ${HAVE_M17N_FLT}"

=== added file 'lisp/net/gnutls.el'
--- lisp/net/gnutls.el	1970-01-01 00:00:00 +0000
+++ lisp/net/gnutls.el	2010-09-14 15:41:02 +0000
@@ -0,0 +1,131 @@
+;;; gnutls.el --- Support SSL and TLS connections through GnuTLS
+;; Copyright (C) 2010 Free Software Foundation, Inc.
+
+;; Author: Ted Zlatanov <tzz@lifelogs.com>
+;; Keywords: comm, tls, ssl, encryption
+;; Originally-By: Simon Josefsson (See http://josefsson.org/emacs-security/)
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This package provides language bindings for the GnuTLS library
+;; using the corresponding core functions in gnutls.c.
+
+;; Simple test:
+;;
+;; (setq jas (open-ssl-stream "ssl" (current-buffer) "www.pdc.kth.se" 443))
+;; (process-send-string jas "GET /\r\n\r\n")
+
+;;; Code:
+
+(defconst gnutls-version "0.3.1")
+
+(defun open-ssl-stream (name buffer host service)
+  "Open a SSL connection for a service to a host.
+Returns a subprocess-object to represent the connection.
+Input and output work as for subprocesses; `delete-process' closes it.
+Args are NAME BUFFER HOST SERVICE.
+NAME is name for process.  It is modified if necessary to make it unique.
+BUFFER is the buffer (or `buffer-name') to associate with the process.
+ Process output goes at end of that buffer, unless you specify
+ an output stream or filter function to handle the output.
+ BUFFER may be also nil, meaning that this process is not associated
+ with any buffer
+Third arg is name of the host to connect to, or its IP address.
+Fourth arg SERVICE is name of the service desired, or an integer
+specifying a port number to connect to."
+  (let ((proc (open-network-stream name buffer host service)))
+    (starttls-negotiate proc nil 'gnutls-x509pki)))
+
+;; (open-ssl-stream "tls" "tls-buffer" "yourserver.com" "https")
+(defun starttls-negotiate (proc &optional priority-string
+                                credentials credentials-file)
+  "Negotiate a SSL or TLS connection.
+PROC is the process returned by `starttls-open-stream'.
+PRIORITY-STRING is as per the GnuTLS docs.
+CREDENTIALS is `gnutls-x509pki' or `gnutls-anon'.
+CREDENTIALS-FILE is a filename with meaning dependent on CREDENTIALS."
+  (let* ((credentials (or credentials 'gnutls-x509pki))
+         (credentials-file (or credentials-file
+                               ;"/etc/ssl/certs/ca-certificates.crt"
+                               ;"/etc/ssl/certs/ca.pem"
+                               "/tmp/ca.pem"
+                               ))
+
+         (priority-string (or priority-string
+                              (cond
+                               ((eq credentials 'gnutls-anon)
+                                "PERFORMANCE:+ANON-DH:!ARCFOUR-128")
+                               ((eq credentials 'gnutls-x509pki)
+                                "PERFORMANCE"))))
+         ret)
+
+    (gnutls-message-maybe
+     (setq ret (gnutls-boot proc priority-string credentials credentials-file))
+     "boot: %s")
+
+    (when (gnutls-errorp ret)
+      (error "Could not boot GnuTLS for this process"));
+
+    (let ((ret 'gnutls-e-again)
+          (n 25))
+      (while (and (or (eq ret 'gnutls-e-again)
+                      (eq ret 'gnutls-e-interrupted))
+                  (> n 0))
+        (decf n)
+        (gnutls-message-maybe
+         (setq ret (gnutls-handshake proc))
+         "handshake: %s")
+        (debug "handshake ret" ret (gnutls-error-string ret)))
+      (if (gnutls-errorp ret)
+          (progn
+            (message "Ouch, error return %s (%s)" 
+                     ret (gnutls-error-string ret))
+            (setq proc nil))
+        (message "Handshake complete %s." ret)))
+     proc))
+
+(defun starttls-open-stream (name buffer host service)
+  "Open a TLS connection for a service to a host.
+Returns a subprocess-object to represent the connection.
+Input and output work as for subprocesses; `delete-process' closes it.
+Args are NAME BUFFER HOST SERVICE.
+NAME is name for process.  It is modified if necessary to make it unique.
+BUFFER is the buffer (or `buffer-name') to associate with the process.
+ Process output goes at end of that buffer, unless you specify
+ an output stream or filter function to handle the output.
+ BUFFER may be also nil, meaning that this process is not associated
+ with any buffer
+Third arg is name of the host to connect to, or its IP address.
+Fourth arg SERVICE is name of the service desired, or an integer
+specifying a port number to connect to."
+  (open-network-stream name buffer host service))
+
+(defun gnutls-message-maybe (doit format &rest params)
+  "When DOIT, message with the caller name followed by FORMAT on PARAMS."
+  ;; (apply 'debug format (or params '(nil)))
+  (when (gnutls-errorp doit)
+    (message "%s: (err=[%s] %s) %s"
+             "gnutls.el"
+             doit (gnutls-error-string doit)
+             (apply 'format format (or params '(nil))))))
+
+(provide 'ssl)
+(provide 'gnutls)
+(provide 'starttls)
+
+;;; gnutls.el ends here

=== modified file 'src/Makefile.in'
--- src/Makefile.in	2010-08-17 21:19:11 +0000
+++ src/Makefile.in	2010-09-14 15:41:02 +0000
@@ -285,6 +285,9 @@
 
 LIBSELINUX_LIBS = @LIBSELINUX_LIBS@
 
+LIBGNUTLS_LIBS = @LIBGNUTLS_LIBS@
+LIBGNUTLS_CFLAGS = @LIBGNUTLS_CFLAGS@
+
 INTERVALS_H = dispextern.h intervals.h composite.h
 
 GETLOADAVG_LIBS = @GETLOADAVG_LIBS@
@@ -323,6 +326,7 @@
   ${C_SWITCH_X_SYSTEM} ${CFLAGS_SOUND} ${RSVG_CFLAGS} ${IMAGEMAGICK_CFLAGS} ${DBUS_CFLAGS} \
   ${GCONF_CFLAGS} ${FREETYPE_CFLAGS} ${FONTCONFIG_CFLAGS} \
   ${LIBOTF_CFLAGS} ${M17N_FLT_CFLAGS} ${DEPFLAGS} ${PROFILING_CFLAGS} \
+  $(LIBGNUTLS_CFLAGS) \
   ${C_WARNINGS_SWITCH} ${CFLAGS}
 ALL_OBJC_CFLAGS=$(ALL_CFLAGS) $(GNU_OBJC_CFLAGS)
 
@@ -347,7 +351,7 @@
 	alloc.o data.o doc.o editfns.o callint.o \
 	eval.o floatfns.o fns.o font.o print.o lread.o \
 	syntax.o $(UNEXEC_OBJ) bytecode.o \
-	process.o callproc.o \
+	process.o gnutls.o callproc.o \
 	region-cache.o sound.o atimer.o \
 	doprnt.o strftime.o intervals.o textprop.o composite.o md5.o \
 	$(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ)
@@ -598,6 +602,7 @@
    $(RSVG_LIBS) ${IMAGEMAGICK_LIBS}  $(DBUS_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \
    $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) ${GCONF_LIBS} ${LIBSELINUX_LIBS} \
    $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
+   $(LIBGNUTLS_LIBS) \
    $(LIB_GCC) $(LIB_MATH) $(LIB_STANDARD) $(LIB_GCC)
 
 all: emacs${EXEEXT} $(OTHER_FILES)

=== modified file 'src/config.in'
--- src/config.in	2010-08-17 21:19:11 +0000
+++ src/config.in	2010-09-14 15:41:02 +0000
@@ -255,6 +255,9 @@
 /* Define to 1 if you have a gif (or ungif) library. */
 #undef HAVE_GIF
 
+/* Define if we have the GNU TLS library.  */
+#undef HAVE_GNUTLS
+
 /* Define to 1 if you have the gpm library (-lgpm). */
 #undef HAVE_GPM
 
@@ -1091,6 +1094,12 @@
 #include config_opsysfile
 #include config_machfile
 
+#if HAVE_GNUTLS
+#define LIBGNUTLS $(LIBGNUTLS_LIBS)
+#else /* not HAVE_GNUTLS */
+#define LIBGNUTLS
+#endif /* not HAVE_GNUTLS */
+
 /* Set up some defines, C and LD flags for NeXTstep interface on GNUstep.
   (There is probably a better place to do this, but right now the Cocoa
    side does this in s/darwin.h and we cannot

=== modified file 'src/emacs.c'
--- src/emacs.c	2010-08-22 21:15:20 +0000
+++ src/emacs.c	2010-09-14 15:41:02 +0000
@@ -63,6 +63,10 @@
 #include "keyboard.h"
 #include "keymap.h"
 
+#ifdef HAVE_GNUTLS
+#include "gnutls.h"
+#endif
+
 #ifdef HAVE_NS
 #include "nsterm.h"
 #endif
@@ -1569,6 +1573,10 @@
       syms_of_fontset ();
 #endif /* HAVE_NS */
 
+#ifdef HAVE_GNUTLS
+      syms_of_gnutls ();
+#endif
+
 #ifdef HAVE_DBUS
       syms_of_dbusbind ();
 #endif /* HAVE_DBUS */

=== added file 'src/gnutls.c'
--- src/gnutls.c	1970-01-01 00:00:00 +0000
+++ src/gnutls.c	2010-09-14 15:41:02 +0000
@@ -0,0 +1,490 @@
+/* GnuTLS glue for GNU Emacs.
+   Copyright (C) 2010  Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs 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 3 of the License, or
+(at your option) any later version.
+
+GNU Emacs 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+#include <errno.h>
+#include <setjmp.h>
+
+#include "lisp.h"
+#include "process.h"
+
+#ifdef HAVE_GNUTLS
+#include <gnutls/gnutls.h>
+
+Lisp_Object Qgnutls_code;
+Lisp_Object Qgnutls_anon, Qgnutls_x509pki;
+Lisp_Object Qgnutls_e_interrupted, Qgnutls_e_again,
+  Qgnutls_e_invalid_session, Qgnutls_e_not_ready_for_handshake;
+int global_initialized;
+
+int
+emacs_gnutls_write (int fildes, gnutls_session_t state, char *buf,
+                    unsigned int nbyte)
+{
+  register int rtnval, bytes_written;
+
+  bytes_written = 0;
+
+  while (nbyte > 0)
+    {
+      rtnval = gnutls_write (state, buf, nbyte);
+
+      if (rtnval == -1)
+        {
+          if (errno == EINTR)
+            continue;
+          else
+            return (bytes_written ? bytes_written : -1);
+        }
+
+      buf += rtnval;
+      nbyte -= rtnval;
+      bytes_written += rtnval;
+    }
+  fsync (STDOUT_FILENO);
+
+  return (bytes_written);
+}
+
+int
+emacs_gnutls_read (int fildes, gnutls_session_t state, char *buf,
+                   unsigned int nbyte)
+{
+  register int rtnval;
+
+  do {
+    rtnval = gnutls_read (state, buf, nbyte);
+  } while (rtnval == GNUTLS_E_INTERRUPTED || rtnval == GNUTLS_E_AGAIN);
+  fsync (STDOUT_FILENO);
+
+  return (rtnval);
+}
+
+/* convert an integer error to a Lisp_Object; it will be either a
+   known symbol like `gnutls_e_interrupted' and `gnutls_e_again' or
+   simply the integer value of the error.  GNUTLS_E_SUCCESS is mapped
+   to Qt.  */
+Lisp_Object gnutls_make_error (int error)
+{
+  switch (error)
+  {
+  case GNUTLS_E_SUCCESS:
+    return Qt;
+  case GNUTLS_E_AGAIN:
+    return Qgnutls_e_again;
+  case GNUTLS_E_INTERRUPTED:
+    return Qgnutls_e_interrupted;
+  case GNUTLS_E_INVALID_SESSION:
+    return Qgnutls_e_invalid_session;
+  }
+
+  return make_number (error);
+}
+
+DEFUN ("gnutls-get-initstage", Fgnutls_get_initstage, Sgnutls_get_initstage, 1, 1, 0,
+       doc: /* Return the GnuTLS init stage of PROCESS.
+See also `gnutls-boot'.  */)
+    (Lisp_Object proc)
+{
+  CHECK_PROCESS (proc);
+
+  return make_number (GNUTLS_INITSTAGE (proc));
+}
+
+DEFUN ("gnutls-errorp", Fgnutls_errorp, Sgnutls_errorp, 1, 1, 0,
+       doc: /* Returns t if ERROR (as generated by gnutls_make_error)
+indicates a GnuTLS problem.  */)
+    (Lisp_Object error)
+{
+  if (EQ (error, Qt)) return Qnil;
+
+  return Qt;
+}
+
+DEFUN ("gnutls-error-string", Fgnutls_error_string, Sgnutls_error_string, 1, 1, 0,
+       doc: /* Returns a description of ERROR.
+ERROR is an integer or a symbol with an integer `gnutls-code' property.  */)
+    (Lisp_Object err)
+{
+  Lisp_Object code;
+
+  if (EQ (err, Qt)) return build_string ("Not an error");
+
+  if (SYMBOLP (err))
+  {
+    code = Fget (err, Qgnutls_code);
+    if (NUMBERP (code))
+    {
+      err = code;
+    }
+    else
+    {
+      return build_string ("Symbol has no numeric gnutls-code property");
+    }
+  }
+
+  if (!NUMBERP (err))
+    return build_string ("Not an error symbol or code");
+
+  return build_string (gnutls_strerror (XINT (err)));
+}
+
+DEFUN ("gnutls-deinit", Fgnutls_deinit, Sgnutls_deinit, 1, 1, 0,
+       doc: /* Deallocate GNU TLS resources associated with PROCESS.
+See also `gnutls-init'.  */)
+    (Lisp_Object proc)
+{
+  gnutls_session_t state;
+
+  CHECK_PROCESS (proc);
+  state = XPROCESS (proc)->gnutls_state;
+
+  if (GNUTLS_INITSTAGE (proc) >= GNUTLS_STAGE_INIT)
+  {
+      gnutls_deinit (state);
+      GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_INIT - 1;
+  }
+
+  return Qt;
+}
+
+DEFUN ("gnutls-global-init", Fgnutls_global_init,
+       Sgnutls_global_init, 0, 0, 0,
+       doc: /* Initializes global GNU TLS state to defaults.
+Call `gnutls-global-deinit' when GNU TLS usage is no longer needed.
+Returns zero on success.  */)
+     (void)
+{
+  int ret = GNUTLS_E_SUCCESS;
+
+  if (!global_initialized)
+    ret = gnutls_global_init ();
+
+  global_initialized = 1;
+
+  return gnutls_make_error (ret);
+}
+
+DEFUN ("gnutls-global-deinit", Fgnutls_global_deinit,
+       Sgnutls_global_deinit, 0, 0, 0,
+       doc: /* Deinitializes global GNU TLS state.
+See also `gnutls-global-init'.  */)
+     (void)
+{
+  if (global_initialized)
+    gnutls_global_deinit ();
+
+  global_initialized = 0;
+
+  return gnutls_make_error (GNUTLS_E_SUCCESS);
+}
+
+DEFUN ("gnutls-boot", Fgnutls_boot, Sgnutls_boot, 3, 6, 0,
+       doc: /* Initializes client-mode GnuTLS for process PROC.
+Currently only client mode is supported.  Returns a success/failure
+value you can check with `gnutls-errorp'.
+
+PRIORITY_STRING is a string describing the priority.
+TYPE is either `gnutls-anon' or `gnutls-x509pki'.
+TRUSTFILE is a PEM encoded trust file for `gnutls-x509pki'.
+KEYFILE is ... for `gnutls-x509pki' (TODO).
+CALLBACK is ... for `gnutls-x509pki' (TODO).
+
+Note that the priority is set on the client.  The server does not use
+the protocols's priority except for disabling protocols that were not
+specified.
+
+Processes must be initialized with this function before other GNU TLS
+functions are used.  This function allocates resources which can only
+be deallocated by calling `gnutls-deinit' or by calling it again.
+
+Each authentication type may need additional information in order to
+work.  For X.509 PKI (`gnutls-x509pki'), you need TRUSTFILE and
+KEYFILE and optionally CALLBACK.  */)
+    (Lisp_Object proc, Lisp_Object priority_string, Lisp_Object type,
+     Lisp_Object trustfile, Lisp_Object keyfile, Lisp_Object callback)
+{
+  int ret = GNUTLS_E_SUCCESS;
+  gnutls_session_t state;
+  gnutls_certificate_credentials_t x509_cred;
+  gnutls_anon_client_credentials_t anon_cred;
+  gnutls_srp_client_credentials_t srp_cred;
+  Lisp_Object global_init;
+
+  CHECK_PROCESS (proc);
+  CHECK_SYMBOL (type);
+  CHECK_STRING (priority_string);
+
+  state = XPROCESS (proc)->gnutls_state;
+
+  /* always initialize globals.  */
+  global_init = Fgnutls_global_init ();
+  if (! NILP (Fgnutls_errorp (global_init)))
+    return global_init;
+
+  /* deinit and free resources.  */
+  if (GNUTLS_INITSTAGE (proc) >= GNUTLS_STAGE_CRED_ALLOC)
+  {
+      message ("gnutls: deallocating certificates");
+
+      if (EQ (type, Qgnutls_x509pki))
+      {
+          message ("gnutls: deallocating x509 certificates");
+
+          x509_cred = XPROCESS (proc)->x509_cred;
+          gnutls_certificate_free_credentials (x509_cred);
+      }
+      else if (EQ (type, Qgnutls_anon))
+      {
+          message ("gnutls: deallocating anon certificates");
+
+          anon_cred = XPROCESS (proc)->anon_cred;
+          gnutls_anon_free_client_credentials (anon_cred);
+      }
+      else
+      {
+          error ("unknown credential type");
+          ret = GNUTLS_EMACS_ERROR_INVALID_TYPE;
+      }
+
+      if (GNUTLS_INITSTAGE (proc) >= GNUTLS_STAGE_INIT)
+      {
+          message ("gnutls: deinitializing");
+
+          Fgnutls_deinit (proc);
+      }
+  }
+
+  GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_EMPTY;
+
+  message ("gnutls: allocating credentials");
+
+  if (EQ (type, Qgnutls_x509pki))
+  {
+      message ("gnutls: allocating x509 credentials");
+
+      x509_cred = XPROCESS (proc)->x509_cred;
+      if (gnutls_certificate_allocate_credentials (&x509_cred) < 0)
+        memory_full ();
+  }
+  else if (EQ (type, Qgnutls_anon))
+  {
+      message ("gnutls: allocating anon credentials");
+
+      anon_cred = XPROCESS (proc)->anon_cred;
+      if (gnutls_anon_allocate_client_credentials (&anon_cred) < 0)
+        memory_full ();
+  }
+  else
+  {
+      error ("unknown credential type");
+      ret = GNUTLS_EMACS_ERROR_INVALID_TYPE;
+  }
+
+  if (ret < GNUTLS_E_SUCCESS)
+      return gnutls_make_error (ret);
+
+  GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_CRED_ALLOC;
+
+  message ("gnutls: setting the trustfile");
+
+  if (EQ (type, Qgnutls_x509pki))
+  {
+      CHECK_STRING (trustfile);
+
+      ret = gnutls_certificate_set_x509_trust_file (x509_cred,
+                                                    XSTRING (trustfile)->data,
+                                                    GNUTLS_X509_FMT_PEM);
+  }
+
+  if (ret < GNUTLS_E_SUCCESS)
+      return gnutls_make_error (ret);
+
+  GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_FILES;
+
+  message ("gnutls: gnutls_init");
+
+  ret = gnutls_init (&state, GNUTLS_CLIENT);
+
+  if (ret < GNUTLS_E_SUCCESS)
+      return gnutls_make_error (ret);
+
+  XPROCESS (proc)->gnutls_state = state;
+
+  GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_INIT;
+
+  message ("gnutls: setting the priority string");
+
+  ret = gnutls_priority_set_direct(state,
+                                   (char*) SDATA (priority_string),
+                                   NULL);
+
+  if (ret < GNUTLS_E_SUCCESS)
+      return gnutls_make_error (ret);
+
+  GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_PRIORITY;
+
+  message ("gnutls: setting the credentials");
+
+  if (EQ (type, Qgnutls_x509pki))
+  {
+      message ("gnutls: setting the x509 credentials");
+
+      ret = gnutls_cred_set (state, GNUTLS_CRD_CERTIFICATE, x509_cred);
+  }
+  else if (EQ (type, Qgnutls_anon))
+  {
+      message ("gnutls: setting the anon credentials");
+
+      ret = gnutls_cred_set (state, GNUTLS_CRD_ANON, anon_cred);
+  }
+  else
+  {
+      error ("unknown credential type");
+      ret = GNUTLS_EMACS_ERROR_INVALID_TYPE;
+  }
+
+  if (ret < GNUTLS_E_SUCCESS)
+      return gnutls_make_error (ret);
+
+  XPROCESS (proc)->anon_cred = anon_cred;
+  XPROCESS (proc)->x509_cred = x509_cred;
+  XPROCESS (proc)->gnutls_cred_type = type;
+
+  GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_CRED_SET;
+
+  return gnutls_make_error (GNUTLS_E_SUCCESS);
+}
+
+DEFUN ("gnutls-bye", Fgnutls_bye,
+       Sgnutls_bye, 2, 2, 0,
+       doc: /* Terminate current GNU TLS connection for PROCESS.
+The connection should have been initiated using `gnutls-handshake'.
+
+If CONT is not nil the TLS connection gets terminated and further
+receives and sends will be disallowed. If the return value is zero you
+may continue using the connection.  If CONT is nil, GnuTLS actually
+sends an alert containing a close request and waits for the peer to
+reply with the same message.  In order to reuse the connection you
+should wait for an EOF from the peer.
+
+This function may also return `gnutls-e-again', or
+`gnutls-e-interrupted'.  */)
+    (Lisp_Object proc, Lisp_Object cont)
+{
+  gnutls_session_t state;
+  int ret;
+
+  CHECK_PROCESS (proc);
+
+  state = XPROCESS (proc)->gnutls_state;
+
+  ret = gnutls_bye (state,
+                    NILP (cont) ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR);
+
+  return gnutls_make_error (ret);
+}
+
+DEFUN ("gnutls-handshake", Fgnutls_handshake,
+       Sgnutls_handshake, 1, 1, 0,
+       doc: /* Perform GNU TLS handshake for PROCESS.
+The identity of the peer is checked automatically.  This function will
+fail if any problem is encountered, and will return a negative error
+code. In case of a client, if it has been asked to resume a session,
+but the server didn't, then a full handshake will be performed.
+
+If the error `gnutls-e-not-ready-for-handshake' is returned, you
+didn't call `gnutls-boot' first.
+
+This function may also return the non-fatal errors `gnutls-e-again',
+or `gnutls-e-interrupted'. In that case you may resume the handshake
+(by calling this function again).  */)
+    (Lisp_Object proc)
+{
+  gnutls_session_t state;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  state = XPROCESS (proc)->gnutls_state;
+
+  if (GNUTLS_INITSTAGE (proc) < GNUTLS_STAGE_HANDSHAKE_CANDO)
+    return Qgnutls_e_not_ready_for_handshake;
+
+  /* for a network process in Emacs infd and outfd are the same
+     but this shows our intent more clearly.  */
+  gnutls_transport_set_ptr2 (state, XPROCESS (proc)->infd,
+                             XPROCESS (proc)->outfd);
+  ret = gnutls_handshake (state);
+
+  GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_HANDSHAKE_DONE;
+
+  if (GNUTLS_E_SUCCESS == ret)
+  {
+    /* here we're finally done.  */
+    GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_READY;
+  }
+
+  return gnutls_make_error (ret);
+}
+
+void
+syms_of_gnutls (void)
+{
+  global_initialized = 0;
+
+  Qgnutls_code = intern_c_string ("gnutls-code");
+  staticpro (&Qgnutls_code);
+
+  Qgnutls_anon = intern_c_string ("gnutls-anon");
+  staticpro (&Qgnutls_anon);
+
+  Qgnutls_x509pki = intern_c_string ("gnutls-x509pki");
+  staticpro (&Qgnutls_x509pki);
+
+  Qgnutls_e_interrupted = intern_c_string ("gnutls-e-interrupted");
+  staticpro (&Qgnutls_e_interrupted);
+  Fput (Qgnutls_e_interrupted, Qgnutls_code,
+        make_number (GNUTLS_E_INTERRUPTED));
+
+  Qgnutls_e_again = intern_c_string ("gnutls-e-again");
+  staticpro (&Qgnutls_e_again);
+  Fput (Qgnutls_e_again, Qgnutls_code,
+        make_number (GNUTLS_E_AGAIN));
+
+  Qgnutls_e_invalid_session = intern_c_string ("gnutls-e-invalid-session");
+  staticpro (&Qgnutls_e_invalid_session);
+  Fput (Qgnutls_e_invalid_session, Qgnutls_code,
+        make_number (GNUTLS_E_INVALID_SESSION));
+
+  Qgnutls_e_not_ready_for_handshake =
+    intern_c_string ("gnutls-e-not-ready-for-handshake");
+  staticpro (&Qgnutls_e_not_ready_for_handshake);
+  Fput (Qgnutls_e_not_ready_for_handshake, Qgnutls_code,
+        make_number (GNUTLS_E_APPLICATION_ERROR_MIN));
+
+  defsubr (&Sgnutls_get_initstage);
+  defsubr (&Sgnutls_errorp);
+  defsubr (&Sgnutls_error_string);
+  defsubr (&Sgnutls_global_init);
+  defsubr (&Sgnutls_global_deinit);
+  defsubr (&Sgnutls_boot);
+  defsubr (&Sgnutls_deinit);
+  defsubr (&Sgnutls_handshake);
+  defsubr (&Sgnutls_bye);
+}
+#endif

=== added file 'src/gnutls.h'
--- src/gnutls.h	1970-01-01 00:00:00 +0000
+++ src/gnutls.h	2010-09-14 15:41:02 +0000
@@ -0,0 +1,57 @@
+/* GnuTLS glue for GNU Emacs.
+   Copyright (C) 2010  Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs 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 3 of the License, or
+(at your option) any later version.
+
+GNU Emacs 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef EMACS_GNUTLS_DEFINED
+#define EMACS_GNUTLS_DEFINED
+
+#ifdef HAVE_GNUTLS
+#include <gnutls/gnutls.h>
+
+typedef enum
+{
+  GNUTLS_STAGE_EMPTY = 0,
+  GNUTLS_STAGE_CRED_ALLOC,
+  GNUTLS_STAGE_FILES,
+  GNUTLS_STAGE_INIT,
+  GNUTLS_STAGE_PRIORITY,
+  GNUTLS_STAGE_CRED_SET,
+
+  GNUTLS_STAGE_HANDSHAKE_CANDO = GNUTLS_STAGE_CRED_SET,
+  GNUTLS_STAGE_HANDSHAKE_DONE,
+
+  GNUTLS_STAGE_READY,
+} gnutls_initstage_t;
+
+#define GNUTLS_EMACS_ERROR_INVALID_TYPE GNUTLS_E_APPLICATION_ERROR_MIN
+
+#define GNUTLS_INITSTAGE(proc) (XPROCESS (proc)->gnutls_initstage)
+
+#define GNUTLS_PROCESS_USABLE(proc) (GNUTLS_INITSTAGE(proc) >= GNUTLS_STAGE_READY)
+
+int
+emacs_gnutls_write (int fildes, gnutls_session_t state, char *buf,
+                    unsigned int nbyte);
+int
+emacs_gnutls_read (int fildes, gnutls_session_t state, char *buf,
+                   unsigned int nbyte);
+
+extern void syms_of_gnutls (void);
+
+#endif 
+
+#endif

=== modified file 'src/process.c'
--- src/process.c	2010-08-22 15:14:37 +0000
+++ src/process.c	2010-09-14 15:41:02 +0000
@@ -105,6 +105,9 @@
 #include "sysselect.h"
 #include "syssignal.h"
 #include "syswait.h"
+#ifdef HAVE_GNUTLS
+#include "gnutls.h"
+#endif
 
 #if defined (USE_GTK) || defined (HAVE_GCONF)
 #include "xgselect.h"
@@ -583,6 +586,10 @@
   p->read_output_skip = 0;
 #endif
 
+#ifdef HAVE_GNUTLS
+  p->gnutls_initstage = GNUTLS_STAGE_EMPTY;
+#endif
+
   /* If name is already in use, modify it until it is unused.  */
 
   name1 = name;
@@ -1526,6 +1533,12 @@
   XPROCESS (proc)->filter = Qnil;
   XPROCESS (proc)->command = Flist (nargs - 2, args + 2);
 
+#ifdef HAVE_GNUTLS
+  /* AKA GNUTLS_INITSTAGE(proc).  */
+  XPROCESS (proc)->gnutls_initstage = GNUTLS_STAGE_EMPTY;
+  XPROCESS (proc)->gnutls_cred_type = Qnil;
+#endif
+
 #ifdef ADAPTIVE_READ_BUFFERING
   XPROCESS (proc)->adaptive_read_buffering
     = (NILP (Vprocess_adaptive_read_buffering) ? 0
@@ -5097,7 +5110,13 @@
 #endif
   if (proc_buffered_char[channel] < 0)
     {
-      nbytes = emacs_read (channel, chars + carryover, readmax);
+#ifdef HAVE_GNUTLS
+      if (NETCONN_P(proc) && GNUTLS_PROCESS_USABLE (proc))
+	nbytes = emacs_gnutls_read (channel, XPROCESS (proc)->gnutls_state,
+                                    chars + carryover, readmax);
+      else
+#endif
+	nbytes = emacs_read (channel, chars + carryover, readmax);
 #ifdef ADAPTIVE_READ_BUFFERING
       if (nbytes > 0 && p->adaptive_read_buffering)
 	{
@@ -5130,7 +5149,13 @@
     {
       chars[carryover] = proc_buffered_char[channel];
       proc_buffered_char[channel] = -1;
-      nbytes = emacs_read (channel, chars + carryover + 1,  readmax - 1);
+#ifdef HAVE_GNUTLS
+      if (NETCONN_P(proc) && GNUTLS_PROCESS_USABLE (proc))
+	nbytes = emacs_gnutls_read (channel, XPROCESS (proc)->gnutls_state,
+                                    chars + carryover + 1, readmax - 1);
+      else
+#endif
+	nbytes = emacs_read (channel, chars + carryover + 1,  readmax - 1);
       if (nbytes < 0)
 	nbytes = 1;
       else
@@ -5540,7 +5565,14 @@
 	      else
 #endif
 		{
-		  rv = emacs_write (outfd, (char *) buf, this);
+#ifdef HAVE_GNUTLS
+		  if (NETCONN_P(proc) && GNUTLS_PROCESS_USABLE (proc))
+		    rv = emacs_gnutls_write (outfd,
+					     XPROCESS (proc)->gnutls_state, 
+					     (char *) buf, this);
+		  else
+#endif
+		    rv = emacs_write (outfd, (char *) buf, this);
 #ifdef ADAPTIVE_READ_BUFFERING
 		  if (p->read_output_delay > 0
 		      && p->adaptive_read_buffering == 1)

=== modified file 'src/process.h'
--- src/process.h	2010-08-11 12:34:46 +0000
+++ src/process.h	2010-09-14 15:41:02 +0000
@@ -24,6 +24,10 @@
 #include <unistd.h>
 #endif
 
+#ifdef HAVE_GNUTLS
+#include "gnutls.h"
+#endif
+
 /* This structure records information about a subprocess
    or network connection.
 
@@ -76,6 +80,10 @@
     /* Working buffer for encoding.  */
     Lisp_Object encoding_buf;
 
+#ifdef HAVE_GNUTLS
+    Lisp_Object gnutls_cred_type;
+#endif
+
     /* After this point, there are no Lisp_Objects any more.  */
     /* alloc.c assumes that `pid' is the first such non-Lisp slot.  */
 
@@ -121,6 +129,13 @@
        needs to be synced to `status'.  */
     unsigned int raw_status_new : 1;
     int raw_status;
+
+#ifdef HAVE_GNUTLS
+    gnutls_initstage_t gnutls_initstage;
+    gnutls_session_t gnutls_state;
+    gnutls_certificate_client_credentials x509_cred;
+    gnutls_anon_client_credentials_t anon_cred;
+#endif
 };
 
 /* Every field in the preceding structure except for the first two


[-- Attachment #3: Type: text/plain, Size: 146 bytes --]

_______________________________________________
Gnutls-devel mailing list
Gnutls-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/gnutls-devel

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-13  7:49                                   ` Nikos Mavrogiannopoulos
@ 2010-09-14 18:30                                     ` Ted Zlatanov
  2010-09-14 18:55                                       ` Nikos Mavrogiannopoulos
  2010-09-15 11:01                                     ` Ted Zlatanov
  1 sibling, 1 reply; 93+ messages in thread
From: Ted Zlatanov @ 2010-09-14 18:30 UTC (permalink / raw)
  To: gnutls-devel; +Cc: emacs-devel

On Mon, 13 Sep 2010 09:49:30 +0200 Nikos Mavrogiannopoulos <nmav@gnutls.org> wrote: 

NM> 2010/9/11 Ted Zlatanov <tzz@lifelogs.com>:
>> - no SRP anywhere, just anon and x509 (I'll add SRP if we need it and
>>  when the other two are working)
>> Now I get GNUTLS_E_INSUFFICIENT_CREDENTIALS when I open a x509
>> connection to an IMAP TLS server so I think there's still work to do.
>> The trust file seems to be wrong (see lisp/net/gnutls.el, I tried both
>> "/etc/ssl/certs/ca-certificates.crt" and "/etc/ssl/certs/ca.pem").
>> The GnuTLS examples don't seem to cover the standard situation of
>> talking to a web server over SSL and possibly accepting an insecure
>> connection if the server credentials are bad.  I must have missed
>> something.  Could the GnuTLS developers look at my patch and help me
>> out?

NM> I cannot look at the patch but the example you are looking for is:
NM> http://www.gnu.org/software/gnutls/manual/html_node/Simple-client-example-with-X_002e509-certificate-support.html#Simple-client-example-with-X_002e509-certificate-support
NM> to do the connection, and this one to verify the certificate:
NM> http://www.gnu.org/software/gnutls/manual/html_node/Verifying-peer_0027s-certificate.html#Verifying-peer_0027s-certificate

What ca.pem should I use?  There's one in GnuTLS and one in
/etc/ssl/certs/ca.pem on my Ubuntu system.  It should Just Work so it
may make sense to ship ca.pem with Emacs.  WDYT?

The simple client code is implemented in my current patch.  Without
verifying anything I keep getting GNUTLS_E_AGAIN when I try to handshake
against an SSL server.  See gnutls-boot, the control flow is really
simple and I think correct.  What am I missing?

Thanks!
Ted

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-14 18:30                                     ` Ted Zlatanov
@ 2010-09-14 18:55                                       ` Nikos Mavrogiannopoulos
  2010-09-14 19:10                                         ` Lars Magne Ingebrigtsen
  2010-09-15  1:25                                         ` Ted Zlatanov
  0 siblings, 2 replies; 93+ messages in thread
From: Nikos Mavrogiannopoulos @ 2010-09-14 18:55 UTC (permalink / raw)
  To: Ted Zlatanov; +Cc: gnutls-devel, emacs-devel

On 09/14/2010 08:30 PM, Ted Zlatanov wrote:
> On Mon, 13 Sep 2010 09:49:30 +0200 Nikos Mavrogiannopoulos <nmav@gnutls.org> wrote: 
> 
> NM> 2010/9/11 Ted Zlatanov <tzz@lifelogs.com>:
>>> - no SRP anywhere, just anon and x509 (I'll add SRP if we need it and
>>>  when the other two are working)
>>> Now I get GNUTLS_E_INSUFFICIENT_CREDENTIALS when I open a x509
>>> connection to an IMAP TLS server so I think there's still work to do.
>>> The trust file seems to be wrong (see lisp/net/gnutls.el, I tried both
>>> "/etc/ssl/certs/ca-certificates.crt" and "/etc/ssl/certs/ca.pem").
>>> The GnuTLS examples don't seem to cover the standard situation of
>>> talking to a web server over SSL and possibly accepting an insecure
>>> connection if the server credentials are bad.  I must have missed
>>> something.  Could the GnuTLS developers look at my patch and help me
>>> out?
> NM> I cannot look at the patch but the example you are looking for is:
> NM> http://www.gnu.org/software/gnutls/manual/html_node/Simple-client-example-with-X_002e509-certificate-support.html#Simple-client-example-with-X_002e509-certificate-support
> NM> to do the connection, and this one to verify the certificate:
> NM> http://www.gnu.org/software/gnutls/manual/html_node/Verifying-peer_0027s-certificate.html#Verifying-peer_0027s-certificate
> 
> What ca.pem should I use?  There's one in GnuTLS and one in
> /etc/ssl/certs/ca.pem on my Ubuntu system.  It should Just Work so it
> may make sense to ship ca.pem with Emacs.  WDYT?

This is local policy, I don't think that it has to be shipped with
emacs. Just give the option of someone specifying it.

> The simple client code is implemented in my current patch.  Without
> verifying anything I keep getting GNUTLS_E_AGAIN when I try to handshake
> against an SSL server.  See gnutls-boot, the control flow is really
> simple and I think correct.  What am I missing?

GNUTLS_E_AGAIN is returned only if the transport layer function
(recv/send) return -1 and EAGAIN. Usually this is normal behavior and is
enough to loop around them. Do you use non-blocking IO?


regards,
Nikos



^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-14 18:55                                       ` Nikos Mavrogiannopoulos
@ 2010-09-14 19:10                                         ` Lars Magne Ingebrigtsen
  2010-09-15 11:20                                           ` Ted Zlatanov
  2010-09-15  1:25                                         ` Ted Zlatanov
  1 sibling, 1 reply; 93+ messages in thread
From: Lars Magne Ingebrigtsen @ 2010-09-14 19:10 UTC (permalink / raw)
  To: emacs-devel; +Cc: gnutls-devel

Nikos Mavrogiannopoulos <nmav@gnutls.org> writes:

>> What ca.pem should I use?  There's one in GnuTLS and one in
>> /etc/ssl/certs/ca.pem on my Ubuntu system.  It should Just Work so it
>> may make sense to ship ca.pem with Emacs.  WDYT?
>
> This is local policy, I don't think that it has to be shipped with
> emacs. Just give the option of someone specifying it.

I don't know how tls stuff works at all, but if a certificate is needed
for basic usage, then it should be shipped with Emacs.

-- 
(domestic pets only, the antidote for overdose, milk.)
  larsi@gnus.org * Lars Magne Ingebrigtsen




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-14 18:55                                       ` Nikos Mavrogiannopoulos
  2010-09-14 19:10                                         ` Lars Magne Ingebrigtsen
@ 2010-09-15  1:25                                         ` Ted Zlatanov
  1 sibling, 0 replies; 93+ messages in thread
From: Ted Zlatanov @ 2010-09-15  1:25 UTC (permalink / raw)
  To: emacs-devel; +Cc: gnutls-devel

On Tue, 14 Sep 2010 20:55:51 +0200 Nikos Mavrogiannopoulos <nmav@gnutls.org> wrote: 

NM> On 09/14/2010 08:30 PM, Ted Zlatanov wrote:

>> The simple client code is implemented in my current patch.  Without
>> verifying anything I keep getting GNUTLS_E_AGAIN when I try to handshake
>> against an SSL server.  See gnutls-boot, the control flow is really
>> simple and I think correct.  What am I missing?

NM> GNUTLS_E_AGAIN is returned only if the transport layer function
NM> (recv/send) return -1 and EAGAIN. Usually this is normal behavior and is
NM> enough to loop around them. Do you use non-blocking IO?

The I/O is on the underlying process file descriptors, which in our case
are network sockets.  I'm not actually sure of all the setup done on
those sockets because Emacs' process.c is a bit of a labyrinth, but
Simon Josefsson's original patch just used them directly and it worked
for him.

Ted




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-13  7:49                                   ` Nikos Mavrogiannopoulos
  2010-09-14 18:30                                     ` Ted Zlatanov
@ 2010-09-15 11:01                                     ` Ted Zlatanov
  2010-09-15 12:13                                       ` Nikos Mavrogiannopoulos
  2010-09-21 11:37                                       ` Simon Josefsson
  1 sibling, 2 replies; 93+ messages in thread
From: Ted Zlatanov @ 2010-09-15 11:01 UTC (permalink / raw)
  To: gnutls-devel; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 3047 bytes --]

On Mon, 13 Sep 2010 09:49:30 +0200 Nikos Mavrogiannopoulos <nmav@gnutls.org> wrote: 

NM> I cannot look at the patch but the example you are looking for is:
NM> http://www.gnu.org/software/gnutls/manual/html_node/Simple-client-example-with-X_002e509-certificate-support.html#Simple-client-example-with-X_002e509-certificate-support
NM> to do the connection, and this one to verify the certificate:
NM> http://www.gnu.org/software/gnutls/manual/html_node/Verifying-peer_0027s-certificate.html#Verifying-peer_0027s-certificate

Thanks for your help.  I am still a little lost though :)

Can you give a specific command line that would start gnutls-serv so the
simple client (ex-client2.c) you reference will connect to it?  If
that's not possible, is there a way to augment ex-client2.c so it
connects to an invocation of gnutls-serv without building all the
gnutls-cli (cli.c, etc.) infrastructure?

I can do a test connection with gnutls-cli but that's a much more
complicated program and I'm trying to get the simple connection working,
even without verification.  If I can get the bare minimum SSL and TLS
working I can drop the patch into Emacs and get more eyes on it.  I'm
tempted to do so now so I can stop sending this patch out :)

It would be wonderful, incidentally, if there was a way to configure all
the file options with a single string, similar to the priority string,
and just get back a session.  A config file would also work if a single
string is too hard to parse.  I don't see any options that couldn't work
like this and it would make setting up a GnuTLS connection much easier.

On Tue, 14 Sep 2010 20:55:51 +0200 Nikos Mavrogiannopoulos <nmav@gnutls.org> wrote: 

NM> GNUTLS_E_AGAIN is returned only if the transport layer function
NM> (recv/send) return -1 and EAGAIN. Usually this is normal behavior and is
NM> enough to loop around them. Do you use non-blocking IO?

Ah, thanks for the hint.  All the GnuTLS source code (e.g. the
do_handshake() function in cli.c) keeps looping forever as long as
GNUTLS_E_AGAIN is returned.  That seems dangerous regardless of the
underlying mechanism because we don't want to lock up Emacs waiting for
a connection, but OTOH there's no other way to know if the handshake is
done.  I limited it to 25000 times (used to be 25) in my patch.  Is that
a reasonable limit?  Should I base it on time elapsed?

With a limit of 25K and by checking `gnutls-error-fatalp' which calls
`gnutls_error_is_fatal', the handshake succeeds after 1250 tries against
a remote SSL server.  So now against that server I get:

-24 (Decryption has failed.)

and against "gnutls-serv --priority NORMAL --http" I get

-12 (A TLS fatal alert has been received.)

(the server side says "Error in handshake
Error: Could not negotiate a supported cipher suite.")

which is a lot better: at least the handshake is no longer the problem
and it tells us the transport FDs are set correctly.  So we can progress
to figuring out the bare minimum I mentioned above.

Latest patch attached, as usual.

Thanks again...
Ted


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: tls.patch --]
[-- Type: text/x-diff, Size: 30665 bytes --]

=== modified file 'configure.in'
--- configure.in	2010-09-13 19:50:30 +0000
+++ configure.in	2010-09-15 09:13:07 +0000
@@ -171,6 +171,7 @@
 OPTION_DEFAULT_ON([dbus],[don't compile with D-Bus support])
 OPTION_DEFAULT_ON([gconf],[don't compile with GConf support])
 OPTION_DEFAULT_ON([selinux],[don't compile with SELinux support])
+OPTION_DEFAULT_ON([gnutls],[don't use -lgnutls for SSL/TLS support])
 
 ## For the times when you want to build Emacs but don't have
 ## a suitable makeinfo, and can live without the manuals.
@@ -1999,6 +2000,13 @@
 fi
 AC_SUBST(LIBSELINUX_LIBS)
 
+HAVE_GNUTLS=no
+if test "${with_gnutls}" = "yes" ; then
+  PKG_CHECK_MODULES([LIBGNUTLS], [gnutls >= 2.2.4])
+  AC_DEFINE(HAVE_GNUTLS)
+  HAVE_GNUTLS=yes
+fi
+
 dnl Do not put whitespace before the #include statements below.
 dnl Older compilers (eg sunos4 cc) choke on it.
 HAVE_XAW3D=no
@@ -3701,6 +3709,7 @@
 echo "  Does Emacs use -ldbus?                                  ${HAVE_DBUS}"
 echo "  Does Emacs use -lgconf?                                 ${HAVE_GCONF}"
 echo "  Does Emacs use -lselinux?                               ${HAVE_LIBSELINUX}"
+echo "  Does Emacs use -lgnutls?                                ${HAVE_GNUTLS}"
 
 echo "  Does Emacs use -lfreetype?                              ${HAVE_FREETYPE}"
 echo "  Does Emacs use -lm17n-flt?                              ${HAVE_M17N_FLT}"

=== added file 'lisp/net/gnutls.el'
--- lisp/net/gnutls.el	1970-01-01 00:00:00 +0000
+++ lisp/net/gnutls.el	2010-09-15 10:38:20 +0000
@@ -0,0 +1,131 @@
+;;; gnutls.el --- Support SSL and TLS connections through GnuTLS
+;; Copyright (C) 2010 Free Software Foundation, Inc.
+
+;; Author: Ted Zlatanov <tzz@lifelogs.com>
+;; Keywords: comm, tls, ssl, encryption
+;; Originally-By: Simon Josefsson (See http://josefsson.org/emacs-security/)
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This package provides language bindings for the GnuTLS library
+;; using the corresponding core functions in gnutls.c.
+
+;; Simple test:
+;;
+;; (setq jas (open-ssl-stream "ssl" (current-buffer) "www.pdc.kth.se" 443))
+;; (process-send-string jas "GET /\r\n\r\n")
+
+;;; Code:
+
+(defconst gnutls-version "0.3.1")
+
+(defun open-ssl-stream (name buffer host service)
+  "Open a SSL connection for a service to a host.
+Returns a subprocess-object to represent the connection.
+Input and output work as for subprocesses; `delete-process' closes it.
+Args are NAME BUFFER HOST SERVICE.
+NAME is name for process.  It is modified if necessary to make it unique.
+BUFFER is the buffer (or `buffer-name') to associate with the process.
+ Process output goes at end of that buffer, unless you specify
+ an output stream or filter function to handle the output.
+ BUFFER may be also nil, meaning that this process is not associated
+ with any buffer
+Third arg is name of the host to connect to, or its IP address.
+Fourth arg SERVICE is name of the service desired, or an integer
+specifying a port number to connect to."
+  (let ((proc (open-network-stream name buffer host service)))
+    (starttls-negotiate proc nil 'gnutls-x509pki)))
+
+;; (open-ssl-stream "tls" "tls-buffer" "yourserver.com" "https")
+(defun starttls-negotiate (proc &optional priority-string
+                                credentials credentials-file)
+  "Negotiate a SSL or TLS connection.
+PROC is the process returned by `starttls-open-stream'.
+PRIORITY-STRING is as per the GnuTLS docs.
+CREDENTIALS is `gnutls-x509pki' or `gnutls-anon'.
+CREDENTIALS-FILE is a filename with meaning dependent on CREDENTIALS."
+  (let* ((credentials (or credentials 'gnutls-x509pki))
+         (credentials-file (or credentials-file
+                               ;"/etc/ssl/certs/ca-certificates.crt"
+                               ;"/etc/ssl/certs/ca.pem"
+                               "/tmp/ca.pem"
+                               ))
+
+         (priority-string (or priority-string
+                              (cond
+                               ((eq credentials 'gnutls-anon)
+                                "PERFORMANCE:+ANON-DH:!ARCFOUR-128")
+                               ((eq credentials 'gnutls-x509pki)
+                                "PERFORMANCE"))))
+         ret)
+
+    (gnutls-message-maybe
+     (setq ret (gnutls-boot proc priority-string credentials credentials-file))
+     "boot: %s")
+
+    (when (gnutls-errorp ret)
+      (error "Could not boot GnuTLS for this process"));
+
+    (let ((ret 'gnutls-e-again)
+          (n 25000))
+      (while (and (not (gnutls-error-fatalp ret))
+                  (> n 0))
+        (decf n)
+        (gnutls-message-maybe
+         (setq ret (gnutls-handshake proc))
+         "handshake: %s")
+        ;(debug "handshake ret" ret (gnutls-error-string ret)))
+        )
+      (if (gnutls-errorp ret)
+          (progn
+            (message "Ouch, error return %s (%s)"
+                     ret (gnutls-error-string ret))
+            (setq proc nil))
+        (message "Handshake complete %s." ret)))
+     proc))
+
+(defun starttls-open-stream (name buffer host service)
+  "Open a TLS connection for a service to a host.
+Returns a subprocess-object to represent the connection.
+Input and output work as for subprocesses; `delete-process' closes it.
+Args are NAME BUFFER HOST SERVICE.
+NAME is name for process.  It is modified if necessary to make it unique.
+BUFFER is the buffer (or `buffer-name') to associate with the process.
+ Process output goes at end of that buffer, unless you specify
+ an output stream or filter function to handle the output.
+ BUFFER may be also nil, meaning that this process is not associated
+ with any buffer
+Third arg is name of the host to connect to, or its IP address.
+Fourth arg SERVICE is name of the service desired, or an integer
+specifying a port number to connect to."
+  (open-network-stream name buffer host service))
+
+(defun gnutls-message-maybe (doit format &rest params)
+  "When DOIT, message with the caller name followed by FORMAT on PARAMS."
+  ;; (apply 'debug format (or params '(nil)))
+  (when (gnutls-errorp doit)
+    (message "%s: (err=[%s] %s) %s"
+             "gnutls.el"
+             doit (gnutls-error-string doit)
+             (apply 'format format (or params '(nil))))))
+
+(provide 'ssl)
+(provide 'gnutls)
+(provide 'starttls)
+
+;;; gnutls.el ends here

=== modified file 'src/Makefile.in'
--- src/Makefile.in	2010-09-10 16:44:35 +0000
+++ src/Makefile.in	2010-09-15 09:13:07 +0000
@@ -287,6 +287,9 @@
 
 LIBSELINUX_LIBS = @LIBSELINUX_LIBS@
 
+LIBGNUTLS_LIBS = @LIBGNUTLS_LIBS@
+LIBGNUTLS_CFLAGS = @LIBGNUTLS_CFLAGS@
+
 INTERVALS_H = dispextern.h intervals.h composite.h
 
 GETLOADAVG_LIBS = @GETLOADAVG_LIBS@
@@ -326,6 +329,7 @@
   ${LIBXML2_CFLAGS} ${DBUS_CFLAGS} \
   ${GCONF_CFLAGS} ${FREETYPE_CFLAGS} ${FONTCONFIG_CFLAGS} \
   ${LIBOTF_CFLAGS} ${M17N_FLT_CFLAGS} ${DEPFLAGS} ${PROFILING_CFLAGS} \
+  $(LIBGNUTLS_CFLAGS) \
   ${C_WARNINGS_SWITCH} ${CFLAGS}
 ALL_OBJC_CFLAGS=$(ALL_CFLAGS) $(GNU_OBJC_CFLAGS)
 
@@ -350,7 +354,7 @@
 	alloc.o data.o doc.o editfns.o callint.o \
 	eval.o floatfns.o fns.o font.o print.o lread.o \
 	syntax.o $(UNEXEC_OBJ) bytecode.o \
-	process.o callproc.o \
+	process.o gnutls.o callproc.o \
 	region-cache.o sound.o atimer.o \
 	doprnt.o strftime.o intervals.o textprop.o composite.o md5.o xml.o \
 	$(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ)
@@ -602,6 +606,7 @@
    ${LIBXML2_LIBS} $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \
    $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) ${GCONF_LIBS} ${LIBSELINUX_LIBS} \
    $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
+   $(LIBGNUTLS_LIBS) \
    $(LIB_GCC) $(LIB_MATH) $(LIB_STANDARD) $(LIB_GCC)
 
 all: emacs${EXEEXT} $(OTHER_FILES)

=== modified file 'src/config.in'
--- src/config.in	2010-09-10 16:44:35 +0000
+++ src/config.in	2010-09-15 09:13:07 +0000
@@ -255,6 +255,9 @@
 /* Define to 1 if you have a gif (or ungif) library. */
 #undef HAVE_GIF
 
+/* Define if we have the GNU TLS library.  */
+#undef HAVE_GNUTLS
+
 /* Define to 1 if you have the gpm library (-lgpm). */
 #undef HAVE_GPM
 
@@ -1094,6 +1097,12 @@
 #include config_opsysfile
 #include config_machfile
 
+#if HAVE_GNUTLS
+#define LIBGNUTLS $(LIBGNUTLS_LIBS)
+#else /* not HAVE_GNUTLS */
+#define LIBGNUTLS
+#endif /* not HAVE_GNUTLS */
+
 /* Set up some defines, C and LD flags for NeXTstep interface on GNUstep.
   (There is probably a better place to do this, but right now the Cocoa
    side does this in s/darwin.h and we cannot

=== modified file 'src/emacs.c'
--- src/emacs.c	2010-09-10 16:44:35 +0000
+++ src/emacs.c	2010-09-15 09:13:07 +0000
@@ -63,6 +63,10 @@
 #include "keyboard.h"
 #include "keymap.h"
 
+#ifdef HAVE_GNUTLS
+#include "gnutls.h"
+#endif
+
 #ifdef HAVE_NS
 #include "nsterm.h"
 #endif
@@ -1573,6 +1577,10 @@
       syms_of_fontset ();
 #endif /* HAVE_NS */
 
+#ifdef HAVE_GNUTLS
+      syms_of_gnutls ();
+#endif
+
 #ifdef HAVE_DBUS
       syms_of_dbusbind ();
 #endif /* HAVE_DBUS */

=== added file 'src/gnutls.c'
--- src/gnutls.c	1970-01-01 00:00:00 +0000
+++ src/gnutls.c	2010-09-15 10:29:28 +0000
@@ -0,0 +1,546 @@
+/* GnuTLS glue for GNU Emacs.
+   Copyright (C) 2010  Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs 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 3 of the License, or
+(at your option) any later version.
+
+GNU Emacs 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+#include <errno.h>
+#include <setjmp.h>
+
+#include "lisp.h"
+#include "process.h"
+
+#ifdef HAVE_GNUTLS
+#include <gnutls/gnutls.h>
+
+Lisp_Object Qgnutls_code;
+Lisp_Object Qgnutls_anon, Qgnutls_x509pki;
+Lisp_Object Qgnutls_e_interrupted, Qgnutls_e_again,
+  Qgnutls_e_invalid_session, Qgnutls_e_not_ready_for_handshake;
+int global_initialized;
+
+int
+emacs_gnutls_write (int fildes, gnutls_session_t state, char *buf,
+                    unsigned int nbyte)
+{
+  register int rtnval, bytes_written;
+
+  bytes_written = 0;
+
+  while (nbyte > 0)
+    {
+      rtnval = gnutls_write (state, buf, nbyte);
+
+      if (rtnval == -1)
+        {
+          if (errno == EINTR)
+            continue;
+          else
+            return (bytes_written ? bytes_written : -1);
+        }
+
+      buf += rtnval;
+      nbyte -= rtnval;
+      bytes_written += rtnval;
+    }
+  fsync (STDOUT_FILENO);
+
+  return (bytes_written);
+}
+
+int
+emacs_gnutls_read (int fildes, gnutls_session_t state, char *buf,
+                   unsigned int nbyte)
+{
+  register int rtnval;
+
+  do {
+    rtnval = gnutls_read (state, buf, nbyte);
+  } while (rtnval == GNUTLS_E_INTERRUPTED || rtnval == GNUTLS_E_AGAIN);
+  fsync (STDOUT_FILENO);
+
+  return (rtnval);
+}
+
+/* convert an integer error to a Lisp_Object; it will be either a
+   known symbol like `gnutls_e_interrupted' and `gnutls_e_again' or
+   simply the integer value of the error.  GNUTLS_E_SUCCESS is mapped
+   to Qt.  */
+Lisp_Object gnutls_make_error (int error)
+{
+  switch (error)
+  {
+  case GNUTLS_E_SUCCESS:
+    return Qt;
+  case GNUTLS_E_AGAIN:
+    return Qgnutls_e_again;
+  case GNUTLS_E_INTERRUPTED:
+    return Qgnutls_e_interrupted;
+  case GNUTLS_E_INVALID_SESSION:
+    return Qgnutls_e_invalid_session;
+  }
+
+  return make_number (error);
+}
+
+DEFUN ("gnutls-get-initstage", Fgnutls_get_initstage, Sgnutls_get_initstage, 1, 1, 0,
+       doc: /* Return the GnuTLS init stage of PROCESS.
+See also `gnutls-boot'.  */)
+    (Lisp_Object proc)
+{
+  CHECK_PROCESS (proc);
+
+  return make_number (GNUTLS_INITSTAGE (proc));
+}
+
+DEFUN ("gnutls-errorp", Fgnutls_errorp, Sgnutls_errorp, 1, 1, 0,
+       doc: /* Returns t if ERROR (as generated by gnutls_make_error)
+indicates a GnuTLS problem.  */)
+    (Lisp_Object error)
+{
+  if (EQ (error, Qt)) return Qnil;
+
+  return Qt;
+}
+
+DEFUN ("gnutls-error-fatalp", Fgnutls_error_fatalp, Sgnutls_error_fatalp, 1, 1, 0,
+       doc: /* Checks if ERROR is fatal.
+ERROR is an integer or a symbol with an integer `gnutls-code' property.  */)
+    (Lisp_Object err)
+{
+  Lisp_Object code;
+
+  if (EQ (err, Qt)) return Qnil;
+
+  if (SYMBOLP (err))
+  {
+    code = Fget (err, Qgnutls_code);
+    if (NUMBERP (code))
+    {
+      err = code;
+    }
+    else
+    {
+      error ("Symbol has no numeric gnutls-code property");
+    }
+  }
+
+  if (!NUMBERP (err))
+    error ("Not an error symbol or code");
+
+  if (0 == gnutls_error_is_fatal (XINT (err)))
+    return Qnil;
+
+  return Qt;
+}
+
+DEFUN ("gnutls-error-string", Fgnutls_error_string, Sgnutls_error_string, 1, 1, 0,
+       doc: /* Returns a description of ERROR.
+ERROR is an integer or a symbol with an integer `gnutls-code' property.  */)
+    (Lisp_Object err)
+{
+  Lisp_Object code;
+
+  if (EQ (err, Qt)) return build_string ("Not an error");
+
+  if (SYMBOLP (err))
+  {
+    code = Fget (err, Qgnutls_code);
+    if (NUMBERP (code))
+    {
+      err = code;
+    }
+    else
+    {
+      return build_string ("Symbol has no numeric gnutls-code property");
+    }
+  }
+
+  if (!NUMBERP (err))
+    return build_string ("Not an error symbol or code");
+
+  return build_string (gnutls_strerror (XINT (err)));
+}
+
+DEFUN ("gnutls-deinit", Fgnutls_deinit, Sgnutls_deinit, 1, 1, 0,
+       doc: /* Deallocate GNU TLS resources associated with PROCESS.
+See also `gnutls-init'.  */)
+    (Lisp_Object proc)
+{
+  gnutls_session_t state;
+
+  CHECK_PROCESS (proc);
+  state = XPROCESS (proc)->gnutls_state;
+
+  if (GNUTLS_INITSTAGE (proc) >= GNUTLS_STAGE_INIT)
+  {
+      gnutls_deinit (state);
+      GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_INIT - 1;
+  }
+
+  return Qt;
+}
+
+DEFUN ("gnutls-global-init", Fgnutls_global_init,
+       Sgnutls_global_init, 0, 0, 0,
+       doc: /* Initializes global GNU TLS state to defaults.
+Call `gnutls-global-deinit' when GNU TLS usage is no longer needed.
+Returns zero on success.  */)
+     (void)
+{
+  int ret = GNUTLS_E_SUCCESS;
+
+  if (!global_initialized)
+    ret = gnutls_global_init ();
+
+  global_initialized = 1;
+
+  return gnutls_make_error (ret);
+}
+
+DEFUN ("gnutls-global-deinit", Fgnutls_global_deinit,
+       Sgnutls_global_deinit, 0, 0, 0,
+       doc: /* Deinitializes global GNU TLS state.
+See also `gnutls-global-init'.  */)
+     (void)
+{
+  if (global_initialized)
+    gnutls_global_deinit ();
+
+  global_initialized = 0;
+
+  return gnutls_make_error (GNUTLS_E_SUCCESS);
+}
+
+DEFUN ("gnutls-boot", Fgnutls_boot, Sgnutls_boot, 3, 6, 0,
+       doc: /* Initializes client-mode GnuTLS for process PROC.
+Currently only client mode is supported.  Returns a success/failure
+value you can check with `gnutls-errorp'.
+
+PRIORITY_STRING is a string describing the priority.
+TYPE is either `gnutls-anon' or `gnutls-x509pki'.
+TRUSTFILE is a PEM encoded trust file for `gnutls-x509pki'.
+KEYFILE is ... for `gnutls-x509pki' (TODO).
+CALLBACK is ... for `gnutls-x509pki' (TODO).
+
+Note that the priority is set on the client.  The server does not use
+the protocols's priority except for disabling protocols that were not
+specified.
+
+Processes must be initialized with this function before other GNU TLS
+functions are used.  This function allocates resources which can only
+be deallocated by calling `gnutls-deinit' or by calling it again.
+
+Each authentication type may need additional information in order to
+work.  For X.509 PKI (`gnutls-x509pki'), you need TRUSTFILE and
+KEYFILE and optionally CALLBACK.  */)
+    (Lisp_Object proc, Lisp_Object priority_string, Lisp_Object type,
+     Lisp_Object trustfile, Lisp_Object keyfile, Lisp_Object callback)
+{
+  int ret = GNUTLS_E_SUCCESS;
+
+  /* TODO: GNUTLS_X509_FMT_DER is also an option.  */
+  int file_format = GNUTLS_X509_FMT_PEM;
+
+  gnutls_session_t state;
+  gnutls_certificate_credentials_t x509_cred;
+  gnutls_anon_client_credentials_t anon_cred;
+  gnutls_srp_client_credentials_t srp_cred;
+  gnutls_datum_t data;
+  Lisp_Object global_init;
+
+  CHECK_PROCESS (proc);
+  CHECK_SYMBOL (type);
+  CHECK_STRING (priority_string);
+
+  state = XPROCESS (proc)->gnutls_state;
+
+  /* always initialize globals.  */
+  global_init = Fgnutls_global_init ();
+  if (! NILP (Fgnutls_errorp (global_init)))
+    return global_init;
+
+  /* deinit and free resources.  */
+  if (GNUTLS_INITSTAGE (proc) >= GNUTLS_STAGE_CRED_ALLOC)
+  {
+      message ("gnutls: deallocating certificates");
+
+      if (EQ (type, Qgnutls_x509pki))
+      {
+          message ("gnutls: deallocating x509 certificates");
+
+          x509_cred = XPROCESS (proc)->x509_cred;
+          gnutls_certificate_free_credentials (x509_cred);
+      }
+      else if (EQ (type, Qgnutls_anon))
+      {
+          message ("gnutls: deallocating anon certificates");
+
+          anon_cred = XPROCESS (proc)->anon_cred;
+          gnutls_anon_free_client_credentials (anon_cred);
+      }
+      else
+      {
+          error ("unknown credential type");
+          ret = GNUTLS_EMACS_ERROR_INVALID_TYPE;
+      }
+
+      if (GNUTLS_INITSTAGE (proc) >= GNUTLS_STAGE_INIT)
+      {
+          message ("gnutls: deinitializing");
+
+          Fgnutls_deinit (proc);
+      }
+  }
+
+  GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_EMPTY;
+
+  message ("gnutls: allocating credentials");
+
+  if (EQ (type, Qgnutls_x509pki))
+  {
+      message ("gnutls: allocating x509 credentials");
+
+      x509_cred = XPROCESS (proc)->x509_cred;
+      if (gnutls_certificate_allocate_credentials (&x509_cred) < 0)
+        memory_full ();
+  }
+  else if (EQ (type, Qgnutls_anon))
+  {
+      message ("gnutls: allocating anon credentials");
+
+      anon_cred = XPROCESS (proc)->anon_cred;
+      if (gnutls_anon_allocate_client_credentials (&anon_cred) < 0)
+        memory_full ();
+  }
+  else
+  {
+      error ("unknown credential type");
+      ret = GNUTLS_EMACS_ERROR_INVALID_TYPE;
+  }
+
+  if (ret < GNUTLS_E_SUCCESS)
+      return gnutls_make_error (ret);
+
+  GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_CRED_ALLOC;
+
+  message ("gnutls: setting the trustfile");
+
+  if (EQ (type, Qgnutls_x509pki))
+  {
+      if (STRINGP (trustfile))
+      {
+          ret = gnutls_certificate_set_x509_trust_file
+            (x509_cred,
+             XSTRING (trustfile)->data,
+             file_format);
+
+          if (ret < GNUTLS_E_SUCCESS)
+            return gnutls_make_error (ret);
+
+          message ("gnutls: processed %d CA certificates", ret);
+      }
+
+      message ("gnutls: setting the keyfile");
+
+      if (STRINGP (keyfile))
+      {
+          ret = gnutls_certificate_set_x509_crl_file
+            (x509_cred,
+             XSTRING (keyfile)->data,
+             file_format);
+
+          if (ret < GNUTLS_E_SUCCESS)
+            return gnutls_make_error (ret);
+
+          message ("gnutls: processed %d CRL(s)", ret);
+      }
+  }
+
+  GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_FILES;
+
+  message ("gnutls: gnutls_init");
+
+  ret = gnutls_init (&state, GNUTLS_CLIENT);
+
+  if (ret < GNUTLS_E_SUCCESS)
+      return gnutls_make_error (ret);
+
+  XPROCESS (proc)->gnutls_state = state;
+
+  GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_INIT;
+
+  message ("gnutls: setting the priority string");
+
+  ret = gnutls_priority_set_direct(state,
+                                   (char*) SDATA (priority_string),
+                                   NULL);
+
+  if (ret < GNUTLS_E_SUCCESS)
+      return gnutls_make_error (ret);
+
+  GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_PRIORITY;
+
+  message ("gnutls: setting the credentials");
+
+  if (EQ (type, Qgnutls_x509pki))
+  {
+      message ("gnutls: setting the x509 credentials");
+
+      ret = gnutls_cred_set (state, GNUTLS_CRD_CERTIFICATE, x509_cred);
+  }
+  else if (EQ (type, Qgnutls_anon))
+  {
+      message ("gnutls: setting the anon credentials");
+
+      ret = gnutls_cred_set (state, GNUTLS_CRD_ANON, anon_cred);
+  }
+  else
+  {
+      error ("unknown credential type");
+      ret = GNUTLS_EMACS_ERROR_INVALID_TYPE;
+  }
+
+  if (ret < GNUTLS_E_SUCCESS)
+      return gnutls_make_error (ret);
+
+  XPROCESS (proc)->anon_cred = anon_cred;
+  XPROCESS (proc)->x509_cred = x509_cred;
+  XPROCESS (proc)->gnutls_cred_type = type;
+
+  GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_CRED_SET;
+
+  return gnutls_make_error (GNUTLS_E_SUCCESS);
+}
+
+DEFUN ("gnutls-bye", Fgnutls_bye,
+       Sgnutls_bye, 2, 2, 0,
+       doc: /* Terminate current GNU TLS connection for PROCESS.
+The connection should have been initiated using `gnutls-handshake'.
+
+If CONT is not nil the TLS connection gets terminated and further
+receives and sends will be disallowed. If the return value is zero you
+may continue using the connection.  If CONT is nil, GnuTLS actually
+sends an alert containing a close request and waits for the peer to
+reply with the same message.  In order to reuse the connection you
+should wait for an EOF from the peer.
+
+This function may also return `gnutls-e-again', or
+`gnutls-e-interrupted'.  */)
+    (Lisp_Object proc, Lisp_Object cont)
+{
+  gnutls_session_t state;
+  int ret;
+
+  CHECK_PROCESS (proc);
+
+  state = XPROCESS (proc)->gnutls_state;
+
+  ret = gnutls_bye (state,
+                    NILP (cont) ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR);
+
+  return gnutls_make_error (ret);
+}
+
+DEFUN ("gnutls-handshake", Fgnutls_handshake,
+       Sgnutls_handshake, 1, 1, 0,
+       doc: /* Perform GNU TLS handshake for PROCESS.
+The identity of the peer is checked automatically.  This function will
+fail if any problem is encountered, and will return a negative error
+code. In case of a client, if it has been asked to resume a session,
+but the server didn't, then a full handshake will be performed.
+
+If the error `gnutls-e-not-ready-for-handshake' is returned, you
+didn't call `gnutls-boot' first.
+
+This function may also return the non-fatal errors `gnutls-e-again',
+or `gnutls-e-interrupted'. In that case you may resume the handshake
+(by calling this function again).  */)
+    (Lisp_Object proc)
+{
+  gnutls_session_t state;
+  int ret;
+
+  CHECK_PROCESS (proc);
+  state = XPROCESS (proc)->gnutls_state;
+
+  if (GNUTLS_INITSTAGE (proc) < GNUTLS_STAGE_HANDSHAKE_CANDO)
+    return Qgnutls_e_not_ready_for_handshake;
+
+  /* for a network process in Emacs infd and outfd are the same
+     but this shows our intent more clearly.  */
+  gnutls_transport_set_ptr2 (state, XPROCESS (proc)->infd,
+                             XPROCESS (proc)->outfd);
+  ret = gnutls_handshake (state);
+
+  GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_HANDSHAKE_DONE;
+
+  if (GNUTLS_E_SUCCESS == ret)
+  {
+    /* here we're finally done.  */
+    GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_READY;
+  }
+
+  return gnutls_make_error (ret);
+}
+
+void
+syms_of_gnutls (void)
+{
+  global_initialized = 0;
+
+  Qgnutls_code = intern_c_string ("gnutls-code");
+  staticpro (&Qgnutls_code);
+
+  Qgnutls_anon = intern_c_string ("gnutls-anon");
+  staticpro (&Qgnutls_anon);
+
+  Qgnutls_x509pki = intern_c_string ("gnutls-x509pki");
+  staticpro (&Qgnutls_x509pki);
+
+  Qgnutls_e_interrupted = intern_c_string ("gnutls-e-interrupted");
+  staticpro (&Qgnutls_e_interrupted);
+  Fput (Qgnutls_e_interrupted, Qgnutls_code,
+        make_number (GNUTLS_E_INTERRUPTED));
+
+  Qgnutls_e_again = intern_c_string ("gnutls-e-again");
+  staticpro (&Qgnutls_e_again);
+  Fput (Qgnutls_e_again, Qgnutls_code,
+        make_number (GNUTLS_E_AGAIN));
+
+  Qgnutls_e_invalid_session = intern_c_string ("gnutls-e-invalid-session");
+  staticpro (&Qgnutls_e_invalid_session);
+  Fput (Qgnutls_e_invalid_session, Qgnutls_code,
+        make_number (GNUTLS_E_INVALID_SESSION));
+
+  Qgnutls_e_not_ready_for_handshake =
+    intern_c_string ("gnutls-e-not-ready-for-handshake");
+  staticpro (&Qgnutls_e_not_ready_for_handshake);
+  Fput (Qgnutls_e_not_ready_for_handshake, Qgnutls_code,
+        make_number (GNUTLS_E_APPLICATION_ERROR_MIN));
+
+  defsubr (&Sgnutls_get_initstage);
+  defsubr (&Sgnutls_errorp);
+  defsubr (&Sgnutls_error_fatalp);
+  defsubr (&Sgnutls_error_string);
+  defsubr (&Sgnutls_global_init);
+  defsubr (&Sgnutls_global_deinit);
+  defsubr (&Sgnutls_boot);
+  defsubr (&Sgnutls_deinit);
+  defsubr (&Sgnutls_handshake);
+  defsubr (&Sgnutls_bye);
+}
+#endif

=== added file 'src/gnutls.h'
--- src/gnutls.h	1970-01-01 00:00:00 +0000
+++ src/gnutls.h	2010-09-15 01:29:34 +0000
@@ -0,0 +1,57 @@
+/* GnuTLS glue for GNU Emacs.
+   Copyright (C) 2010  Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs 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 3 of the License, or
+(at your option) any later version.
+
+GNU Emacs 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef EMACS_GNUTLS_DEFINED
+#define EMACS_GNUTLS_DEFINED
+
+#ifdef HAVE_GNUTLS
+#include <gnutls/gnutls.h>
+
+typedef enum
+{
+  GNUTLS_STAGE_EMPTY = 0,
+  GNUTLS_STAGE_CRED_ALLOC,
+  GNUTLS_STAGE_FILES,
+  GNUTLS_STAGE_INIT,
+  GNUTLS_STAGE_PRIORITY,
+  GNUTLS_STAGE_CRED_SET,
+
+  GNUTLS_STAGE_HANDSHAKE_CANDO = GNUTLS_STAGE_CRED_SET,
+  GNUTLS_STAGE_HANDSHAKE_DONE,
+
+  GNUTLS_STAGE_READY,
+} gnutls_initstage_t;
+
+#define GNUTLS_EMACS_ERROR_INVALID_TYPE GNUTLS_E_APPLICATION_ERROR_MIN
+
+#define GNUTLS_INITSTAGE(proc) (XPROCESS (proc)->gnutls_initstage)
+
+#define GNUTLS_PROCESS_USABLE(proc) (GNUTLS_INITSTAGE(proc) >= GNUTLS_STAGE_READY)
+
+int
+emacs_gnutls_write (int fildes, gnutls_session_t state, char *buf,
+                    unsigned int nbyte);
+int
+emacs_gnutls_read (int fildes, gnutls_session_t state, char *buf,
+                   unsigned int nbyte);
+
+extern void syms_of_gnutls (void);
+
+#endif 
+
+#endif

=== modified file 'src/process.c'
--- src/process.c	2010-08-22 15:14:37 +0000
+++ src/process.c	2010-09-15 01:29:34 +0000
@@ -105,6 +105,9 @@
 #include "sysselect.h"
 #include "syssignal.h"
 #include "syswait.h"
+#ifdef HAVE_GNUTLS
+#include "gnutls.h"
+#endif
 
 #if defined (USE_GTK) || defined (HAVE_GCONF)
 #include "xgselect.h"
@@ -583,6 +586,10 @@
   p->read_output_skip = 0;
 #endif
 
+#ifdef HAVE_GNUTLS
+  p->gnutls_initstage = GNUTLS_STAGE_EMPTY;
+#endif
+
   /* If name is already in use, modify it until it is unused.  */
 
   name1 = name;
@@ -1526,6 +1533,12 @@
   XPROCESS (proc)->filter = Qnil;
   XPROCESS (proc)->command = Flist (nargs - 2, args + 2);
 
+#ifdef HAVE_GNUTLS
+  /* AKA GNUTLS_INITSTAGE(proc).  */
+  XPROCESS (proc)->gnutls_initstage = GNUTLS_STAGE_EMPTY;
+  XPROCESS (proc)->gnutls_cred_type = Qnil;
+#endif
+
 #ifdef ADAPTIVE_READ_BUFFERING
   XPROCESS (proc)->adaptive_read_buffering
     = (NILP (Vprocess_adaptive_read_buffering) ? 0
@@ -5097,7 +5110,13 @@
 #endif
   if (proc_buffered_char[channel] < 0)
     {
-      nbytes = emacs_read (channel, chars + carryover, readmax);
+#ifdef HAVE_GNUTLS
+      if (NETCONN_P(proc) && GNUTLS_PROCESS_USABLE (proc))
+	nbytes = emacs_gnutls_read (channel, XPROCESS (proc)->gnutls_state,
+                                    chars + carryover, readmax);
+      else
+#endif
+	nbytes = emacs_read (channel, chars + carryover, readmax);
 #ifdef ADAPTIVE_READ_BUFFERING
       if (nbytes > 0 && p->adaptive_read_buffering)
 	{
@@ -5130,7 +5149,13 @@
     {
       chars[carryover] = proc_buffered_char[channel];
       proc_buffered_char[channel] = -1;
-      nbytes = emacs_read (channel, chars + carryover + 1,  readmax - 1);
+#ifdef HAVE_GNUTLS
+      if (NETCONN_P(proc) && GNUTLS_PROCESS_USABLE (proc))
+	nbytes = emacs_gnutls_read (channel, XPROCESS (proc)->gnutls_state,
+                                    chars + carryover + 1, readmax - 1);
+      else
+#endif
+	nbytes = emacs_read (channel, chars + carryover + 1,  readmax - 1);
       if (nbytes < 0)
 	nbytes = 1;
       else
@@ -5540,7 +5565,14 @@
 	      else
 #endif
 		{
-		  rv = emacs_write (outfd, (char *) buf, this);
+#ifdef HAVE_GNUTLS
+		  if (NETCONN_P(proc) && GNUTLS_PROCESS_USABLE (proc))
+		    rv = emacs_gnutls_write (outfd,
+					     XPROCESS (proc)->gnutls_state, 
+					     (char *) buf, this);
+		  else
+#endif
+		    rv = emacs_write (outfd, (char *) buf, this);
 #ifdef ADAPTIVE_READ_BUFFERING
 		  if (p->read_output_delay > 0
 		      && p->adaptive_read_buffering == 1)

=== modified file 'src/process.h'
--- src/process.h	2010-08-11 12:34:46 +0000
+++ src/process.h	2010-09-15 01:29:34 +0000
@@ -24,6 +24,10 @@
 #include <unistd.h>
 #endif
 
+#ifdef HAVE_GNUTLS
+#include "gnutls.h"
+#endif
+
 /* This structure records information about a subprocess
    or network connection.
 
@@ -76,6 +80,10 @@
     /* Working buffer for encoding.  */
     Lisp_Object encoding_buf;
 
+#ifdef HAVE_GNUTLS
+    Lisp_Object gnutls_cred_type;
+#endif
+
     /* After this point, there are no Lisp_Objects any more.  */
     /* alloc.c assumes that `pid' is the first such non-Lisp slot.  */
 
@@ -121,6 +129,13 @@
        needs to be synced to `status'.  */
     unsigned int raw_status_new : 1;
     int raw_status;
+
+#ifdef HAVE_GNUTLS
+    gnutls_initstage_t gnutls_initstage;
+    gnutls_session_t gnutls_state;
+    gnutls_certificate_client_credentials x509_cred;
+    gnutls_anon_client_credentials_t anon_cred;
+#endif
 };
 
 /* Every field in the preceding structure except for the first two


[-- Attachment #3: Type: text/plain, Size: 146 bytes --]

_______________________________________________
Gnutls-devel mailing list
Gnutls-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/gnutls-devel

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-14 19:10                                         ` Lars Magne Ingebrigtsen
@ 2010-09-15 11:20                                           ` Ted Zlatanov
  0 siblings, 0 replies; 93+ messages in thread
From: Ted Zlatanov @ 2010-09-15 11:20 UTC (permalink / raw)
  To: emacs-devel; +Cc: gnutls-devel

On Tue, 14 Sep 2010 21:10:52 +0200 Lars Magne Ingebrigtsen <larsi@gnus.org> wrote: 

LMI> Nikos Mavrogiannopoulos <nmav@gnutls.org> writes:
>>> What ca.pem should I use?  There's one in GnuTLS and one in
>>> /etc/ssl/certs/ca.pem on my Ubuntu system.  It should Just Work so it
>>> may make sense to ship ca.pem with Emacs.  WDYT?
>> 
>> This is local policy, I don't think that it has to be shipped with
>> emacs. Just give the option of someone specifying it.

LMI> I don't know how tls stuff works at all, but if a certificate is needed
LMI> for basic usage, then it should be shipped with Emacs.

On my Ubuntu system I get 142 CA certificates out of
/etc/ssl/certs/ca-certificates.crt and one out of /etc/ssl/certs/ca.pem.
So the former seems like a better starting point IIUC.  It seems like
this should be part of the configure process: if GnuTLS is enabled, look
for a certificate bundle (allowing an override).  Then build a merged
bundle out of the local one plus whatever Emacs ships by default and
make that the default certificate bundle (the user can override that in
gnutls.el at runtime, of course).  See
http://lynx.isc.org/current/README.sslcerts for an example of how we
could explain this to the Emacs users.

Should Emacs blindly trust all the certificates in the local policy?

Ted




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-15 11:01                                     ` Ted Zlatanov
@ 2010-09-15 12:13                                       ` Nikos Mavrogiannopoulos
  2010-09-15 15:40                                         ` Ted Zlatanov
  2010-09-26  6:09                                         ` Ted Zlatanov
  2010-09-21 11:37                                       ` Simon Josefsson
  1 sibling, 2 replies; 93+ messages in thread
From: Nikos Mavrogiannopoulos @ 2010-09-15 12:13 UTC (permalink / raw)
  To: Ted Zlatanov; +Cc: gnutls-devel, emacs-devel

2010/9/15 Ted Zlatanov <tzz@lifelogs.com>:

> NM> I cannot look at the patch but the example you are looking for is:
> NM> http://www.gnu.org/software/gnutls/manual/html_node/Simple-client-example-with-X_002e509-certificate-support.html#Simple-client-example-with-X_002e509-certificate-support
> NM> to do the connection, and this one to verify the certificate:
> NM> http://www.gnu.org/software/gnutls/manual/html_node/Verifying-peer_0027s-certificate.html#Verifying-peer_0027s-certificate
> Thanks for your help.  I am still a little lost though :)
>
> Can you give a specific command line that would start gnutls-serv so the
> simple client (ex-client2.c) you reference will connect to it?  If
> that's not possible, is there a way to augment ex-client2.c so it
> connects to an invocation of gnutls-serv without building all the
> gnutls-cli (cli.c, etc.) infrastructure?

Use/check the gnutls-http-serv script in doc/credentials. It sets up a
server with a certificate, ready for testing. If the server doesn't
have a certificate it wouldn't be able to fully operate.

> NM> GNUTLS_E_AGAIN is returned only if the transport layer function
> NM> (recv/send) return -1 and EAGAIN. Usually this is normal behavior and is
> NM> enough to loop around them. Do you use non-blocking IO?
> Ah, thanks for the hint.  All the GnuTLS source code (e.g. the
> do_handshake() function in cli.c) keeps looping forever as long as
> GNUTLS_E_AGAIN is returned.  That seems dangerous regardless of the
> underlying mechanism because we don't want to lock up Emacs waiting for
> a connection, but OTOH there's no other way to know if the handshake is
> done.  I limited it to 25000 times (used to be 25) in my patch.  Is that
> a reasonable limit?  Should I base it on time elapsed?
> With a limit of 25K and by checking `gnutls-error-fatalp' which calls
> `gnutls_error_is_fatal', the handshake succeeds after 1250 tries against
> a remote SSL server.  So now against that server I get:

Maybe a time limit would be more reasonable, but it depends on the
context. Why would you use non-blocking IO in that case?

regards,
Nikos



^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-15 12:13                                       ` Nikos Mavrogiannopoulos
@ 2010-09-15 15:40                                         ` Ted Zlatanov
  2010-09-26  6:09                                         ` Ted Zlatanov
  1 sibling, 0 replies; 93+ messages in thread
From: Ted Zlatanov @ 2010-09-15 15:40 UTC (permalink / raw)
  To: emacs-devel; +Cc: gnutls-devel

On Wed, 15 Sep 2010 14:13:57 +0200 Nikos Mavrogiannopoulos <nmav@gnutls.org> wrote: 

NM> Use/check the gnutls-http-serv script in doc/credentials. It sets up a
NM> server with a certificate, ready for testing. If the server doesn't
NM> have a certificate it wouldn't be able to fully operate.

Thanks.  I get a bad TLS packet now, so investigating...

NM> Maybe a time limit would be more reasonable, but it depends on the
NM> context. Why would you use non-blocking IO in that case?

We want to avoid locking up Emacs, which is single-threaded.  So I kept
the handshake cycle at the ELisp level, which is much harder to lock up
(the user can abort a slow operation with `C-g').

Maybe we can use a `timeout' variable the user can set per process.  We
can assume they know if a server is slow or not.  Doing it by retry
count is almost definitely wrong.

Ted




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-15 11:01                                     ` Ted Zlatanov
  2010-09-15 12:13                                       ` Nikos Mavrogiannopoulos
@ 2010-09-21 11:37                                       ` Simon Josefsson
  2010-09-26  6:12                                         ` Ted Zlatanov
  1 sibling, 1 reply; 93+ messages in thread
From: Simon Josefsson @ 2010-09-21 11:37 UTC (permalink / raw)
  To: Ted Zlatanov; +Cc: gnutls-devel, emacs-devel

Ted Zlatanov <tzz@lifelogs.com> writes:

> +(defconst gnutls-version "0.3.1")

This should be removed.  If the GnuTLS version is at all interesting for
elisp callers, there could be an elisp function gnutls-check-version
that in C calls gnutls_check_version.

> +(defun open-ssl-stream (name buffer host service)
> +  "Open a SSL connection for a service to a host.

I suggest using 'TLS' or possibly 'SSL/TLS' consistently in
documentation.  Is 'open-ssl-stream' for backwards compatibility?
Otherwise I suggest 'open-tls-stream'.

> +
> +;; (open-ssl-stream "tls" "tls-buffer" "yourserver.com" "https")

Looks like debug code that should be removed?

> +(defun starttls-negotiate (proc &optional priority-string
> +                                credentials credentials-file)
> +  "Negotiate a SSL or TLS connection.

Here I suggest 'TLS' or 'SSL/TLS' instead.

> +PRIORITY-STRING is as per the GnuTLS docs.

Maybe there could be an info hyperlink here?

> +                               "/tmp/ca.pem"

This should be fixed, naturally.
> +
> +         (priority-string (or priority-string
> +                              (cond
> +                               ((eq credentials 'gnutls-anon)
> +                                "PERFORMANCE:+ANON-DH:!ARCFOUR-128")
> +                               ((eq credentials 'gnutls-x509pki)
> +                                "PERFORMANCE"))))

I think NORMAL should be used instead of PERFORMANCE here.

> +    (gnutls-message-maybe
> +     (setq ret (gnutls-boot proc priority-string credentials credentials-file))
> +     "boot: %s")

How much debug code do we want to retain?  I'm not sure.

> +(defun starttls-open-stream (name buffer host service)
> +  "Open a TLS connection for a service to a host.

'TLS' or 'SSL/TLS' again.

> +DEFUN ("gnutls-global-init", Fgnutls_global_init,
> +       Sgnutls_global_init, 0, 0, 0,
> +       doc: /* Initializes global GNU TLS state to defaults.
> +Call `gnutls-global-deinit' when GNU TLS usage is no longer needed.
> +Returns zero on success.  */)
...
> +DEFUN ("gnutls-global-deinit", Fgnutls_global_deinit,
> +       Sgnutls_global_deinit, 0, 0, 0,
> +       doc: /* Deinitializes global GNU TLS state.
> +See also `gnutls-global-init'.  */)

I think this shouldn't be exposed to Elisp, Emacs startup code could
initialize GnuTLS directly.

> +DEFUN ("gnutls-boot", Fgnutls_boot, Sgnutls_boot, 3, 6, 0,
> +       doc: /* Initializes client-mode GnuTLS for process PROC.
> +Currently only client mode is supported.  Returns a success/failure
> +value you can check with `gnutls-errorp'.
> +
> +PRIORITY_STRING is a string describing the priority.
> +TYPE is either `gnutls-anon' or `gnutls-x509pki'.
> +TRUSTFILE is a PEM encoded trust file for `gnutls-x509pki'.
> +KEYFILE is ... for `gnutls-x509pki' (TODO).
> +CALLBACK is ... for `gnutls-x509pki' (TODO).

Two comments here: 1) The name is a bit generic..?  2) The design makes
it a bit difficult to support multiple credentials.  The GnuTLS API
allows clients to have several credentials (X.509, OpenPGP, etc).
Perhaps copying the GnuTLS API further is more flexible.

Good work.  I think you are getting there!

/Simon

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-15 12:13                                       ` Nikos Mavrogiannopoulos
  2010-09-15 15:40                                         ` Ted Zlatanov
@ 2010-09-26  6:09                                         ` Ted Zlatanov
  2010-09-26 15:32                                           ` Lars Magne Ingebrigtsen
  2010-09-26 21:50                                           ` James Cloos
  1 sibling, 2 replies; 93+ messages in thread
From: Ted Zlatanov @ 2010-09-26  6:09 UTC (permalink / raw)
  To: emacs-devel; +Cc: gnutls-devel

On Wed, 15 Sep 2010 14:13:57 +0200 Nikos Mavrogiannopoulos <nmav@gnutls.org> wrote: 

NM> Use/check the gnutls-http-serv script in doc/credentials. It sets up a
NM> server with a certificate, ready for testing. If the server doesn't
NM> have a certificate it wouldn't be able to fully operate.

OK, this server works with ex-client2 and with a regular web browser
like w3m, but not with Emacs.  The only difference between ex-client2
and my code AFAICT is that it specifies the trust file as "ca.pem" and
then calls `gnutls_certificate_set_x509_trust_file' with that missing
file without checking the return code.  I tried that and it didn't make
a difference.  I keep getting error GNUTLS_E_UNEXPECTED_PACKET_LENGTH
after a bunch of handshakes.

I've gone over my code carefully and just can't figure out what's
different.  I'm sure it's something simple I've overlooked.  So I
checked my changes into the Emacs repo in order to have other, more
expert developers take a look.  All the tedious work is done; the files
of interest are src/process.[ch] (where the process is set up with the
GnuTLS members), src/gnutls.[ch], and lisp/net/gnutls.el.

Here's the recipe to see the problem:

1) compile Emacs with

./configure --with-gnutls; make bootstrap

2) run it directly:

cd src
gdb --args ./emacs ../lisp/net/gnutls.el

3) when it loads, do:

(you'll also need the gnutls-http-serv running locally)

M-x eval-buffer
M-: (open-ssl-stream "tls" "tls-buffer" "localhost" 5556)

4) look in *Messages* for the errors:

gnutls: allocating credentials
gnutls: allocating x509 credentials
gnutls: setting the trustfile
gnutls: processed 142 CA certificates
gnutls: setting the keyfile
gnutls: gnutls_init
gnutls: setting the priority string
gnutls: setting the credentials
gnutls: setting the x509 credentials
gnutls: handshake: setting the transport pointers to 8/8
gnutls: handshake: handshaking
gnutls.el: (err=[gnutls-e-again] Resource temporarily unavailable, try again.) handshake: nil
gnutls: handshake: handshaking
... repeated a LOT ...
gnutls.el: (err=[gnutls-e-again] Resource temporarily unavailable, try again.) handshake: nil
gnutls: handshake: handshaking [2 times]
gnutls.el: (err=[gnutls-e-again] Resource temporarily unavailable, try again.) handshake: nil
gnutls: handshake: handshaking
gnutls.el: (err=[-9] A TLS packet with unexpected length was received.) handshake: nil
Ouch, error return -9 (A TLS packet with unexpected length was received.)
nil
Mark set [2 times]


Ted




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-21 11:37                                       ` Simon Josefsson
@ 2010-09-26  6:12                                         ` Ted Zlatanov
  2010-09-30 10:10                                           ` Simon Josefsson
  0 siblings, 1 reply; 93+ messages in thread
From: Ted Zlatanov @ 2010-09-26  6:12 UTC (permalink / raw)
  To: gnutls-devel; +Cc: emacs-devel

On Tue, 21 Sep 2010 13:37:42 +0200 Simon Josefsson <simon@josefsson.org> wrote: 

SJ> Ted Zlatanov <tzz@lifelogs.com> writes:
>> +(defconst gnutls-version "0.3.1")
>> +                               "/tmp/ca.pem"

SJ> This should be removed.

Done.

>> +         (priority-string (or priority-string
>> +                              (cond
>> +                               ((eq credentials 'gnutls-anon)
>> +                                "PERFORMANCE:+ANON-DH:!ARCFOUR-128")
>> +                               ((eq credentials 'gnutls-x509pki)
>> +                                "PERFORMANCE"))))

SJ> I think NORMAL should be used instead of PERFORMANCE here.

Done.

>> +(defun open-ssl-stream (name buffer host service)
>> +  "Open a SSL connection for a service to a host.

SJ> I suggest using 'TLS' or possibly 'SSL/TLS' consistently in
SJ> documentation.  

OK, but let's get the code working first.

SJ> Is 'open-ssl-stream' for backwards compatibility?  Otherwise I
SJ> suggest 'open-tls-stream'.

Yes, it's trying to be compatible.  I'd rather get rid of the
compatibility but we'll see.

>> +;; (open-ssl-stream "tls" "tls-buffer" "yourserver.com" "https")

SJ> Looks like debug code that should be removed?

Please let it be for now.  It's useful for quick testing.

>> +PRIORITY-STRING is as per the GnuTLS docs.

SJ> Maybe there could be an info hyperlink here?

Sorry, you mean to the GnuTLS webserver?  I don't know if that's
necessary.

>> +    (gnutls-message-maybe
>> +     (setq ret (gnutls-boot proc priority-string credentials credentials-file))
>> +     "boot: %s")

SJ> How much debug code do we want to retain?  I'm not sure.

For now, as much as possible.  We can always turn it down later.

>> +DEFUN ("gnutls-global-init", Fgnutls_global_init,
>> +       Sgnutls_global_init, 0, 0, 0,
>> +       doc: /* Initializes global GNU TLS state to defaults.
>> +Call `gnutls-global-deinit' when GNU TLS usage is no longer needed.
>> +Returns zero on success.  */)
SJ> ...
>> +DEFUN ("gnutls-global-deinit", Fgnutls_global_deinit,
>> +       Sgnutls_global_deinit, 0, 0, 0,
>> +       doc: /* Deinitializes global GNU TLS state.
>> +See also `gnutls-global-init'.  */)

SJ> I think this shouldn't be exposed to Elisp, Emacs startup code could
SJ> initialize GnuTLS directly.

OK, done.

>> +DEFUN ("gnutls-boot", Fgnutls_boot, Sgnutls_boot, 3, 6, 0,
>> +       doc: /* Initializes client-mode GnuTLS for process PROC.
>> +Currently only client mode is supported.  Returns a success/failure
>> +value you can check with `gnutls-errorp'.
>> +
>> +PRIORITY_STRING is a string describing the priority.
>> +TYPE is either `gnutls-anon' or `gnutls-x509pki'.
>> +TRUSTFILE is a PEM encoded trust file for `gnutls-x509pki'.
>> +KEYFILE is ... for `gnutls-x509pki' (TODO).
>> +CALLBACK is ... for `gnutls-x509pki' (TODO).

SJ> Two comments here: 1) The name is a bit generic..?

Well, "init" is taken and I have a small vocabulary :)

SJ> 2) The design makes it a bit difficult to support multiple
SJ> credentials.  The GnuTLS API allows clients to have several
SJ> credentials (X.509, OpenPGP, etc).  Perhaps copying the GnuTLS API
SJ> further is more flexible.

I thought of making it more flexible but I really want to get the basic
case working.  As I mentioned earlier I think GnuTLS should consider
further extending the idea of priority strings to a full configuration
(credentials especially) in a single string or file.  That would make
using it so much easier from Emacs Lisp.

I tried to figure out the TLS handshake problem but it has stumped me.
It's taken me many hours and I still don't know what I'm missing so, as
I mentioned in my other message, I've checked in my current state to let
others take a look.  If you or other GnuTLS developers can help, it
would be greatly appreciated.  Once the handshake works I will work on
the other improvements you mentioned and on getting the GnuTLS support
into Gnus and other parts of Emacs.

Thanks
Ted

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-26  6:09                                         ` Ted Zlatanov
@ 2010-09-26 15:32                                           ` Lars Magne Ingebrigtsen
  2010-09-26 21:50                                           ` James Cloos
  1 sibling, 0 replies; 93+ messages in thread
From: Lars Magne Ingebrigtsen @ 2010-09-26 15:32 UTC (permalink / raw)
  To: emacs-devel; +Cc: gnutls-devel

Ted Zlatanov <tzz@lifelogs.com> writes:

> gnutls: handshake: handshaking
> gnutls.el: (err=[-9] A TLS packet with unexpected length was received.) handshake: nil
> Ouch, error return -9 (A TLS packet with unexpected length was received.)
> nil
> Mark set [2 times]

(open-ssl-stream "tls" "tls-buffer" "imap.gmail.com" "imaps")

Yes, I'm getting the same:

gnutls.el: (err=[gnutls-e-again] Resource temporarily unavailable, try again.) handshake: nil
gnutls: handshake: handshaking [2 times]
gnutls.el: (err=[-15] An unexpected TLS packet was received.) handshake: nil
Ouch, error return -15 (An unexpected TLS packet was received.)


-- 
(domestic pets only, the antidote for overdose, milk.)
  larsi@gnus.org * Lars Magne Ingebrigtsen




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-26  6:09                                         ` Ted Zlatanov
  2010-09-26 15:32                                           ` Lars Magne Ingebrigtsen
@ 2010-09-26 21:50                                           ` James Cloos
  2010-09-27 13:37                                             ` Lars Magne Ingebrigtsen
  2010-09-27 14:36                                             ` Emacs core TLS support Ted Zlatanov
  1 sibling, 2 replies; 93+ messages in thread
From: James Cloos @ 2010-09-26 21:50 UTC (permalink / raw)
  To: Ted Zlatanov; +Cc: gnutls-devel, emacs-devel

>>>>> "TZ" == Ted Zlatanov <tzz@lifelogs.com> writes:

TZ> I've gone over my code carefully and just can't figure out what's
TZ> different.  I'm sure it's something simple I've overlooked.

It probably would help to get a full packet trace of the failed
handshake and look at it in wireshark.

-JimC
-- 
James Cloos <cloos@jhcloos.com>         OpenPGP: 1024D/ED7DAEA6



^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-26 21:50                                           ` James Cloos
@ 2010-09-27 13:37                                             ` Lars Magne Ingebrigtsen
  2010-09-27 13:56                                               ` Lars Magne Ingebrigtsen
  2010-09-27 14:36                                             ` Emacs core TLS support Ted Zlatanov
  1 sibling, 1 reply; 93+ messages in thread
From: Lars Magne Ingebrigtsen @ 2010-09-27 13:37 UTC (permalink / raw)
  To: emacs-devel; +Cc: gnutls-devel

[-- Attachment #1: Type: text/plain, Size: 196 bytes --]

I put

  gnutls_global_set_log_level(9);

into the boot function, and it's definitely doing...  something.

I get the following.  It looks like a certificate to me.  But it's very
binarish.  :-)


[-- Attachment #2: google --]
[-- Type: application/octet-stream, Size: 1750 bytes --]

[-- Attachment #3: Type: text/plain, Size: 161 bytes --]


I had expected the debugging info to be more...  better.

-- 
(domestic pets only, the antidote for overdose, milk.)
  larsi@gnus.org * Lars Magne Ingebrigtsen

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-27 13:37                                             ` Lars Magne Ingebrigtsen
@ 2010-09-27 13:56                                               ` Lars Magne Ingebrigtsen
  2010-09-27 14:03                                                 ` Lars Magne Ingebrigtsen
                                                                   ` (3 more replies)
  0 siblings, 4 replies; 93+ messages in thread
From: Lars Magne Ingebrigtsen @ 2010-09-27 13:56 UTC (permalink / raw)
  To: emacs-devel; +Cc: gnutls-devel

Ok, now we're getting somewhere.

With the following dirty patch:

=== modified file 'src/gnutls.c'
*** src/gnutls.c	2010-09-26 06:06:28 +0000
--- src/gnutls.c	2010-09-27 13:52:46 +0000
***************
*** 221,226 ****
--- 221,230 ----
    return gnutls_make_error (GNUTLS_E_SUCCESS);
  }
  
+ void my_log_function (int level, const char* string) {
+   message("hello: %d %s", strlen(string), string);
+ }
+ 
  DEFUN ("gnutls-boot", Fgnutls_boot, Sgnutls_boot, 3, 6, 0,
         doc: /* Initializes client-mode GnuTLS for process PROC.
  Currently only client mode is supported.  Returns a success/failure
***************
*** 264,269 ****
--- 268,276 ----
  
    state = XPROCESS (proc)->gnutls_state;
  
+   gnutls_global_set_log_level(9);
+   gnutls_global_set_log_function(my_log_function);
+   
    /* always initialize globals.  */
    global_init = gnutls_emacs_global_init ();
    if (! NILP (Fgnutls_errorp (global_init)))


I get the following output (after a lot of other output):

gnutls: handshake: handshaking
hello: 73 REC[0x16bbe20]: Expected Packet[3] Change Cipher Spec(20) with length: 1

hello: 73 REC[0x16bbe20]: Received Packet[3] Change Cipher Spec(20) with length: 1

hello: 28 ASSERT: gnutls_cipher.c:204

hello: 53 REC[0x16bbe20]: ChangeCipherSpec Packet was received

hello: 46 HSK[0x16bbe20]: Cipher Suite: RSA_ARCFOUR_MD5

hello: 61 HSK[0x16bbe20]: Initializing internal [read] cipher sessions

hello: 64 REC[0x16bbe20]: Expected Packet[0] Handshake(22) with length: 1

hello: 65 REC[0x16bbe20]: Received Packet[0] Handshake(22) with length: 32

hello: 66 REC[0x16bbe20]: Decrypted Packet[0] Handshake(22) with length: 16

hello: 49 HSK[0x16bbe20]: FINISHED was received [16 bytes]

gnutls: handshake: handshaking
hello: 62 HSK[0x16bbe20]: Keeping ciphersuite: DHE_RSA_AES_128_CBC_SHA1

hello: 67 HSK[0x16bbe20]: Keeping ciphersuite: DHE_RSA_CAMELLIA_128_CBC_SHA1

hello: 62 HSK[0x16bbe20]: Keeping ciphersuite: DHE_RSA_AES_256_CBC_SHA1

hello: 67 HSK[0x16bbe20]: Keeping ciphersuite: DHE_RSA_CAMELLIA_256_CBC_SHA1

hello: 63 HSK[0x16bbe20]: Keeping ciphersuite: DHE_RSA_3DES_EDE_CBC_SHA1

hello: 62 HSK[0x16bbe20]: Keeping ciphersuite: DHE_DSS_AES_128_CBC_SHA1

hello: 67 HSK[0x16bbe20]: Keeping ciphersuite: DHE_DSS_CAMELLIA_128_CBC_SHA1

hello: 62 HSK[0x16bbe20]: Keeping ciphersuite: DHE_DSS_AES_256_CBC_SHA1

hello: 67 HSK[0x16bbe20]: Keeping ciphersuite: DHE_DSS_CAMELLIA_256_CBC_SHA1

hello: 63 HSK[0x16bbe20]: Keeping ciphersuite: DHE_DSS_3DES_EDE_CBC_SHA1

hello: 58 HSK[0x16bbe20]: Keeping ciphersuite: DHE_DSS_ARCFOUR_SHA1

hello: 67 HSK[0x16bbe20]: Removing ciphersuite: DHE_PSK_SHA_AES_128_CBC_SHA1

hello: 67 HSK[0x16bbe20]: Removing ciphersuite: DHE_PSK_SHA_AES_256_CBC_SHA1

hello: 68 HSK[0x16bbe20]: Removing ciphersuite: DHE_PSK_SHA_3DES_EDE_CBC_SHA1

hello: 63 HSK[0x16bbe20]: Removing ciphersuite: DHE_PSK_SHA_ARCFOUR_SHA1

hello: 67 HSK[0x16bbe20]: Removing ciphersuite: SRP_SHA_RSA_AES_128_CBC_SHA1

hello: 67 HSK[0x16bbe20]: Removing ciphersuite: SRP_SHA_RSA_AES_256_CBC_SHA1

hello: 68 HSK[0x16bbe20]: Removing ciphersuite: SRP_SHA_RSA_3DES_EDE_CBC_SHA1

hello: 67 HSK[0x16bbe20]: Removing ciphersuite: SRP_SHA_DSS_AES_128_CBC_SHA1

hello: 67 HSK[0x16bbe20]: Removing ciphersuite: SRP_SHA_DSS_AES_256_CBC_SHA1

hello: 68 HSK[0x16bbe20]: Removing ciphersuite: SRP_SHA_DSS_3DES_EDE_CBC_SHA1

hello: 58 HSK[0x16bbe20]: Keeping ciphersuite: RSA_AES_128_CBC_SHA1

hello: 63 HSK[0x16bbe20]: Keeping ciphersuite: RSA_CAMELLIA_128_CBC_SHA1

hello: 58 HSK[0x16bbe20]: Keeping ciphersuite: RSA_AES_256_CBC_SHA1

hello: 63 HSK[0x16bbe20]: Keeping ciphersuite: RSA_CAMELLIA_256_CBC_SHA1

hello: 59 HSK[0x16bbe20]: Keeping ciphersuite: RSA_3DES_EDE_CBC_SHA1

hello: 54 HSK[0x16bbe20]: Keeping ciphersuite: RSA_ARCFOUR_SHA1

hello: 53 HSK[0x16bbe20]: Keeping ciphersuite: RSA_ARCFOUR_MD5

hello: 63 HSK[0x16bbe20]: Removing ciphersuite: PSK_SHA_AES_128_CBC_SHA1

hello: 63 HSK[0x16bbe20]: Removing ciphersuite: PSK_SHA_AES_256_CBC_SHA1

hello: 64 HSK[0x16bbe20]: Removing ciphersuite: PSK_SHA_3DES_EDE_CBC_SHA1

hello: 59 HSK[0x16bbe20]: Removing ciphersuite: PSK_SHA_ARCFOUR_SHA1

hello: 63 HSK[0x16bbe20]: Removing ciphersuite: SRP_SHA_AES_128_CBC_SHA1

hello: 63 HSK[0x16bbe20]: Removing ciphersuite: SRP_SHA_AES_256_CBC_SHA1

hello: 64 HSK[0x16bbe20]: Removing ciphersuite: SRP_SHA_3DES_EDE_CBC_SHA1

hello: 44 EXT[0x16bbe20]: Sending extension CERT_TYPE

hello: 49 HSK[0x16bbe20]: CLIENT HELLO was send [88 bytes]

hello: 64 REC[0x16bbe20]: Sending Packet[1] Handshake(22) with length: 88

hello: 62 REC[0x16bbe20]: Sent Packet[2] Handshake(22) with length: 109

hello: 64 REC[0x16bbe20]: Expected Packet[1] Handshake(22) with length: 1

hello: 72 REC[0x16bbe20]: Received Packet[1] Application Data(23) with length: 84

hello: 73 REC[0x16bbe20]: Decrypted Packet[1] Application Data(23) with length: 68

hello: 28 ASSERT: gnutls_record.c:735

hello: 29 ASSERT: gnutls_record.c:1048

hello: 30 ASSERT: gnutls_buffers.c:1032

hello: 32 ASSERT: gnutls_handshake.c:1045

hello: 32 ASSERT: gnutls_handshake.c:2364



I have no idea what this means, though.  :-)


-- 
(domestic pets only, the antidote for overdose, milk.)
  larsi@gnus.org * Lars Magne Ingebrigtsen




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-27 13:56                                               ` Lars Magne Ingebrigtsen
@ 2010-09-27 14:03                                                 ` Lars Magne Ingebrigtsen
  2010-09-27 14:11                                                 ` Lars Magne Ingebrigtsen
                                                                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 93+ messages in thread
From: Lars Magne Ingebrigtsen @ 2010-09-27 14:03 UTC (permalink / raw)
  To: emacs-devel; +Cc: gnutls-devel

Lars Magne Ingebrigtsen <larsi@gnus.org> writes:

> hello: 64 HSK[0x16bbe20]: Removing ciphersuite: SRP_SHA_3DES_EDE_CBC_SHA1
>
> hello: 44 EXT[0x16bbe20]: Sending extension CERT_TYPE
>
> hello: 49 HSK[0x16bbe20]: CLIENT HELLO was send [88 bytes]
>
> hello: 64 REC[0x16bbe20]: Sending Packet[1] Handshake(22) with length: 88
>
> hello: 62 REC[0x16bbe20]: Sent Packet[2] Handshake(22) with length: 109
>
> hello: 64 REC[0x16bbe20]: Expected Packet[1] Handshake(22) with length: 1
>
> hello: 72 REC[0x16bbe20]: Received Packet[1] Application Data(23) with length: 84
>
> hello: 73 REC[0x16bbe20]: Decrypted Packet[1] Application Data(23) with length: 68

I've tried a few servers, and this is always how it ends.  It expects a
handshake after HELLO, but gets application data back.

-- 
(domestic pets only, the antidote for overdose, milk.)
  larsi@gnus.org * Lars Magne Ingebrigtsen




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-27 13:56                                               ` Lars Magne Ingebrigtsen
  2010-09-27 14:03                                                 ` Lars Magne Ingebrigtsen
@ 2010-09-27 14:11                                                 ` Lars Magne Ingebrigtsen
  2010-09-27 14:21                                                 ` Lars Magne Ingebrigtsen
  2010-09-27 14:42                                                 ` Ted Zlatanov
  3 siblings, 0 replies; 93+ messages in thread
From: Lars Magne Ingebrigtsen @ 2010-09-27 14:11 UTC (permalink / raw)
  To: emacs-devel; +Cc: gnutls-devel

Here's the entire trace from the connection:

HSK[0x1f927e0]: Keeping ciphersuite: DHE_RSA_AES_128_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: DHE_RSA_CAMELLIA_128_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: DHE_RSA_AES_256_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: DHE_RSA_CAMELLIA_256_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: DHE_RSA_3DES_EDE_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: DHE_DSS_AES_128_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: DHE_DSS_CAMELLIA_128_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: DHE_DSS_AES_256_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: DHE_DSS_CAMELLIA_256_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: DHE_DSS_3DES_EDE_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: DHE_DSS_ARCFOUR_SHA1
HSK[0x1f927e0]: Removing ciphersuite: DHE_PSK_SHA_AES_128_CBC_SHA1
HSK[0x1f927e0]: Removing ciphersuite: DHE_PSK_SHA_AES_256_CBC_SHA1
HSK[0x1f927e0]: Removing ciphersuite: DHE_PSK_SHA_3DES_EDE_CBC_SHA1
HSK[0x1f927e0]: Removing ciphersuite: DHE_PSK_SHA_ARCFOUR_SHA1
HSK[0x1f927e0]: Removing ciphersuite: SRP_SHA_RSA_AES_128_CBC_SHA1
HSK[0x1f927e0]: Removing ciphersuite: SRP_SHA_RSA_AES_256_CBC_SHA1
HSK[0x1f927e0]: Removing ciphersuite: SRP_SHA_RSA_3DES_EDE_CBC_SHA1
HSK[0x1f927e0]: Removing ciphersuite: SRP_SHA_DSS_AES_128_CBC_SHA1
HSK[0x1f927e0]: Removing ciphersuite: SRP_SHA_DSS_AES_256_CBC_SHA1
HSK[0x1f927e0]: Removing ciphersuite: SRP_SHA_DSS_3DES_EDE_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: RSA_AES_128_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: RSA_CAMELLIA_128_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: RSA_AES_256_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: RSA_CAMELLIA_256_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: RSA_3DES_EDE_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: RSA_ARCFOUR_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: RSA_ARCFOUR_MD5
HSK[0x1f927e0]: Removing ciphersuite: PSK_SHA_AES_128_CBC_SHA1
HSK[0x1f927e0]: Removing ciphersuite: PSK_SHA_AES_256_CBC_SHA1
HSK[0x1f927e0]: Removing ciphersuite: PSK_SHA_3DES_EDE_CBC_SHA1
HSK[0x1f927e0]: Removing ciphersuite: PSK_SHA_ARCFOUR_SHA1
HSK[0x1f927e0]: Removing ciphersuite: SRP_SHA_AES_128_CBC_SHA1
HSK[0x1f927e0]: Removing ciphersuite: SRP_SHA_AES_256_CBC_SHA1
HSK[0x1f927e0]: Removing ciphersuite: SRP_SHA_3DES_EDE_CBC_SHA1
EXT[0x1f927e0]: Sending extension CERT_TYPE
HSK[0x1f927e0]: CLIENT HELLO was send [88 bytes]
REC[0x1f927e0]: Sending Packet[0] Handshake(22) with length: 88
ASSERT: gnutls_cipher.c:204
REC[0x1f927e0]: Sent Packet[1] Handshake(22) with length: 93
REC[0x1f927e0]: Expected Packet[0] Handshake(22) with length: 1
REC[0x1f927e0]: Received Packet[0] Handshake(22) with length: 74
ASSERT: gnutls_cipher.c:204
REC[0x1f927e0]: Decrypted Packet[0] Handshake(22) with length: 74
HSK[0x1f927e0]: SERVER HELLO was received [74 bytes]
HSK[0x1f927e0]: Server's version: 3.1
HSK[0x1f927e0]: SessionID length: 32
HSK[0x1f927e0]: SessionID: f61b04980923171cfe2002e2a955cc198d4910ba1e4ebacbfc69840d8c4a9117
HSK[0x1f927e0]: Selected cipher suite: DHE_RSA_AES_128_CBC_SHA1
ASSERT: gnutls_extensions.c:124
REC[0x1f927e0]: Expected Packet[1] Handshake(22) with length: 1
REC[0x1f927e0]: Received Packet[1] Handshake(22) with length: 822
ASSERT: gnutls_cipher.c:204
REC[0x1f927e0]: Decrypted Packet[1] Handshake(22) with length: 822
HSK[0x1f927e0]: CERTIFICATE was received [822 bytes]
REC[0x1f927e0]: Expected Packet[2] Handshake(22) with length: 1
REC[0x1f927e0]: Received Packet[2] Handshake(22) with length: 397
ASSERT: gnutls_cipher.c:204
REC[0x1f927e0]: Decrypted Packet[2] Handshake(22) with length: 397
HSK[0x1f927e0]: SERVER KEY EXCHANGE was received [397 bytes]
REC[0x1f927e0]: Expected Packet[3] Handshake(22) with length: 1
REC[0x1f927e0]: Received Packet[3] Handshake(22) with length: 4
ASSERT: gnutls_cipher.c:204
REC[0x1f927e0]: Decrypted Packet[3] Handshake(22) with length: 4
HSK[0x1f927e0]: SERVER HELLO DONE was received [4 bytes]
ASSERT: gnutls_handshake.c:1123
HSK[0x1f927e0]: CLIENT KEY EXCHANGE was send [134 bytes]
REC[0x1f927e0]: Sending Packet[1] Handshake(22) with length: 134
ASSERT: gnutls_cipher.c:204
REC[0x1f927e0]: Sent Packet[2] Handshake(22) with length: 139
REC[0x1f927e0]: Sent ChangeCipherSpec
REC[0x1f927e0]: Sending Packet[2] Change Cipher Spec(20) with length: 1
ASSERT: gnutls_cipher.c:204
REC[0x1f927e0]: Sent Packet[3] Change Cipher Spec(20) with length: 6
 INT: PREMASTER SECRET[128]: b6e5db84294a9a5baaee9bef86ffef5291ddf3c05f89499a8886daf08efa56375c51b18d8d77d0f2eec4c15f45dfefb4c5e0f889f7b657335ac597d38250eda9a2aba41f308679516096b2e66123e6d88ba404f3ce2ffc661fecce32375492c2a40901f395b3589c4bbae52eb6c5c7c760d70b7709baffb937ee1873af205cbc
INT: CLIENT RANDOM[32]: 4ca0a5bee2a9c7b97625a749ccc5517991d2aab2e2453a3e0c4f32276c35fcc0
INT: SERVER RANDOM[32]: 4ca0a5bef00fb375c5e1ecc418f64566f621c6dd620161c146650ef50ad9c2ac
 INT: MASTER SECRET: 408e7621cb6a64815e6c24443d253f1449c74d48eb8be7a24bebe90a886aa1eab4683a3c91123d2ea02c0a8076914503
INT: KEY BLOCK[104]: 7696db01048a00a561eb42326691f07edaa83e3a8b4aee76e0d8aaacd568dcc2
INT: CLIENT WRITE KEY [16]: d8f1e68d677bfea28200e5c6b491f710
INT: SERVER WRITE KEY [16]: 9740dbee6da2a243eb7d35e856c4fa93
HSK[0x1f927e0]: Cipher Suite: DHE_RSA_AES_128_CBC_SHA1
HSK[0x1f927e0]: Initializing internal [write] cipher sessions
HSK[0x1f927e0]: FINISHED was send [16 bytes]
REC[0x1f927e0]: Sending Packet[0] Handshake(22) with length: 16
REC[0x1f927e0]: Sent Packet[1] Handshake(22) with length: 277
REC[0x1f927e0]: Expected Packet[4] Change Cipher Spec(20) with length: 1
REC[0x1f927e0]: Received Packet[4] Change Cipher Spec(20) with length: 1
ASSERT: gnutls_cipher.c:204
REC[0x1f927e0]: ChangeCipherSpec Packet was received
HSK[0x1f927e0]: Cipher Suite: DHE_RSA_AES_128_CBC_SHA1
HSK[0x1f927e0]: Initializing internal [read] cipher sessions
REC[0x1f927e0]: Expected Packet[0] Handshake(22) with length: 1
REC[0x1f927e0]: Received Packet[0] Handshake(22) with length: 48
REC[0x1f927e0]: Decrypted Packet[0] Handshake(22) with length: 16
HSK[0x1f927e0]: FINISHED was received [16 bytes]
HSK[0x1f927e0]: Keeping ciphersuite: DHE_RSA_AES_128_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: DHE_RSA_CAMELLIA_128_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: DHE_RSA_AES_256_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: DHE_RSA_CAMELLIA_256_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: DHE_RSA_3DES_EDE_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: DHE_DSS_AES_128_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: DHE_DSS_CAMELLIA_128_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: DHE_DSS_AES_256_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: DHE_DSS_CAMELLIA_256_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: DHE_DSS_3DES_EDE_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: DHE_DSS_ARCFOUR_SHA1
HSK[0x1f927e0]: Removing ciphersuite: DHE_PSK_SHA_AES_128_CBC_SHA1
HSK[0x1f927e0]: Removing ciphersuite: DHE_PSK_SHA_AES_256_CBC_SHA1
HSK[0x1f927e0]: Removing ciphersuite: DHE_PSK_SHA_3DES_EDE_CBC_SHA1
HSK[0x1f927e0]: Removing ciphersuite: DHE_PSK_SHA_ARCFOUR_SHA1
HSK[0x1f927e0]: Removing ciphersuite: SRP_SHA_RSA_AES_128_CBC_SHA1
HSK[0x1f927e0]: Removing ciphersuite: SRP_SHA_RSA_AES_256_CBC_SHA1
HSK[0x1f927e0]: Removing ciphersuite: SRP_SHA_RSA_3DES_EDE_CBC_SHA1
HSK[0x1f927e0]: Removing ciphersuite: SRP_SHA_DSS_AES_128_CBC_SHA1
HSK[0x1f927e0]: Removing ciphersuite: SRP_SHA_DSS_AES_256_CBC_SHA1
HSK[0x1f927e0]: Removing ciphersuite: SRP_SHA_DSS_3DES_EDE_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: RSA_AES_128_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: RSA_CAMELLIA_128_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: RSA_AES_256_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: RSA_CAMELLIA_256_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: RSA_3DES_EDE_CBC_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: RSA_ARCFOUR_SHA1
HSK[0x1f927e0]: Keeping ciphersuite: RSA_ARCFOUR_MD5
HSK[0x1f927e0]: Removing ciphersuite: PSK_SHA_AES_128_CBC_SHA1
HSK[0x1f927e0]: Removing ciphersuite: PSK_SHA_AES_256_CBC_SHA1
HSK[0x1f927e0]: Removing ciphersuite: PSK_SHA_3DES_EDE_CBC_SHA1
HSK[0x1f927e0]: Removing ciphersuite: PSK_SHA_ARCFOUR_SHA1
HSK[0x1f927e0]: Removing ciphersuite: SRP_SHA_AES_128_CBC_SHA1
HSK[0x1f927e0]: Removing ciphersuite: SRP_SHA_AES_256_CBC_SHA1
HSK[0x1f927e0]: Removing ciphersuite: SRP_SHA_3DES_EDE_CBC_SHA1
EXT[0x1f927e0]: Sending extension CERT_TYPE
HSK[0x1f927e0]: CLIENT HELLO was send [88 bytes]
REC[0x1f927e0]: Sending Packet[1] Handshake(22) with length: 88
REC[0x1f927e0]: Sent Packet[2] Handshake(22) with length: 149
REC[0x1f927e0]: Expected Packet[1] Handshake(22) with length: 1
REC[0x1f927e0]: Received Packet[1] Application Data(23) with length: 48
REC[0x1f927e0]: Decrypted Packet[1] Application Data(23) with length: 21
ASSERT: gnutls_record.c:735
ASSERT: gnutls_record.c:1048
ASSERT: gnutls_buffers.c:1032
ASSERT: gnutls_handshake.c:1045
ASSERT: gnutls_handshake.c:2364

-- 
(domestic pets only, the antidote for overdose, milk.)
  larsi@gnus.org * Lars Magne Ingebrigtsen




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-27 13:56                                               ` Lars Magne Ingebrigtsen
  2010-09-27 14:03                                                 ` Lars Magne Ingebrigtsen
  2010-09-27 14:11                                                 ` Lars Magne Ingebrigtsen
@ 2010-09-27 14:21                                                 ` Lars Magne Ingebrigtsen
  2010-09-27 14:40                                                   ` Lars Magne Ingebrigtsen
  2010-09-27 14:42                                                 ` Ted Zlatanov
  3 siblings, 1 reply; 93+ messages in thread
From: Lars Magne Ingebrigtsen @ 2010-09-27 14:21 UTC (permalink / raw)
  To: emacs-devel; +Cc: gnutls-devel

If I return Qt when gnutls_handshake() returns zero, then I get the
Gmail IMAP greeting, which I think it works.

I'll clean it up and see whether that really fixed this...

-- 
(domestic pets only, the antidote for overdose, milk.)
  larsi@gnus.org * Lars Magne Ingebrigtsen




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-26 21:50                                           ` James Cloos
  2010-09-27 13:37                                             ` Lars Magne Ingebrigtsen
@ 2010-09-27 14:36                                             ` Ted Zlatanov
  2010-09-27 18:25                                               ` James Cloos
  1 sibling, 1 reply; 93+ messages in thread
From: Ted Zlatanov @ 2010-09-27 14:36 UTC (permalink / raw)
  To: emacs-devel; +Cc: gnutls-devel

On Sun, 26 Sep 2010 17:50:37 -0400 James Cloos <cloos@jhcloos.com> wrote: 

>>>>>> "TZ" == Ted Zlatanov <tzz@lifelogs.com> writes:
TZ> I've gone over my code carefully and just can't figure out what's
TZ> different.  I'm sure it's something simple I've overlooked.

JC> It probably would help to get a full packet trace of the failed
JC> handshake and look at it in wireshark.

It's not really helpful to me since I don't know TLS well.  But there is
GnuTLS traffic across the wire, so I know the error is actually during
the handshake and not in the setup phase.  Opening a connection to a
server with an invalid SSL certificate resulted in "decryption failed"
which is not the invalid TLS packet error I see otherwise.  So I assume
the handshake passes the point of verifying certificates.

Ted




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-27 14:21                                                 ` Lars Magne Ingebrigtsen
@ 2010-09-27 14:40                                                   ` Lars Magne Ingebrigtsen
  2010-09-27 14:56                                                     ` Ted Zlatanov
                                                                       ` (2 more replies)
  0 siblings, 3 replies; 93+ messages in thread
From: Lars Magne Ingebrigtsen @ 2010-09-27 14:40 UTC (permalink / raw)
  To: emacs-devel; +Cc: gnutls-devel

Lars Magne Ingebrigtsen <larsi@gnus.org> writes:

> If I return Qt when gnutls_handshake() returns zero, then I get the
> Gmail IMAP greeting, which I think it works.
>
> I'll clean it up and see whether that really fixed this...

I've checked in the changes, since it works a bit better now than
before.  Previously, it would try to do the handshake in a loop after
completing it, and that obviously doesn't work.

With my patch, this returns an IMAP greeting:

(progn
  (require 'gnutls)
  (open-ssl-stream "tls" (current-buffer) "imap.gmail.com" "imaps"))

However, it then loops taking 100% CPU, since _gnutls_read() is being
called in an infloop since the socket in non-blocking, or something...  

-- 
(domestic pets only, the antidote for overdose, milk.)
  larsi@gnus.org * Lars Magne Ingebrigtsen




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-27 13:56                                               ` Lars Magne Ingebrigtsen
                                                                   ` (2 preceding siblings ...)
  2010-09-27 14:21                                                 ` Lars Magne Ingebrigtsen
@ 2010-09-27 14:42                                                 ` Ted Zlatanov
  2010-09-29 12:53                                                   ` Lars Magne Ingebrigtsen
  3 siblings, 1 reply; 93+ messages in thread
From: Ted Zlatanov @ 2010-09-27 14:42 UTC (permalink / raw)
  To: emacs-devel; +Cc: gnutls-devel

On Mon, 27 Sep 2010 15:56:06 +0200 Lars Magne Ingebrigtsen <larsi@gnus.org> wrote: 

LMI> Ok, now we're getting somewhere.
...
LMI> I get the following output (after a lot of other output):
...
LMI> If I return Qt when gnutls_handshake() returns zero, then I get the
LMI> Gmail IMAP greeting, which I think it works.

LMI> I'll clean it up and see whether that really fixed this...

I really appreciate you're looking at this.  I spent so much time at the
lower levels, I had my blinders on about the built-in GnuTLS logging
functions.

Ted




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-27 14:40                                                   ` Lars Magne Ingebrigtsen
@ 2010-09-27 14:56                                                     ` Ted Zlatanov
  2010-09-27 15:13                                                       ` Lars Magne Ingebrigtsen
  2010-09-27 15:02                                                     ` Bruce Stephens
  2010-09-27 15:11                                                     ` Ted Zlatanov
  2 siblings, 1 reply; 93+ messages in thread
From: Ted Zlatanov @ 2010-09-27 14:56 UTC (permalink / raw)
  To: emacs-devel; +Cc: gnutls-devel

On Mon, 27 Sep 2010 16:40:09 +0200 Lars Magne Ingebrigtsen <larsi@gnus.org> wrote: 

LMI> Lars Magne Ingebrigtsen <larsi@gnus.org> writes:
>> If I return Qt when gnutls_handshake() returns zero, then I get the
>> Gmail IMAP greeting, which I think it works.
>> 
>> I'll clean it up and see whether that really fixed this...

LMI> I've checked in the changes, since it works a bit better now than
LMI> before.  Previously, it would try to do the handshake in a loop after
LMI> completing it, and that obviously doesn't work.

Hmm, GNUTLS_E_SUCCESS is 0 by definition.  But you say in your patch:

-  if (GNUTLS_E_SUCCESS == ret)
+  if (GNUTLS_E_SUCCESS == ret || ret == 0)
   {
     /* here we're finally done.  */
     GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_READY;
+    return Qt;
   }
 
   return gnutls_make_error (ret);

gnutls_make_error returns Qt when the error is GNUTLS_E_SUCCESS.  So
none of this should be necessary.  Similarly the change to gnutls.el:

-      (while (and (not (gnutls-error-fatalp ret))
+      (while (and (not (eq ret t))
+                 (not (gnutls-error-fatalp ret))

If you do (gnutls-error-fatalp t) you'll get nil, so again that
shouldn't have been necessary.  Am I missing something?

Ted




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-27 14:40                                                   ` Lars Magne Ingebrigtsen
  2010-09-27 14:56                                                     ` Ted Zlatanov
@ 2010-09-27 15:02                                                     ` Bruce Stephens
  2010-09-27 15:07                                                       ` Lars Magne Ingebrigtsen
  2010-09-27 15:11                                                     ` Ted Zlatanov
  2 siblings, 1 reply; 93+ messages in thread
From: Bruce Stephens @ 2010-09-27 15:02 UTC (permalink / raw)
  To: emacs-devel

Lars Magne Ingebrigtsen <larsi@gnus.org> writes:

[...]

> However, it then loops taking 100% CPU, since _gnutls_read() is being
> called in an infloop since the socket in non-blocking, or something...  

In case it's not handled correctly already, TLS is potentially confusing
in that sometimes in order to read something it's necessary to write and
vice versa (because TLS sends and receives things in packets that don't
necessarily match the units of communication at other levels).

So using non-blocking I/O in TLS requires some care; the conditions at
the socket level you want to be triggered for don't necessarily match
what you're trying to do at the higher level.



^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-27 15:02                                                     ` Bruce Stephens
@ 2010-09-27 15:07                                                       ` Lars Magne Ingebrigtsen
  2010-09-27 15:18                                                         ` Lars Magne Ingebrigtsen
  0 siblings, 1 reply; 93+ messages in thread
From: Lars Magne Ingebrigtsen @ 2010-09-27 15:07 UTC (permalink / raw)
  To: emacs-devel

Bruce Stephens <bruce.stephens@isode.com> writes:

> So using non-blocking I/O in TLS requires some care; the conditions at
> the socket level you want to be triggered for don't necessarily match
> what you're trying to do at the higher level.

Right.  I think it almost handled correctly -- it just looped too much
on retries instead of letting the Emacs loop run and retry.

With the latest tweaks, I'm able to carry on a conversation with Gmail,
so I think we're getting there...

---
(progn
  (require 'gnutls)
  (setq messages-buffer-max-lines  600000)
  (open-ssl-stream "tls" (current-buffer) "imap.gmail.com" "imaps"))
* OK Gimap ready for requests from 84.215.34.171 44if8472547eex.14.

(process-send-string (get-buffer-process (current-buffer)) "1 CAPABILITY\r\n")


* CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA XLIST CHILDREN XYZZY SASL-IR AUTH=XOAUTH.
1 OK Thats all she wrote! 44if8472547eex.14.
---

However.  :-)  If I switch debugging off:

  //gnutls_global_set_log_level(4);
  //gnutls_global_set_log_function(gnutls_log_function);

Then the handshake no longer works.  That's odd?    

-- 
(domestic pets only, the antidote for overdose, milk.)
  larsi@gnus.org * Lars Magne Ingebrigtsen




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-27 14:40                                                   ` Lars Magne Ingebrigtsen
  2010-09-27 14:56                                                     ` Ted Zlatanov
  2010-09-27 15:02                                                     ` Bruce Stephens
@ 2010-09-27 15:11                                                     ` Ted Zlatanov
  2010-09-27 15:14                                                       ` Lars Magne Ingebrigtsen
  2 siblings, 1 reply; 93+ messages in thread
From: Ted Zlatanov @ 2010-09-27 15:11 UTC (permalink / raw)
  To: emacs-devel

On Mon, 27 Sep 2010 16:40:09 +0200 Lars Magne Ingebrigtsen <larsi@gnus.org> wrote: 

LMI> Lars Magne Ingebrigtsen <larsi@gnus.org> writes:
>> If I return Qt when gnutls_handshake() returns zero, then I get the
>> Gmail IMAP greeting, which I think it works.
>> 
>> I'll clean it up and see whether that really fixed this...

LMI> I've checked in the changes, since it works a bit better now than
LMI> before.  Previously, it would try to do the handshake in a loop after
LMI> completing it, and that obviously doesn't work.

(taking the GnuTLS mailing list off the CC)

I would prefer to keep my gnutls.c logging in place (using
gnutls_log_function probably).  Do you think that's confusing and that's
why you removed it all?  It provides checkpoints on every stage.

Ted




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-27 14:56                                                     ` Ted Zlatanov
@ 2010-09-27 15:13                                                       ` Lars Magne Ingebrigtsen
  0 siblings, 0 replies; 93+ messages in thread
From: Lars Magne Ingebrigtsen @ 2010-09-27 15:13 UTC (permalink / raw)
  To: emacs-devel; +Cc: gnutls-devel

Ted Zlatanov <tzz@lifelogs.com> writes:

> Hmm, GNUTLS_E_SUCCESS is 0 by definition.  But you say in your patch:
>
> -  if (GNUTLS_E_SUCCESS == ret)
> +  if (GNUTLS_E_SUCCESS == ret || ret == 0)
>    {
>      /* here we're finally done.  */
>      GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_READY;
> +    return Qt;
>    }

Oh, right.  Yeah, it was just the Elisp bit that looped too much, then.

-- 
(domestic pets only, the antidote for overdose, milk.)
  larsi@gnus.org * Lars Magne Ingebrigtsen




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-27 15:11                                                     ` Ted Zlatanov
@ 2010-09-27 15:14                                                       ` Lars Magne Ingebrigtsen
  0 siblings, 0 replies; 93+ messages in thread
From: Lars Magne Ingebrigtsen @ 2010-09-27 15:14 UTC (permalink / raw)
  To: emacs-devel

Ted Zlatanov <tzz@lifelogs.com> writes:

> I would prefer to keep my gnutls.c logging in place (using
> gnutls_log_function probably).  Do you think that's confusing and that's
> why you removed it all?  It provides checkpoints on every stage.

It was messaging so much that it was difficult to find sort out the
messages from the gnutls library, so I removed them while fiddling with
this.  Feel free to put them back.

-- 
(domestic pets only, the antidote for overdose, milk.)
  larsi@gnus.org * Lars Magne Ingebrigtsen




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-27 15:07                                                       ` Lars Magne Ingebrigtsen
@ 2010-09-27 15:18                                                         ` Lars Magne Ingebrigtsen
  0 siblings, 0 replies; 93+ messages in thread
From: Lars Magne Ingebrigtsen @ 2010-09-27 15:18 UTC (permalink / raw)
  To: emacs-devel

Lars Magne Ingebrigtsen <larsi@gnus.org> writes:

> However.  :-)  If I switch debugging off:
>
>   //gnutls_global_set_log_level(4);
>   //gnutls_global_set_log_function(gnutls_log_function);
>
> Then the handshake no longer works.  That's odd?    

Ok, this is now verified.  Without debugging, it doesn't work.  Or
rather, if the debugging is too fast, it doesn't work, so it's timing
sensitive.

Ted, feel free to take it from here, because I've got to do some other
stuff now...

-- 
(domestic pets only, the antidote for overdose, milk.)
  larsi@gnus.org * Lars Magne Ingebrigtsen




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-27 14:36                                             ` Emacs core TLS support Ted Zlatanov
@ 2010-09-27 18:25                                               ` James Cloos
  2010-09-27 18:45                                                 ` Ted Zlatanov
  0 siblings, 1 reply; 93+ messages in thread
From: James Cloos @ 2010-09-27 18:25 UTC (permalink / raw)
  To: Ted Zlatanov; +Cc: gnutls-devel, emacs-devel

>>>>> "TZ" == Ted Zlatanov <tzz@lifelogs.com> writes:

TZ> It's not really helpful to me since I don't know TLS well.

Sorry.  My point was that wireshark does a decent job of decoding the
TLS such that anyone should be able to follow what is happening.

-JimC
-- 
James Cloos <cloos@jhcloos.com>         OpenPGP: 1024D/ED7DAEA6

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-27 18:25                                               ` James Cloos
@ 2010-09-27 18:45                                                 ` Ted Zlatanov
  2010-09-27 19:07                                                   ` Lars Magne Ingebrigtsen
  0 siblings, 1 reply; 93+ messages in thread
From: Ted Zlatanov @ 2010-09-27 18:45 UTC (permalink / raw)
  To: gnutls-devel; +Cc: emacs-devel

On Mon, 27 Sep 2010 14:25:10 -0400 James Cloos <cloos@jhcloos.com> wrote: 

>>>>>> "TZ" == Ted Zlatanov <tzz@lifelogs.com> writes:
TZ> It's not really helpful to me since I don't know TLS well.

JC> Sorry.  My point was that wireshark does a decent job of decoding the
JC> TLS such that anyone should be able to follow what is happening.

With Lars' latest change we found that enabling logging, in itself, will
make things work (yay!).  We guessed it was the delay introduced by
logging but using (sit-for 0.1) in the handshake loop doesn't work like
enabling logging.  So it's something specific about the logging
function's interaction with Emacs and looking at the wire is *probably*
not going to help.  But I don't know yet what's going on.

Ted

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-27 18:45                                                 ` Ted Zlatanov
@ 2010-09-27 19:07                                                   ` Lars Magne Ingebrigtsen
  2010-09-27 19:38                                                     ` Lars Magne Ingebrigtsen
  0 siblings, 1 reply; 93+ messages in thread
From: Lars Magne Ingebrigtsen @ 2010-09-27 19:07 UTC (permalink / raw)
  To: gnutls-devel; +Cc: emacs-devel

Ted Zlatanov <tzz@lifelogs.com> writes:

> With Lars' latest change we found that enabling logging, in itself, will
> make things work (yay!).  We guessed it was the delay introduced by
> logging but using (sit-for 0.1) in the handshake loop doesn't work like
> enabling logging.  So it's something specific about the logging
> function's interaction with Emacs and looking at the wire is *probably*
> not going to help.  But I don't know yet what's going on.

I did one further test.  If I replace the `message' in the logging
function with a printf, it still works.  But if I then said

$ emacs > /dev/null

then it didn't work.

Which may point to a timing issue again.

I forgot to test with > file, to actually see what the debugging info
was.  :-/

-- 
(domestic pets only, the antidote for overdose, milk.)
  larsi@gnus.org * Lars Magne Ingebrigtsen

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-27 19:07                                                   ` Lars Magne Ingebrigtsen
@ 2010-09-27 19:38                                                     ` Lars Magne Ingebrigtsen
  0 siblings, 0 replies; 93+ messages in thread
From: Lars Magne Ingebrigtsen @ 2010-09-27 19:38 UTC (permalink / raw)
  To: emacs-devel

Lars Magne Ingebrigtsen <larsi@gnus.org> writes:

> I forgot to test with > file, to actually see what the debugging info
> was.  :-/

I did this now:

gnutls.c: [1] (Emacs) allocating credentials
gnutls.c: [2] (Emacs) allocating x509 credentials
gnutls.c: [1] (Emacs) setting the trustfile
gnutls.c: [1] (Emacs) gnutls_init
gnutls.c: [1] (Emacs) setting the priority string
gnutls.c: [2] EXT[0x1777d80]: Sending extension CERT_TYPE

gnutls.c: [2] ASSERT: gnutls_cipher.c:204

gnutls.c: [2] ASSERT: gnutls_buffers.c:322

gnutls.c: [2] ASSERT: gnutls_buffers.c:1032

gnutls.c: [2] ASSERT: gnutls_handshake.c:1045

gnutls.c: [2] ASSERT: gnutls_buffers.c:322

gnutls.c: [2] ASSERT: gnutls_buffers.c:1032

gnutls.c: [2] ASSERT: gnutls_handshake.c:1045

...

And then it just loops there.  So it bails really early...

-- 
(domestic pets only, the antidote for overdose, milk.)
  larsi@gnus.org * Lars Magne Ingebrigtsen




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-27 14:42                                                 ` Ted Zlatanov
@ 2010-09-29 12:53                                                   ` Lars Magne Ingebrigtsen
  2010-09-29 13:25                                                     ` Lars Magne Ingebrigtsen
  2010-09-29 17:06                                                     ` Ted Zlatanov
  0 siblings, 2 replies; 93+ messages in thread
From: Lars Magne Ingebrigtsen @ 2010-09-29 12:53 UTC (permalink / raw)
  To: emacs-devel

I've now gotten the gnutls support to work.  There were two main
problems:

1) emacs_read would be called instead of emacs_gnutls_read on
initialising streams.  This made the gnutls libraries very confused, as
they would get some of the data, and other bits of the data would just
be output to the process buffer.

2) 25K iterations while waiting for the handshake was just too short.
I increased it ten-fold, and now it Works For Me, but that area needs
more work to determine when to time out.  Instead of looping like that,
I think it would make more sense to move it into the accept_process_data
C layer, and re-run the handshake when there's actually more data
available on the socket.  That is, emacs_gnutls_read should do the
handshake, basically.

But I've now committed what I've done, since it's actually usable now,
and it's really fast!  It takes like a fraction of the time that tls.el
uses, what with the gnutls-cli forking and stuff.

-- 
(domestic pets only, the antidote for overdose, milk.)
  larsi@gnus.org * Lars Magne Ingebrigtsen




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-29 12:53                                                   ` Lars Magne Ingebrigtsen
@ 2010-09-29 13:25                                                     ` Lars Magne Ingebrigtsen
  2010-09-29 18:36                                                       ` Jason Earl
  2010-09-29 17:06                                                     ` Ted Zlatanov
  1 sibling, 1 reply; 93+ messages in thread
From: Lars Magne Ingebrigtsen @ 2010-09-29 13:25 UTC (permalink / raw)
  To: emacs-devel

Lars Magne Ingebrigtsen <larsi@gnus.org> writes:

> That is, emacs_gnutls_read should do the handshake, basically.

What the hey.  I implemented it, and it seems to work for me.

-- 
(domestic pets only, the antidote for overdose, milk.)
  larsi@gnus.org * Lars Magne Ingebrigtsen




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-29 12:53                                                   ` Lars Magne Ingebrigtsen
  2010-09-29 13:25                                                     ` Lars Magne Ingebrigtsen
@ 2010-09-29 17:06                                                     ` Ted Zlatanov
  2010-09-29 17:44                                                       ` Ted Zlatanov
                                                                         ` (2 more replies)
  1 sibling, 3 replies; 93+ messages in thread
From: Ted Zlatanov @ 2010-09-29 17:06 UTC (permalink / raw)
  To: emacs-devel

On Wed, 29 Sep 2010 14:53:48 +0200 Lars Magne Ingebrigtsen <larsi@gnus.org> wrote: 

LMI> But I've now committed what I've done, since it's actually usable now,
LMI> and it's really fast!  It takes like a fraction of the time that tls.el
LMI> uses, what with the gnutls-cli forking and stuff.

On Wed, 29 Sep 2010 15:25:41 +0200 Lars Magne Ingebrigtsen <larsi@gnus.org> wrote: 

LMI> Lars Magne Ingebrigtsen <larsi@gnus.org> writes:

>> That is, emacs_gnutls_read should do the handshake, basically.

LMI> What the hey.  I implemented it, and it seems to work for me.

Thanks so much, you rock.  So now it's time to actually work on the
API.  That's the easy part after you did all the hard work making it
actually run :)

The ELisp entry point is:

(defun starttls-negotiate (proc &optional priority-string
                                credentials credentials-file)

That's not very good since we also need a trust file, a callback for
some credentials, and possibly more parameters (there's three kinds of
credentials and only two are implemented currently, but they all need
different things).  So I think the parameters should be an alist or a
plist, probably a plist since the parameters will be well-defined.  The
user should probably be able to override them globally in the typical
alist keyed by server name.

I would also rename the function above to `gnutls-negotiate' and
generally keep everything in gnutls.el with the gnutls- prefix.  So:

(defun gnutls-negotiate (proc &rest params)

The C entry point:

DEFUN ("gnutls-boot", Fgnutls_boot, Sgnutls_boot, 3, 7, 0,
       doc: /* Initializes client-mode GnuTLS for process PROC.
...
PRIORITY_STRING is a string describing the priority.
TYPE is either `gnutls-anon' or `gnutls-x509pki'.
TRUSTFILE is a PEM encoded trust file for `gnutls-x509pki'.
KEYFILE is ... for `gnutls-x509pki' (TODO).
CALLBACK is ... for `gnutls-x509pki' (TODO).
LOGLEVEL is the debug level requested from GnuTLS, try 4.
...
    (Lisp_Object proc, Lisp_Object priority_string, Lisp_Object type,
     Lisp_Object trustfile, Lisp_Object keyfile, Lisp_Object callback,
     Lisp_Object loglevel)

Should be similarly reworked and made more robust to catch errors.  So:

DEFUN ("gnutls-boot", Fgnutls_boot, Sgnutls_boot, 3, 7, 0,
       doc: /* Initializes client-mode GnuTLS for process PROC.
...
PRIORITY_STRING is a string describing the priority.
LOGLEVEL is the debug level requested from GnuTLS, try 4.
PARAMS is a plist of parameters, see below.
...
    (Lisp_Object proc, Lisp_Object loglevel, Lisp_Object params)

Generally I'd like to make the API less of an override to ssl.el and
starttls.el and more of a standalone facility.  So `open-ssl-stream' and
`starttls-open-stream' would not be provided by gnutls.el.  It would
provide `open-gnutls-stream' with a required parameters alist/plist,
which then calls `gnutls-negotiate'.

Yes, that means that older code won't work directly with gnutls.el, but
the GnuTLS is just much richer than ssl.el or starttls.el.  I don't want
packages authors to say "oh I can open a stream and It Just Works" but
instead they should at least look at the docstring and understand what
they are providing to their users.

Finally, I did not explore making Emacs a SSL/TLS server.  I think
that's not really useful without threads, but if anyone has an amazing
reason to do it, please speak up.

Ted




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-29 17:06                                                     ` Ted Zlatanov
@ 2010-09-29 17:44                                                       ` Ted Zlatanov
  2010-09-29 18:43                                                         ` Lars Magne Ingebrigtsen
  2010-09-29 18:43                                                       ` Lars Magne Ingebrigtsen
  2010-10-03 14:21                                                       ` Ted Zlatanov
  2 siblings, 1 reply; 93+ messages in thread
From: Ted Zlatanov @ 2010-09-29 17:44 UTC (permalink / raw)
  To: emacs-devel

Regarding this comment from Stefan Monnier in gnutls.c:

    /* FIXME: This can't be right: infd and outfd are integers (file handles)
       whereas the function expects args of type gnutls_transport_ptr_t.  */
     gnutls_transport_set_ptr2 (state, XPROCESS (proc)->infd,
                                XPROCESS (proc)->outfd);

According to the docs and to the example clients in the GnuTLS code,
that's the right way to set up socket FDs as GnuTLS transports.  Should
I add a clarifying comment?

Ted




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-29 13:25                                                     ` Lars Magne Ingebrigtsen
@ 2010-09-29 18:36                                                       ` Jason Earl
  2010-09-29 20:05                                                         ` Ted Zlatanov
  0 siblings, 1 reply; 93+ messages in thread
From: Jason Earl @ 2010-09-29 18:36 UTC (permalink / raw)
  To: emacs-devel

On Wed, Sep 29 2010, Lars Magne Ingebrigtsen wrote:

> Lars Magne Ingebrigtsen <larsi@gnus.org> writes:
>
>> That is, emacs_gnutls_read should do the handshake, basically.
>
> What the hey.  I implemented it, and it seems to work for me.

It works here as well, and it seems to be considerably faster to boot.
There is one thing that I did have to change from an older setup,
however.  I keep my authinfo file in ~/.emacs.d/authinfo so that I can
version it with the rest of my emacs stuff.  I used to set
nnimap-authinfo-file for imaps, but with the newest builds it appears
that auth-sources is the correct variable to set to customize this.

This is not a criticism, as I am excited to see these changes land.  It
is just a bit of advice for someone else who is interested in testing
this code.

You also might want to consider changing the (BROKEN) in configure.in to
(EXPERIMENTAL).

Jason



^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-29 17:06                                                     ` Ted Zlatanov
  2010-09-29 17:44                                                       ` Ted Zlatanov
@ 2010-09-29 18:43                                                       ` Lars Magne Ingebrigtsen
  2010-10-03 14:21                                                       ` Ted Zlatanov
  2 siblings, 0 replies; 93+ messages in thread
From: Lars Magne Ingebrigtsen @ 2010-09-29 18:43 UTC (permalink / raw)
  To: emacs-devel

Ted Zlatanov <tzz@lifelogs.com> writes:

> I would also rename the function above to `gnutls-negotiate' and
> generally keep everything in gnutls.el with the gnutls- prefix.  So:
>
> (defun gnutls-negotiate (proc &rest params)

Sounds good.

> Generally I'd like to make the API less of an override to ssl.el and
> starttls.el and more of a standalone facility.  So `open-ssl-stream' and
> `starttls-open-stream' would not be provided by gnutls.el.  It would
> provide `open-gnutls-stream' with a required parameters alist/plist,
> which then calls `gnutls-negotiate'.

Yes, it's better to have -gnutls- in the function name, so that there's
no confusion about which one of the many (ssl.el/tls.el/starttls.el)
interfaces we're actually calling.

-- 
(domestic pets only, the antidote for overdose, milk.)
  larsi@gnus.org * Lars Magne Ingebrigtsen




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-29 17:44                                                       ` Ted Zlatanov
@ 2010-09-29 18:43                                                         ` Lars Magne Ingebrigtsen
  0 siblings, 0 replies; 93+ messages in thread
From: Lars Magne Ingebrigtsen @ 2010-09-29 18:43 UTC (permalink / raw)
  To: emacs-devel

Ted Zlatanov <tzz@lifelogs.com> writes:

> According to the docs and to the example clients in the GnuTLS code,
> that's the right way to set up socket FDs as GnuTLS transports.  Should
> I add a clarifying comment?

Yes, please.  But it should be cast explicitly (and not implicitly) so
that we avoid the compiler warning.

-- 
(domestic pets only, the antidote for overdose, milk.)
  larsi@gnus.org * Lars Magne Ingebrigtsen




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-29 18:36                                                       ` Jason Earl
@ 2010-09-29 20:05                                                         ` Ted Zlatanov
  2010-09-29 20:32                                                           ` Jason Earl
  0 siblings, 1 reply; 93+ messages in thread
From: Ted Zlatanov @ 2010-09-29 20:05 UTC (permalink / raw)
  To: emacs-devel

On Wed, 29 Sep 2010 12:36:59 -0600 Jason Earl <jearl@notengoamigos.org> wrote: 

JE> It works here as well, and it seems to be considerably faster to boot.
JE> There is one thing that I did have to change from an older setup,
JE> however.  I keep my authinfo file in ~/.emacs.d/authinfo so that I can
JE> version it with the rest of my emacs stuff.  I used to set
JE> nnimap-authinfo-file for imaps, but with the newest builds it appears
JE> that auth-sources is the correct variable to set to customize this.

JE> This is not a criticism, as I am excited to see these changes land.  It
JE> is just a bit of advice for someone else who is interested in testing
JE> this code.

I think nnimap.el should maybe warn the user on get-new-news if it sees
`nnimap-authinfo-file' to save them the frustration of figuring this
out.

JE> You also might want to consider changing the (BROKEN) in configure.in to
JE> (EXPERIMENTAL).

I'll do it when I push the API changes I mentioned, thanks :)

Ted




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-29 20:05                                                         ` Ted Zlatanov
@ 2010-09-29 20:32                                                           ` Jason Earl
  2010-09-29 20:35                                                             ` Lars Magne Ingebrigtsen
  0 siblings, 1 reply; 93+ messages in thread
From: Jason Earl @ 2010-09-29 20:32 UTC (permalink / raw)
  To: Ted Zlatanov; +Cc: emacs-devel

On Wed, Sep 29 2010, Ted Zlatanov wrote:

> On Wed, 29 Sep 2010 12:36:59 -0600 Jason Earl <jearl@notengoamigos.org> wrote: 
>
> JE> It works here as well, and it seems to be considerably faster to boot.
> JE> There is one thing that I did have to change from an older setup,
> JE> however.  I keep my authinfo file in ~/.emacs.d/authinfo so that I can
> JE> version it with the rest of my emacs stuff.  I used to set
> JE> nnimap-authinfo-file for imaps, but with the newest builds it appears
> JE> that auth-sources is the correct variable to set to customize this.
>
> JE> This is not a criticism, as I am excited to see these changes land.  It
> JE> is just a bit of advice for someone else who is interested in testing
> JE> this code.
>
> I think nnimap.el should maybe warn the user on get-new-news if it
> sees `nnimap-authinfo-file' to save them the frustration of figuring
> this out.

For the record, it wasn't frustrating to me at all.  I have been using
Emacs for quite some time, but I am just getting to the point where I
can use the Emacs source code to actually solve (some) problems.  It was
actually pretty exciting to be able to figure this out.

Which, of course, is why I am using the bzr version of Emacs.  I agree
that warning users of the switch would be a great idea.  While you are
at it you might want to consider doing something with
nntp-authinfo-file.  Perhaps it should use auth-sources as well?

> JE> You also might want to consider changing the (BROKEN) in
> JE> configure.in to (EXPERIMENTAL).
>
> I'll do it when I push the API changes I mentioned, thanks :)
>
> Ted

I did a bit more testing, and now I am not sure that I am using the
built-in gnutls stuff.  I looked in *Messages* and I saw lines with
gnutls-cli.  So I removed gnutls-cli and now apparently openssl is
involved.  This probably means that I am not actually testing the built
in gnutls connections.  Right?  Here's a bit from my current *Messages*

--8<---------------cut here---------------start------------->8---
Opening nnimap server on mail...
Opening TLS connection to `helpdesk.0catch.com'...
Opening TLS connection with `gnutls-cli -p 993 helpdesk.0catch.com'...failed
Opening TLS connection with `gnutls-cli -p 993 helpdesk.0catch.com --protocols ssl3'...failed
Opening TLS connection with `openssl s_client -connect helpdesk.0catch.com:993 -no_ssl2 -ign_eof'...done
Opening TLS connection to `helpdesk.0catch.com'...done
--8<---------------cut here---------------end--------------->8---

So how do I test this?  I did:

./configure --with-gnutls

and I get

--8<---------------cut here---------------start------------->8---
  Does Emacs use -lgnutls (BROKEN)?                       yes
--8<---------------cut here---------------end--------------->8---

What else do I need to do?

Sorry for the confusion.

Jason



^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-29 20:32                                                           ` Jason Earl
@ 2010-09-29 20:35                                                             ` Lars Magne Ingebrigtsen
  2010-09-29 21:33                                                               ` Jason Earl
  0 siblings, 1 reply; 93+ messages in thread
From: Lars Magne Ingebrigtsen @ 2010-09-29 20:35 UTC (permalink / raw)
  To: emacs-devel

Jason Earl <jearl@notengoamigos.org> writes:

> While you are at it you might want to consider doing something with
> nntp-authinfo-file.  Perhaps it should use auth-sources as well?

It should, but since the auth-source interface is in a flux, I don't
think that has to happen yet.

> This probably means that I am not actually testing the built
> in gnutls connections.  Right?

Right.

> and I get
>   Does Emacs use -lgnutls (BROKEN)?                       yes
> What else do I need to do?

Nothing uses the built-in gnutls support yet, but if you want to test
it, say

(progn
  (require 'gnutls)
  (open-ssl-stream "imap" (current-buffer) "imap.gmail.com" "imaps"))

If you get a greeting, it works.  :-)  

-- 
(domestic pets only, the antidote for overdose, milk.)
  larsi@gnus.org * Lars Magne Ingebrigtsen




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-29 20:35                                                             ` Lars Magne Ingebrigtsen
@ 2010-09-29 21:33                                                               ` Jason Earl
  0 siblings, 0 replies; 93+ messages in thread
From: Jason Earl @ 2010-09-29 21:33 UTC (permalink / raw)
  To: emacs-devel

On Wed, Sep 29 2010, Lars Magne Ingebrigtsen wrote:

> Jason Earl <jearl@notengoamigos.org> writes:
>
>> While you are at it you might want to consider doing something with
>> nntp-authinfo-file.  Perhaps it should use auth-sources as well?
>
> It should, but since the auth-source interface is in a flux, I don't
> think that has to happen yet.
>
>> This probably means that I am not actually testing the built
>> in gnutls connections.  Right?
>
> Right.

Suddenly I feel considerably less helpful.

>> and I get
>>   Does Emacs use -lgnutls (BROKEN)?                       yes
>> What else do I need to do?
>
> Nothing uses the built-in gnutls support yet, but if you want to test
> it, say
>
> (progn
>   (require 'gnutls)
>   (open-ssl-stream "imap" (current-buffer) "imap.gmail.com" "imaps"))
>
> If you get a greeting, it works.  :-)  

Well, that did work for me, and with minor changes I got a response from
my own imaps server with it as well.  So at the very least that is
another successful trial.

Thanks for your patience with me.  I learned a great deal.
Unfortunately, none of it was helpful to Emacs as a whole.  Maybe next
time.

Jason



^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-26  6:12                                         ` Ted Zlatanov
@ 2010-09-30 10:10                                           ` Simon Josefsson
  2010-10-04  3:42                                             ` Ted Zlatanov
  0 siblings, 1 reply; 93+ messages in thread
From: Simon Josefsson @ 2010-09-30 10:10 UTC (permalink / raw)
  To: Ted Zlatanov; +Cc: gnutls-devel, emacs-devel

Ted Zlatanov <tzz@lifelogs.com> writes:

>>> +PRIORITY-STRING is as per the GnuTLS docs.
>
> SJ> Maybe there could be an info hyperlink here?
>
> Sorry, you mean to the GnuTLS webserver?  I don't know if that's
> necessary.

I was thinking to the Info manual.  Just a nit...

> SJ> 2) The design makes it a bit difficult to support multiple
> SJ> credentials.  The GnuTLS API allows clients to have several
> SJ> credentials (X.509, OpenPGP, etc).  Perhaps copying the GnuTLS API
> SJ> further is more flexible.
>
> I thought of making it more flexible but I really want to get the basic
> case working.

That's probably a good idea.

> As I mentioned earlier I think GnuTLS should consider further
> extending the idea of priority strings to a full configuration
> (credentials especially) in a single string or file.  That would make
> using it so much easier from Emacs Lisp.

Hm.  Interesting, yes, it could do that.  I'm not sure it makes sense to
support at the C layer, but I'll think about it.

> I tried to figure out the TLS handshake problem but it has stumped me.
> It's taken me many hours and I still don't know what I'm missing so, as
> I mentioned in my other message, I've checked in my current state to let
> others take a look.  If you or other GnuTLS developers can help, it
> would be greatly appreciated.  Once the handshake works I will work on
> the other improvements you mentioned and on getting the GnuTLS support
> into Gnus and other parts of Emacs.

Isn't it just that you don't have a proper X.509 setup?

/Simon

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-29 17:06                                                     ` Ted Zlatanov
  2010-09-29 17:44                                                       ` Ted Zlatanov
  2010-09-29 18:43                                                       ` Lars Magne Ingebrigtsen
@ 2010-10-03 14:21                                                       ` Ted Zlatanov
  2010-10-03 14:48                                                         ` Ted Zlatanov
  2 siblings, 1 reply; 93+ messages in thread
From: Ted Zlatanov @ 2010-10-03 14:21 UTC (permalink / raw)
  To: emacs-devel

I pushed the last version of gnutls.{c,el} using the old API, but with
plists for gnutls-boot.  Please test and let me know if it works for
you.  It worked for me.

If there are no problems I'll rework gnutls.el to be a standalone
library and change the API as we discussed.

Thanks
Ted




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-10-03 14:21                                                       ` Ted Zlatanov
@ 2010-10-03 14:48                                                         ` Ted Zlatanov
  2010-10-03 22:37                                                           ` Lars Magne Ingebrigtsen
  0 siblings, 1 reply; 93+ messages in thread
From: Ted Zlatanov @ 2010-10-03 14:48 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 476 bytes --]

On Sun, 03 Oct 2010 09:21:49 -0500 Ted Zlatanov <tzz@lifelogs.com> wrote: 

TZ> I pushed the last version of gnutls.{c,el} using the old API, but with
TZ> plists for gnutls-boot.  Please test and let me know if it works for
TZ> you.  It worked for me.

TZ> If there are no problems I'll rework gnutls.el to be a standalone
TZ> library and change the API as we discussed.

I had trouble committing so the patches are below.  I'll commit when I
can or Lars can push them.

Ted


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: tls-plist1.patch --]
[-- Type: text/x-diff, Size: 3252 bytes --]

=== modified file 'lisp/ChangeLog'
--- lisp/ChangeLog	2010-10-03 04:31:59 +0000
+++ lisp/ChangeLog	2010-10-03 14:19:04 +0000
@@ -1,3 +1,10 @@
+2010-10-03  Teodor Zlatanov  <tzz@lifelogs.com>
+
+	* net/gnutls.el (starttls-negotiate): Use the plist interface to
+	`gnutls-boot'.  Make TYPE the only required parameter.  Allow
+	TRUSTFILES and KEYFILES to be lists.
+	(open-ssl-stream): Use it.
+
 2010-10-03  Chong Yidong  <cyd@stupidchicken.com>
 
 	* emacs-lisp/bytecomp.el (byte-compile-from-buffer): Remove

=== modified file 'lisp/net/gnutls.el'
--- lisp/net/gnutls.el	2010-09-29 13:25:24 +0000
+++ lisp/net/gnutls.el	2010-10-03 14:19:04 +0000
@@ -57,34 +57,36 @@
 Fourth arg SERVICE is name of the service desired, or an integer
 specifying a port number to connect to."
   (let ((proc (open-network-stream name buffer host service)))
-    (starttls-negotiate proc nil 'gnutls-x509pki)))
+    (starttls-negotiate proc 'gnutls-x509pki)))
 
 ;; (open-ssl-stream "tls" "tls-buffer" "yourserver.com" "https")
-(defun starttls-negotiate (proc &optional priority-string
-                                credentials credentials-file)
+;; (open-ssl-stream "tls" "tls-buffer" "imap.gmail.com" "imaps")
+(defun starttls-negotiate (proc type &optional priority-string
+                                trustfiles keyfiles)
   "Negotiate a SSL or TLS connection.
-PROC is the process returned by `starttls-open-stream'.
-PRIORITY-STRING is as per the GnuTLS docs.
-CREDENTIALS is `gnutls-x509pki' or `gnutls-anon'.
-CREDENTIALS-FILE is a filename with meaning dependent on CREDENTIALS."
-  (let* ((credentials (or credentials 'gnutls-x509pki))
-         (credentials-file (or credentials-file
-                               "/etc/ssl/certs/ca-certificates.crt"
-                               ;"/etc/ssl/certs/ca.pem"
-                               ))
-
+TYPE is `gnutls-x509pki' (default) or `gnutls-anon'.  Use nil for the default.
+PROC is a process returned by `open-network-stream'.
+PRIORITY-STRING is as per the GnuTLS docs, default is \"NORMAL\".
+TRUSTFILES is a list of CA bundles.
+KEYFILES is a list of client keys."
+  (let* ((type (or type 'gnutls-x509pki))
+         (trusfiles (or trustfiles
+                        '("/etc/ssl/certs/ca-certificates.crt")))
          (priority-string (or priority-string
                               (cond
-                               ((eq credentials 'gnutls-anon)
+                               ((eq type 'gnutls-anon)
                                 "NORMAL:+ANON-DH:!ARCFOUR-128")
-                               ((eq credentials 'gnutls-x509pki)
+                               ((eq type 'gnutls-x509pki)
                                 "NORMAL"))))
+         (params `(:priority ,priority-string
+                             :loglevel ,gnutls-log-level
+                             :trustfiles ,trustfiles
+                             :keyfiles ,keyfiles
+                             :callbacks nil))
          ret)
 
     (gnutls-message-maybe
-     (setq ret (gnutls-boot proc priority-string
-                            credentials credentials-file
-                            nil nil gnutls-log-level))
+     (setq ret (gnutls-boot proc type params))
      "boot: %s")
 
     proc))


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: tls-plist2.patch --]
[-- Type: text/x-diff, Size: 9359 bytes --]

=== modified file 'src/ChangeLog'
--- src/ChangeLog	2010-10-03 12:36:19 +0000
+++ src/ChangeLog	2010-10-03 14:18:40 +0000
@@ -1,3 +1,15 @@
+2010-10-03  Teodor Zlatanov  <tzz@lifelogs.com>
+
+	* gnutls.h (GNUTLS_LOG2): Convenience macro.
+
+	* gnutls.c: Add property list symbol holders.
+	(emacs_gnutls_handshake): Clarify how sockets are passed to
+	GnuTLS.
+	(gnutls_log_function2): Convenience function using GNUTLS_LOG2.
+	(Fgnutls_boot): Get all parameters from a plist.  Require trustfiles
+	and keyfiles to be a list of file names.  Default to "NORMAL" for
+	the priority string.  Improve logging.
+
 2010-10-03  Juanma Barranquero  <lekktu@gmail.com>
 
 	* makefile.w32-in (TAGS, TAGS-LISP, TAGS-gmake): Add $(FONTOBJ).

=== modified file 'src/gnutls.c'
--- src/gnutls.c	2010-10-03 04:12:15 +0000
+++ src/gnutls.c	2010-10-03 14:18:40 +0000
@@ -32,6 +32,13 @@
   Qgnutls_e_invalid_session, Qgnutls_e_not_ready_for_handshake;
 int global_initialized;
 
+/* The following are for the property list of `gnutls-boot'.  */
+Lisp_Object Qgnutls_bootprop_priority;
+Lisp_Object Qgnutls_bootprop_trustfiles;
+Lisp_Object Qgnutls_bootprop_keyfiles;
+Lisp_Object Qgnutls_bootprop_callbacks;
+Lisp_Object Qgnutls_bootprop_loglevel;
+
 static void
 emacs_gnutls_handshake (struct Lisp_Process *proc)
 {
@@ -43,6 +50,9 @@
 
   if (proc->gnutls_initstage < GNUTLS_STAGE_TRANSPORT_POINTERS_SET)
     {
+      /* This is how GnuTLS takes sockets: as file descriptors passed
+         in.  For an Emacs process socket, infd and outfd are the
+         same but we use this two-argument version for clarity.  */
       gnutls_transport_set_ptr2 (state,
 				 (gnutls_transport_ptr_t) (long) proc->infd,
 				 (gnutls_transport_ptr_t) (long) proc->outfd);
@@ -271,20 +281,29 @@
   message ("gnutls.c: [%d] %s", level, string);
 }
 
-DEFUN ("gnutls-boot", Fgnutls_boot, Sgnutls_boot, 3, 7, 0,
-       doc: /* Initialize client-mode GnuTLS for process PROC.
+static void
+gnutls_log_function2 (int level, const char* string, const char* extra)
+{
+  message ("gnutls.c: [%d] %s %s", level, string, extra);
+}
+
+DEFUN ("gnutls-boot", Fgnutls_boot, Sgnutls_boot, 3, 3, 0,
+       doc: /* Initialize GnuTLS client for process PROC with TYPE+PROPLIST.
 Currently only client mode is supported.  Returns a success/failure
 value you can check with `gnutls-errorp'.
 
-PRIORITY-STRING is a string describing the priority.
-TYPE is either `gnutls-anon' or `gnutls-x509pki'.
-TRUSTFILE is a PEM encoded trust file for `gnutls-x509pki'.
-KEYFILE is ... for `gnutls-x509pki' (TODO).
-CALLBACK is ... for `gnutls-x509pki' (TODO).
-LOGLEVEL is the debug level requested from GnuTLS, try 4.
-
-LOGLEVEL will be set for this process AND globally for GnuTLS.  So if
-you set it higher or lower at any point, it affects global debugging.
+TYPE is a symbol, either `gnutls-anon' or `gnutls-x509pki'.
+PROPLIST is a property list with the following keys:
+
+:priority is a GnuTLS priority string, defaults to "NORMAL".
+:trustfiles is a list of PEM-encoded trust files for `gnutls-x509pki'.
+:keyfiles is a list of PEM-encoded key files for `gnutls-x509pki'.
+:callbacks is an alist of callback functions (TODO).
+:loglevel is the debug level requested from GnuTLS, try 4.
+
+The debug level will be set for this process AND globally for GnuTLS.
+So if you set it higher or lower at any point, it affects global
+debugging.
 
 Note that the priority is set on the client.  The server does not use
 the protocols's priority except for disabling protocols that were not
@@ -295,11 +314,9 @@
 be deallocated by calling `gnutls-deinit' or by calling it again.
 
 Each authentication type may need additional information in order to
-work.  For X.509 PKI (`gnutls-x509pki'), you need TRUSTFILE and
-KEYFILE and optionally CALLBACK.  */)
-  (Lisp_Object proc, Lisp_Object priority_string, Lisp_Object type,
-   Lisp_Object trustfile, Lisp_Object keyfile, Lisp_Object callback,
-   Lisp_Object loglevel)
+work.  For X.509 PKI (`gnutls-x509pki'), you probably need at least
+one trustfile (usually a CA bundle).  */)
+  (Lisp_Object proc, Lisp_Object type, Lisp_Object proplist)
 {
   int ret = GNUTLS_E_SUCCESS;
 
@@ -312,10 +329,25 @@
   gnutls_certificate_credentials_t x509_cred;
   gnutls_anon_client_credentials_t anon_cred;
   Lisp_Object global_init;
+  char* priority_string_ptr = "NORMAL"; /* default priority string.  */
+  Lisp_Object tail;
+
+  /* Placeholders for the property list elements.  */
+  Lisp_Object priority_string;
+  Lisp_Object trustfiles;
+  Lisp_Object keyfiles;
+  Lisp_Object callbacks;
+  Lisp_Object loglevel;
 
   CHECK_PROCESS (proc);
   CHECK_SYMBOL (type);
-  CHECK_STRING (priority_string);
+  CHECK_LIST (proplist);
+
+  priority_string = Fplist_get (proplist, Qgnutls_bootprop_priority);
+  trustfiles      = Fplist_get (proplist, Qgnutls_bootprop_trustfiles);
+  keyfiles        = Fplist_get (proplist, Qgnutls_bootprop_keyfiles);
+  callbacks       = Fplist_get (proplist, Qgnutls_bootprop_callbacks);
+  loglevel        = Fplist_get (proplist, Qgnutls_bootprop_loglevel);
 
   state = XPROCESS (proc)->gnutls_state;
   XPROCESS (proc)->gnutls_p = 1;
@@ -394,29 +426,49 @@
 
   if (EQ (type, Qgnutls_x509pki))
     {
-      if (STRINGP (trustfile))
-	{
-          GNUTLS_LOG (1, max_log_level, "setting the trustfile");
-          ret = gnutls_certificate_set_x509_trust_file
-            (x509_cred,
-             SDATA (trustfile),
-             file_format);
-
-          if (ret < GNUTLS_E_SUCCESS)
-            return gnutls_make_error (ret);
-	}
-
-      if (STRINGP (keyfile))
-	{
-          GNUTLS_LOG (1, max_log_level, "setting the keyfile");
-          ret = gnutls_certificate_set_x509_crl_file
-            (x509_cred,
-             SDATA (keyfile),
-             file_format);
-
-          if (ret < GNUTLS_E_SUCCESS)
-            return gnutls_make_error (ret);
-	}
+      for (tail = trustfiles; !NILP (tail); tail = Fcdr (tail))
+	{
+	  Lisp_Object trustfile = Fcar (tail);
+          if (STRINGP (trustfile))
+            {
+              GNUTLS_LOG2 (1, max_log_level, "setting the trustfile: ",
+                           SDATA (trustfile));
+              ret = gnutls_certificate_set_x509_trust_file
+                (x509_cred,
+                 SDATA (trustfile),
+                 file_format);
+              
+              if (ret < GNUTLS_E_SUCCESS)
+                return gnutls_make_error (ret);
+            }
+          else
+            {
+              error ("Sorry, GnuTLS can't use non-string trustfile %s",
+                     trustfile);
+            }
+        }
+
+      for (tail = keyfiles; !NILP (tail); tail = Fcdr (tail))
+	{
+	  Lisp_Object keyfile = Fcar (tail);
+          if (STRINGP (keyfile))
+            {
+              GNUTLS_LOG2 (1, max_log_level, "setting the keyfile: ",
+                           SDATA (keyfile));
+              ret = gnutls_certificate_set_x509_crl_file
+                (x509_cred,
+                 SDATA (keyfile),
+                 file_format);
+              
+              if (ret < GNUTLS_E_SUCCESS)
+                return gnutls_make_error (ret);
+            }
+          else
+            {
+              error ("Sorry, GnuTLS can't use non-string keyfile %s",
+                     keyfile);
+            }
+        }
     }
 
   GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_FILES;
@@ -432,10 +484,22 @@
 
   GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_INIT;
 
+  if (STRINGP (priority_string))
+    {
+      priority_string_ptr = (char*) SDATA (priority_string);
+      GNUTLS_LOG2 (1, max_log_level, "got non-default priority string:",
+                   priority_string_ptr);
+    }
+  else
+    {
+      GNUTLS_LOG2 (1, max_log_level, "using default priority string:",
+                   priority_string_ptr);
+    }
+  
   GNUTLS_LOG (1, max_log_level, "setting the priority string");
 
   ret = gnutls_priority_set_direct (state,
-				    (char*) SDATA (priority_string),
+				    priority_string_ptr,
 				    NULL);
 
   if (ret < GNUTLS_E_SUCCESS)
@@ -514,6 +578,21 @@
   Qgnutls_x509pki = intern_c_string ("gnutls-x509pki");
   staticpro (&Qgnutls_x509pki);
 
+  Qgnutls_bootprop_priority = intern_c_string ("priority");
+  staticpro (&Qgnutls_bootprop_priority);
+
+  Qgnutls_bootprop_trustfiles = intern_c_string ("trustfiles");
+  staticpro (&Qgnutls_bootprop_trustfiles);
+
+  Qgnutls_bootprop_keyfiles = intern_c_string ("keyfiles");
+  staticpro (&Qgnutls_bootprop_keyfiles);
+
+  Qgnutls_bootprop_callbacks = intern_c_string ("callbacks");
+  staticpro (&Qgnutls_bootprop_callbacks);
+
+  Qgnutls_bootprop_loglevel = intern_c_string ("loglevel");
+  staticpro (&Qgnutls_bootprop_loglevel);
+
   Qgnutls_e_interrupted = intern_c_string ("gnutls-e-interrupted");
   staticpro (&Qgnutls_e_interrupted);
   Fput (Qgnutls_e_interrupted, Qgnutls_code,

=== modified file 'src/gnutls.h'
--- src/gnutls.h	2010-09-29 12:48:29 +0000
+++ src/gnutls.h	2010-10-03 14:18:40 +0000
@@ -48,6 +48,8 @@
 
 #define GNUTLS_LOG(level, max, string) if (level <= max) { gnutls_log_function (level, "(Emacs) " string); }
 
+#define GNUTLS_LOG2(level, max, string, extra) if (level <= max) { gnutls_log_function2 (level, "(Emacs) " string, extra); }
+
 int
 emacs_gnutls_write (int fildes, struct Lisp_Process *proc, char *buf,
                     unsigned int nbyte);


^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-10-03 14:48                                                         ` Ted Zlatanov
@ 2010-10-03 22:37                                                           ` Lars Magne Ingebrigtsen
  2010-10-04  1:23                                                             ` final GnuTLS API! (was: Emacs core TLS support) Ted Zlatanov
  0 siblings, 1 reply; 93+ messages in thread
From: Lars Magne Ingebrigtsen @ 2010-10-03 22:37 UTC (permalink / raw)
  To: emacs-devel

Ted Zlatanov <tzz@lifelogs.com> writes:

> I had trouble committing so the patches are below.  I'll commit when I
> can or Lars can push them.

I've checked this in now.

-- 
(domestic pets only, the antidote for overdose, milk.)
  larsi@gnus.org * Lars Magne Ingebrigtsen




^ permalink raw reply	[flat|nested] 93+ messages in thread

* final GnuTLS API! (was: Emacs core TLS support)
  2010-10-03 22:37                                                           ` Lars Magne Ingebrigtsen
@ 2010-10-04  1:23                                                             ` Ted Zlatanov
  2010-10-04 10:49                                                               ` final GnuTLS API! Lars Magne Ingebrigtsen
  0 siblings, 1 reply; 93+ messages in thread
From: Ted Zlatanov @ 2010-10-04  1:23 UTC (permalink / raw)
  To: emacs-devel

On Mon, 04 Oct 2010 00:37:37 +0200 Lars Magne Ingebrigtsen <larsi@gnus.org> wrote: 

LMI> Ted Zlatanov <tzz@lifelogs.com> writes:
>> I had trouble committing so the patches are below.  I'll commit when I
>> can or Lars can push them.

LMI> I've checked this in now.

Thanks.  My connection was really bad this morning.

What do you think about the interface?  I like it much better.  A plist
is a nice balance between static parameters and a freeform alist.

I've now committed the final GnuTLS client API in lisp/net/gnutls.el.
It's just two functions clients are supposed to use, which I think is
good.  Look it over and unless you have any problems with it, I'll mark
it EXPERIMENTAL instead of BROKEN and write a NEWS entry.

The callbacks are still to come.  I need to figure out how to accept a
client certificate; the GnuTLS examples don't have that so I asked on
the GnuTLS mailing list.  For storage I think we'll end up with
$HOME/.emacs.d/certificates or something like that.  We can also build
our own (Emacs) list of certificate authorities (CAs) in addition to the
one provided by the OS.  That may make a lot of sense: for instance, to
set up our own CA for package management.  But it's really a GNU/FSF
question, so I'll leave any further words to the Emacs maintainers.

Thanks again for your help.
Ted




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-09-30 10:10                                           ` Simon Josefsson
@ 2010-10-04  3:42                                             ` Ted Zlatanov
  2010-10-04  6:24                                               ` Nikos Mavrogiannopoulos
  0 siblings, 1 reply; 93+ messages in thread
From: Ted Zlatanov @ 2010-10-04  3:42 UTC (permalink / raw)
  To: gnutls-devel; +Cc: emacs-devel

On Thu, 30 Sep 2010 12:10:22 +0200 Simon Josefsson <simon@josefsson.org> wrote: 

SJ> Ted Zlatanov <tzz@lifelogs.com> writes:
>>>> +PRIORITY-STRING is as per the GnuTLS docs.
>> 
SJ> Maybe there could be an info hyperlink here?
SJ> I was thinking to the Info manual.  Just a nit...

Generally I don't see Info links in the function docstrings.  It's
common to link to other functions, but I don't know about Info links.
Maybe someone more knowledgeable can say.

It's pretty unusual to use a priority string other than the default of
"NORMAL", right?  I think if we provide decent defaults, this will
rarely need to be checked and so it's not too important to provide live
links to a manual.

SJ> 2) The design makes it a bit difficult to support multiple
SJ> credentials.  The GnuTLS API allows clients to have several
SJ> credentials (X.509, OpenPGP, etc).

Do you think it's sensible to add the complexity of multiple
credentials?  It would make the current API much heavier.  Right now we
just have a credential type (anon or X.509) and a few options for
trust/keyfiles, etc.  Stacking multiple credentials could maybe work by
passing multiple plists, each with its own type, instead of just one, to
gnutls-boot.  But is that really a common scenario for a client?

>> As I mentioned earlier I think GnuTLS should consider further
>> extending the idea of priority strings to a full configuration
>> (credentials especially) in a single string or file.  That would make
>> using it so much easier from Emacs Lisp.

SJ> Hm.  Interesting, yes, it could do that.  I'm not sure it makes sense to
SJ> support at the C layer, but I'll think about it.

Thanks.  That would be very nice for talking to GnuTLS not only from
Emacs, but from Perl and other scripting languages and even from the
shell as well.

Ted

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: Emacs core TLS support
  2010-10-04  3:42                                             ` Ted Zlatanov
@ 2010-10-04  6:24                                               ` Nikos Mavrogiannopoulos
  0 siblings, 0 replies; 93+ messages in thread
From: Nikos Mavrogiannopoulos @ 2010-10-04  6:24 UTC (permalink / raw)
  To: Ted Zlatanov; +Cc: gnutls-devel, emacs-devel

2010/10/4 Ted Zlatanov <tzz@lifelogs.com>:

> SJ> Hm.  Interesting, yes, it could do that.  I'm not sure it makes sense to
> SJ> support at the C layer, but I'll think about it.
> Thanks.  That would be very nice for talking to GnuTLS not only from
> Emacs, but from Perl and other scripting languages and even from the
> shell as well.

Keep in mind that gnutls is a C library. Doing something like that it is pretty
unusual for a C API. This can be done at a higher level on the wrapper libraries
sometimes more easily.

regards,
Nikos

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: final GnuTLS API!
  2010-10-04  1:23                                                             ` final GnuTLS API! (was: Emacs core TLS support) Ted Zlatanov
@ 2010-10-04 10:49                                                               ` Lars Magne Ingebrigtsen
  2010-10-04 14:44                                                                 ` Ted Zlatanov
  0 siblings, 1 reply; 93+ messages in thread
From: Lars Magne Ingebrigtsen @ 2010-10-04 10:49 UTC (permalink / raw)
  To: emacs-devel

Ted Zlatanov <tzz@lifelogs.com> writes:

> What do you think about the interface?  I like it much better.  A plist
> is a nice balance between static parameters and a freeform alist.
>
> I've now committed the final GnuTLS client API in lisp/net/gnutls.el.
> It's just two functions clients are supposed to use, which I think is
> good.  Look it over and unless you have any problems with it, I'll mark
> it EXPERIMENTAL instead of BROKEN and write a NEWS entry.

It looks very usable.  The normal open-gnutls-stream is what most people
will use, and gnutls-negotiate is convenient for use if you're doing
STARTTLS.  

But how do you say "I don't care whether the server has a valid
certificate or not" or "I do care"?

-- 
(domestic pets only, the antidote for overdose, milk.)
  larsi@gnus.org * Lars Magne Ingebrigtsen




^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: final GnuTLS API!
  2010-10-04 10:49                                                               ` final GnuTLS API! Lars Magne Ingebrigtsen
@ 2010-10-04 14:44                                                                 ` Ted Zlatanov
  0 siblings, 0 replies; 93+ messages in thread
From: Ted Zlatanov @ 2010-10-04 14:44 UTC (permalink / raw)
  To: emacs-devel

On Mon, 04 Oct 2010 12:49:25 +0200 Lars Magne Ingebrigtsen <larsi@gnus.org> wrote: 

LMI> It looks very usable.  The normal open-gnutls-stream is what most people
LMI> will use, and gnutls-negotiate is convenient for use if you're doing
LMI> STARTTLS.

Great.  You can add it into Gnus as a network stream option if you want.

LMI> But how do you say "I don't care whether the server has a valid
LMI> certificate or not" or "I do care"?

With callbacks.  There will be a standard (not the default)
'gnutls-accept-all callback on certificate verification and the default
will probably be nil to let GnuTLS verify them internally (which it does
now IIUC).  I also want a callback that verifies, queries the user if
the certificate is unknown, and stores the certificate if accepted.  I'm
talking to the GnuTLS guys about that.  It may be a problem because I
think the handshake blocks the Emacs display thread, so we may have to
abort the handshake, query the user, then retry the handshake.

All of these callbacks will be in an alist under the :callbacks key in
the gnutls-boot parameters.

Ted




^ permalink raw reply	[flat|nested] 93+ messages in thread

end of thread, other threads:[~2010-10-04 14:44 UTC | newest]

Thread overview: 93+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-01-13 21:53 Emacs core TLS support Ted Zlatanov
2010-01-13 23:46 ` Chong Yidong
2010-01-14 14:09   ` Ted Zlatanov
2010-01-14 15:44     ` Stefan Monnier
2010-01-14 16:38       ` Ted Zlatanov
2010-01-29 19:59         ` Ted Zlatanov
2010-08-12 23:00           ` Ted Zlatanov
2010-08-13 11:04             ` James Cloos
2010-08-13 15:07               ` Ted Zlatanov
2010-08-13 15:51                 ` Julien Danjou
2010-08-13 16:11                   ` Eli Zaretskii
2010-08-13 15:53                 ` David Kastrup
2010-08-13 16:11                   ` Julien Danjou
2010-08-13 15:57                 ` Chong Yidong
2010-08-13 17:25                   ` Ted Zlatanov
2010-08-14  0:15                     ` Chong Yidong
2010-09-05  4:57                       ` Ted Zlatanov
2010-09-05  8:06                         ` Andreas Schwab
2010-09-05 22:47                         ` Stefan Monnier
2010-09-06  7:47                           ` Andreas Schwab
2010-09-06 14:31                           ` Ted Zlatanov
2010-09-06 15:53                             ` Andreas Schwab
2010-09-06 17:18                             ` Andreas Schwab
2010-09-09 15:12                               ` Ted Zlatanov
2010-09-09 22:00                                 ` Lars Magne Ingebrigtsen
2010-09-10  8:33                                   ` Andreas Schwab
2010-09-10 10:59                                     ` Lars Magne Ingebrigtsen
2010-09-10 14:06                                       ` Ted Zlatanov
2010-09-11 12:45                                         ` Stefan Monnier
2010-09-14 15:34                                           ` Ted Zlatanov
2010-09-06 21:00                             ` Stefan Monnier
2010-09-06 23:13                               ` Ted Zlatanov
2010-09-11 14:59                                 ` Ted Zlatanov
2010-09-11 15:00                                   ` Ted Zlatanov
2010-09-12 10:58                                     ` Stefan Monnier
2010-09-14 15:45                                       ` Ted Zlatanov
2010-09-13  7:49                                   ` Nikos Mavrogiannopoulos
2010-09-14 18:30                                     ` Ted Zlatanov
2010-09-14 18:55                                       ` Nikos Mavrogiannopoulos
2010-09-14 19:10                                         ` Lars Magne Ingebrigtsen
2010-09-15 11:20                                           ` Ted Zlatanov
2010-09-15  1:25                                         ` Ted Zlatanov
2010-09-15 11:01                                     ` Ted Zlatanov
2010-09-15 12:13                                       ` Nikos Mavrogiannopoulos
2010-09-15 15:40                                         ` Ted Zlatanov
2010-09-26  6:09                                         ` Ted Zlatanov
2010-09-26 15:32                                           ` Lars Magne Ingebrigtsen
2010-09-26 21:50                                           ` James Cloos
2010-09-27 13:37                                             ` Lars Magne Ingebrigtsen
2010-09-27 13:56                                               ` Lars Magne Ingebrigtsen
2010-09-27 14:03                                                 ` Lars Magne Ingebrigtsen
2010-09-27 14:11                                                 ` Lars Magne Ingebrigtsen
2010-09-27 14:21                                                 ` Lars Magne Ingebrigtsen
2010-09-27 14:40                                                   ` Lars Magne Ingebrigtsen
2010-09-27 14:56                                                     ` Ted Zlatanov
2010-09-27 15:13                                                       ` Lars Magne Ingebrigtsen
2010-09-27 15:02                                                     ` Bruce Stephens
2010-09-27 15:07                                                       ` Lars Magne Ingebrigtsen
2010-09-27 15:18                                                         ` Lars Magne Ingebrigtsen
2010-09-27 15:11                                                     ` Ted Zlatanov
2010-09-27 15:14                                                       ` Lars Magne Ingebrigtsen
2010-09-27 14:42                                                 ` Ted Zlatanov
2010-09-29 12:53                                                   ` Lars Magne Ingebrigtsen
2010-09-29 13:25                                                     ` Lars Magne Ingebrigtsen
2010-09-29 18:36                                                       ` Jason Earl
2010-09-29 20:05                                                         ` Ted Zlatanov
2010-09-29 20:32                                                           ` Jason Earl
2010-09-29 20:35                                                             ` Lars Magne Ingebrigtsen
2010-09-29 21:33                                                               ` Jason Earl
2010-09-29 17:06                                                     ` Ted Zlatanov
2010-09-29 17:44                                                       ` Ted Zlatanov
2010-09-29 18:43                                                         ` Lars Magne Ingebrigtsen
2010-09-29 18:43                                                       ` Lars Magne Ingebrigtsen
2010-10-03 14:21                                                       ` Ted Zlatanov
2010-10-03 14:48                                                         ` Ted Zlatanov
2010-10-03 22:37                                                           ` Lars Magne Ingebrigtsen
2010-10-04  1:23                                                             ` final GnuTLS API! (was: Emacs core TLS support) Ted Zlatanov
2010-10-04 10:49                                                               ` final GnuTLS API! Lars Magne Ingebrigtsen
2010-10-04 14:44                                                                 ` Ted Zlatanov
2010-09-27 14:36                                             ` Emacs core TLS support Ted Zlatanov
2010-09-27 18:25                                               ` James Cloos
2010-09-27 18:45                                                 ` Ted Zlatanov
2010-09-27 19:07                                                   ` Lars Magne Ingebrigtsen
2010-09-27 19:38                                                     ` Lars Magne Ingebrigtsen
2010-09-21 11:37                                       ` Simon Josefsson
2010-09-26  6:12                                         ` Ted Zlatanov
2010-09-30 10:10                                           ` Simon Josefsson
2010-10-04  3:42                                             ` Ted Zlatanov
2010-10-04  6:24                                               ` Nikos Mavrogiannopoulos
2010-08-13 13:54             ` Leo
2010-08-13 14:50               ` Ted Zlatanov
2010-08-14 19:20                 ` Leo
  -- strict thread matches above, loose matches on Subject: below --
2010-01-14  1:37 MON KEY

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).