Rework the gnutls boot interface.
From Teodor Zlatanov.
This commit is contained in:
parent
5589b70e57
commit
c1ae068bbb
5 changed files with 157 additions and 55 deletions
|
@ -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 Glenn Morris <rgm@gnu.org>
|
||||
|
||||
* subr.el (directory-sep-char): Remove obsolete variable.
|
||||
|
|
|
@ -57,34 +57,36 @@ 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)))
|
||||
(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))
|
||||
|
|
|
@ -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 Glenn Morris <rgm@gnu.org>
|
||||
|
||||
* fileio.c (Vdirectory_sep_char): Remove.
|
||||
|
|
153
src/gnutls.c
153
src/gnutls.c
|
@ -32,6 +32,13 @@ Lisp_Object Qgnutls_e_interrupted, Qgnutls_e_again,
|
|||
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 @@ emacs_gnutls_handshake (struct Lisp_Process *proc)
|
|||
|
||||
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 @@ gnutls_log_function (int level, const char* string)
|
|||
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.
|
||||
TYPE is a symbol, either `gnutls-anon' or `gnutls-x509pki'.
|
||||
PROPLIST is a property list with the following keys:
|
||||
|
||||
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.
|
||||
: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 @@ 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,
|
||||
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 @@ KEYFILE and optionally CALLBACK. */)
|
|||
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 @@ KEYFILE and optionally CALLBACK. */)
|
|||
|
||||
if (EQ (type, Qgnutls_x509pki))
|
||||
{
|
||||
if (STRINGP (trustfile))
|
||||
for (tail = trustfiles; !NILP (tail); tail = Fcdr (tail))
|
||||
{
|
||||
GNUTLS_LOG (1, max_log_level, "setting the trustfile");
|
||||
ret = gnutls_certificate_set_x509_trust_file
|
||||
(x509_cred,
|
||||
SDATA (trustfile),
|
||||
file_format);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret < GNUTLS_E_SUCCESS)
|
||||
return gnutls_make_error (ret);
|
||||
}
|
||||
|
||||
if (STRINGP (keyfile))
|
||||
for (tail = keyfiles; !NILP (tail); tail = Fcdr (tail))
|
||||
{
|
||||
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);
|
||||
}
|
||||
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 @@ KEYFILE and optionally CALLBACK. */)
|
|||
|
||||
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 @@ syms_of_gnutls (void)
|
|||
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,
|
||||
|
|
|
@ -48,6 +48,8 @@ typedef enum
|
|||
|
||||
#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);
|
||||
|
|
Loading…
Add table
Reference in a new issue