Emacs core TLS support
Stefan Monnier
monnier at iro.umontreal.ca
Mon Sep 6 00:47:39 CEST 2010
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
More information about the Gnutls-devel
mailing list