* 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-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-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: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: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: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: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: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-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 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-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-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 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-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-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-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 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-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-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 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-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-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 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: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 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 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: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 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 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: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 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 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-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 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 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: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: 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
* 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: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-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-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: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-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: 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 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-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
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 external index https://git.savannah.gnu.org/cgit/emacs.git https://git.savannah.gnu.org/cgit/emacs/org-mode.git This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.