src/gnutls.c: Doc fixes. Make some functions static.
[emacs.git] / src / gnutls.c
blobd49f0b27655c78b4d101ae84ef29332ff7a57a6a
1 /* GnuTLS glue for GNU Emacs.
2 Copyright (C) 2010 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
19 #include <config.h>
20 #include <errno.h>
21 #include <setjmp.h>
23 #include "lisp.h"
24 #include "process.h"
26 #ifdef HAVE_GNUTLS
27 #include <gnutls/gnutls.h>
29 Lisp_Object Qgnutls_code;
30 Lisp_Object Qgnutls_anon, Qgnutls_x509pki;
31 Lisp_Object Qgnutls_e_interrupted, Qgnutls_e_again,
32 Qgnutls_e_invalid_session, Qgnutls_e_not_ready_for_handshake;
33 int global_initialized;
35 static void
36 emacs_gnutls_handshake (struct Lisp_Process *proc)
38 gnutls_session_t state = proc->gnutls_state;
39 int ret;
41 if (proc->gnutls_initstage < GNUTLS_STAGE_HANDSHAKE_CANDO)
42 return;
44 if (proc->gnutls_initstage < GNUTLS_STAGE_TRANSPORT_POINTERS_SET)
46 gnutls_transport_set_ptr2 (state,
47 (gnutls_transport_ptr_t) (long) proc->infd,
48 (gnutls_transport_ptr_t) (long) proc->outfd);
50 proc->gnutls_initstage = GNUTLS_STAGE_TRANSPORT_POINTERS_SET;
53 ret = gnutls_handshake (state);
54 proc->gnutls_initstage = GNUTLS_STAGE_HANDSHAKE_TRIED;
56 if (ret == GNUTLS_E_SUCCESS)
58 /* here we're finally done. */
59 proc->gnutls_initstage = GNUTLS_STAGE_READY;
63 int
64 emacs_gnutls_write (int fildes, struct Lisp_Process *proc, char *buf,
65 unsigned int nbyte)
67 register int rtnval, bytes_written;
68 gnutls_session_t state = proc->gnutls_state;
70 if (proc->gnutls_initstage != GNUTLS_STAGE_READY)
71 return -1;
73 bytes_written = 0;
75 while (nbyte > 0)
77 rtnval = gnutls_write (state, buf, nbyte);
79 if (rtnval == -1)
81 if (errno == EINTR)
82 continue;
83 else
84 return (bytes_written ? bytes_written : -1);
87 buf += rtnval;
88 nbyte -= rtnval;
89 bytes_written += rtnval;
91 fsync (STDOUT_FILENO);
93 return (bytes_written);
96 int
97 emacs_gnutls_read (int fildes, struct Lisp_Process *proc, char *buf,
98 unsigned int nbyte)
100 register int rtnval;
101 gnutls_session_t state = proc->gnutls_state;
103 if (proc->gnutls_initstage != GNUTLS_STAGE_READY)
105 emacs_gnutls_handshake (proc);
106 return -1;
109 rtnval = gnutls_read (state, buf, nbyte);
110 if (rtnval >= 0)
111 return rtnval;
112 else
113 return 0;
116 /* convert an integer error to a Lisp_Object; it will be either a
117 known symbol like `gnutls_e_interrupted' and `gnutls_e_again' or
118 simply the integer value of the error. GNUTLS_E_SUCCESS is mapped
119 to Qt. */
120 static Lisp_Object
121 gnutls_make_error (int error)
123 switch (error)
125 case GNUTLS_E_SUCCESS:
126 return Qt;
127 case GNUTLS_E_AGAIN:
128 return Qgnutls_e_again;
129 case GNUTLS_E_INTERRUPTED:
130 return Qgnutls_e_interrupted;
131 case GNUTLS_E_INVALID_SESSION:
132 return Qgnutls_e_invalid_session;
135 return make_number (error);
138 DEFUN ("gnutls-get-initstage", Fgnutls_get_initstage, Sgnutls_get_initstage, 1, 1, 0,
139 doc: /* Return the GnuTLS init stage of process PROC.
140 See also `gnutls-boot'. */)
141 (Lisp_Object proc)
143 CHECK_PROCESS (proc);
145 return make_number (GNUTLS_INITSTAGE (proc));
148 DEFUN ("gnutls-errorp", Fgnutls_errorp, Sgnutls_errorp, 1, 1, 0,
149 doc: /* Return t if ERROR indicates a GnuTLS problem.
150 ERROR is an integer or a symbol with an integer `gnutls-code' property.
151 usage: (gnutls-errorp ERROR) */)
152 (Lisp_Object err)
154 if (EQ (err, Qt)) return Qnil;
156 return Qt;
159 DEFUN ("gnutls-error-fatalp", Fgnutls_error_fatalp, Sgnutls_error_fatalp, 1, 1, 0,
160 doc: /* Check if ERROR is fatal.
161 ERROR is an integer or a symbol with an integer `gnutls-code' property.
162 usage: (gnutls-error-fatalp ERROR) */)
163 (Lisp_Object err)
165 Lisp_Object code;
167 if (EQ (err, Qt)) return Qnil;
169 if (SYMBOLP (err))
171 code = Fget (err, Qgnutls_code);
172 if (NUMBERP (code))
174 err = code;
176 else
178 error ("Symbol has no numeric gnutls-code property");
182 if (!NUMBERP (err))
183 error ("Not an error symbol or code");
185 if (0 == gnutls_error_is_fatal (XINT (err)))
186 return Qnil;
188 return Qt;
191 DEFUN ("gnutls-error-string", Fgnutls_error_string, Sgnutls_error_string, 1, 1, 0,
192 doc: /* Return a description of ERROR.
193 ERROR is an integer or a symbol with an integer `gnutls-code' property.
194 usage: (gnutls-error-string ERROR) */)
195 (Lisp_Object err)
197 Lisp_Object code;
199 if (EQ (err, Qt)) return build_string ("Not an error");
201 if (SYMBOLP (err))
203 code = Fget (err, Qgnutls_code);
204 if (NUMBERP (code))
206 err = code;
208 else
210 return build_string ("Symbol has no numeric gnutls-code property");
214 if (!NUMBERP (err))
215 return build_string ("Not an error symbol or code");
217 return build_string (gnutls_strerror (XINT (err)));
220 DEFUN ("gnutls-deinit", Fgnutls_deinit, Sgnutls_deinit, 1, 1, 0,
221 doc: /* Deallocate GNU TLS resources associated with process PROC.
222 See also `gnutls-init'. */)
223 (Lisp_Object proc)
225 gnutls_session_t state;
227 CHECK_PROCESS (proc);
228 state = XPROCESS (proc)->gnutls_state;
230 if (GNUTLS_INITSTAGE (proc) >= GNUTLS_STAGE_INIT)
232 gnutls_deinit (state);
233 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_INIT - 1;
236 return Qt;
239 /* Initializes global GNU TLS state to defaults.
240 Call `gnutls-global-deinit' when GNU TLS usage is no longer needed.
241 Returns zero on success. */
242 static Lisp_Object
243 gnutls_emacs_global_init (void)
245 int ret = GNUTLS_E_SUCCESS;
247 if (!global_initialized)
248 ret = gnutls_global_init ();
250 global_initialized = 1;
252 return gnutls_make_error (ret);
255 /* Deinitializes global GNU TLS state.
256 See also `gnutls-global-init'. */
257 static Lisp_Object
258 gnutls_emacs_global_deinit (void)
260 if (global_initialized)
261 gnutls_global_deinit ();
263 global_initialized = 0;
265 return gnutls_make_error (GNUTLS_E_SUCCESS);
268 static void
269 gnutls_log_function (int level, const char* string)
271 message ("gnutls.c: [%d] %s", level, string);
274 DEFUN ("gnutls-boot", Fgnutls_boot, Sgnutls_boot, 3, 7, 0,
275 doc: /* Initialize client-mode GnuTLS for process PROC.
276 Currently only client mode is supported. Returns a success/failure
277 value you can check with `gnutls-errorp'.
279 PRIORITY-STRING is a string describing the priority.
280 TYPE is either `gnutls-anon' or `gnutls-x509pki'.
281 TRUSTFILE is a PEM encoded trust file for `gnutls-x509pki'.
282 KEYFILE is ... for `gnutls-x509pki' (TODO).
283 CALLBACK is ... for `gnutls-x509pki' (TODO).
284 LOGLEVEL is the debug level requested from GnuTLS, try 4.
286 LOGLEVEL will be set for this process AND globally for GnuTLS. So if
287 you set it higher or lower at any point, it affects global debugging.
289 Note that the priority is set on the client. The server does not use
290 the protocols's priority except for disabling protocols that were not
291 specified.
293 Processes must be initialized with this function before other GnuTLS
294 functions are used. This function allocates resources which can only
295 be deallocated by calling `gnutls-deinit' or by calling it again.
297 Each authentication type may need additional information in order to
298 work. For X.509 PKI (`gnutls-x509pki'), you need TRUSTFILE and
299 KEYFILE and optionally CALLBACK. */)
300 (Lisp_Object proc, Lisp_Object priority_string, Lisp_Object type,
301 Lisp_Object trustfile, Lisp_Object keyfile, Lisp_Object callback,
302 Lisp_Object loglevel)
304 int ret = GNUTLS_E_SUCCESS;
306 int max_log_level = 0;
308 /* TODO: GNUTLS_X509_FMT_DER is also an option. */
309 int file_format = GNUTLS_X509_FMT_PEM;
311 gnutls_session_t state;
312 gnutls_certificate_credentials_t x509_cred;
313 gnutls_anon_client_credentials_t anon_cred;
314 Lisp_Object global_init;
316 CHECK_PROCESS (proc);
317 CHECK_SYMBOL (type);
318 CHECK_STRING (priority_string);
320 state = XPROCESS (proc)->gnutls_state;
321 XPROCESS (proc)->gnutls_p = 1;
323 if (NUMBERP (loglevel))
325 gnutls_global_set_log_function (gnutls_log_function);
326 gnutls_global_set_log_level (XINT (loglevel));
327 max_log_level = XINT (loglevel);
328 XPROCESS (proc)->gnutls_log_level = max_log_level;
331 /* always initialize globals. */
332 global_init = gnutls_emacs_global_init ();
333 if (! NILP (Fgnutls_errorp (global_init)))
334 return global_init;
336 /* deinit and free resources. */
337 if (GNUTLS_INITSTAGE (proc) >= GNUTLS_STAGE_CRED_ALLOC)
339 GNUTLS_LOG (1, max_log_level, "deallocating credentials");
341 if (EQ (type, Qgnutls_x509pki))
343 GNUTLS_LOG (2, max_log_level, "deallocating x509 credentials");
344 x509_cred = XPROCESS (proc)->gnutls_x509_cred;
345 gnutls_certificate_free_credentials (x509_cred);
347 else if (EQ (type, Qgnutls_anon))
349 GNUTLS_LOG (2, max_log_level, "deallocating anon credentials");
350 anon_cred = XPROCESS (proc)->gnutls_anon_cred;
351 gnutls_anon_free_client_credentials (anon_cred);
353 else
355 error ("unknown credential type");
356 ret = GNUTLS_EMACS_ERROR_INVALID_TYPE;
359 if (GNUTLS_INITSTAGE (proc) >= GNUTLS_STAGE_INIT)
361 GNUTLS_LOG (1, max_log_level, "deallocating x509 credentials");
362 Fgnutls_deinit (proc);
366 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_EMPTY;
368 GNUTLS_LOG (1, max_log_level, "allocating credentials");
370 if (EQ (type, Qgnutls_x509pki))
372 GNUTLS_LOG (2, max_log_level, "allocating x509 credentials");
373 x509_cred = XPROCESS (proc)->gnutls_x509_cred;
374 if (gnutls_certificate_allocate_credentials (&x509_cred) < 0)
375 memory_full ();
377 else if (EQ (type, Qgnutls_anon))
379 GNUTLS_LOG (2, max_log_level, "allocating anon credentials");
380 anon_cred = XPROCESS (proc)->gnutls_anon_cred;
381 if (gnutls_anon_allocate_client_credentials (&anon_cred) < 0)
382 memory_full ();
384 else
386 error ("unknown credential type");
387 ret = GNUTLS_EMACS_ERROR_INVALID_TYPE;
390 if (ret < GNUTLS_E_SUCCESS)
391 return gnutls_make_error (ret);
393 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_CRED_ALLOC;
395 if (EQ (type, Qgnutls_x509pki))
397 if (STRINGP (trustfile))
399 GNUTLS_LOG (1, max_log_level, "setting the trustfile");
400 ret = gnutls_certificate_set_x509_trust_file
401 (x509_cred,
402 SDATA (trustfile),
403 file_format);
405 if (ret < GNUTLS_E_SUCCESS)
406 return gnutls_make_error (ret);
409 if (STRINGP (keyfile))
411 GNUTLS_LOG (1, max_log_level, "setting the keyfile");
412 ret = gnutls_certificate_set_x509_crl_file
413 (x509_cred,
414 SDATA (keyfile),
415 file_format);
417 if (ret < GNUTLS_E_SUCCESS)
418 return gnutls_make_error (ret);
422 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_FILES;
424 GNUTLS_LOG (1, max_log_level, "gnutls_init");
426 ret = gnutls_init (&state, GNUTLS_CLIENT);
428 if (ret < GNUTLS_E_SUCCESS)
429 return gnutls_make_error (ret);
431 XPROCESS (proc)->gnutls_state = state;
433 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_INIT;
435 GNUTLS_LOG (1, max_log_level, "setting the priority string");
437 ret = gnutls_priority_set_direct (state,
438 (char*) SDATA (priority_string),
439 NULL);
441 if (ret < GNUTLS_E_SUCCESS)
442 return gnutls_make_error (ret);
444 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_PRIORITY;
446 if (EQ (type, Qgnutls_x509pki))
448 ret = gnutls_cred_set (state, GNUTLS_CRD_CERTIFICATE, x509_cred);
450 else if (EQ (type, Qgnutls_anon))
452 ret = gnutls_cred_set (state, GNUTLS_CRD_ANON, anon_cred);
454 else
456 error ("unknown credential type");
457 ret = GNUTLS_EMACS_ERROR_INVALID_TYPE;
460 if (ret < GNUTLS_E_SUCCESS)
461 return gnutls_make_error (ret);
463 XPROCESS (proc)->gnutls_anon_cred = anon_cred;
464 XPROCESS (proc)->gnutls_x509_cred = x509_cred;
465 XPROCESS (proc)->gnutls_cred_type = type;
467 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_CRED_SET;
469 emacs_gnutls_handshake (XPROCESS (proc));
471 return gnutls_make_error (GNUTLS_E_SUCCESS);
474 DEFUN ("gnutls-bye", Fgnutls_bye,
475 Sgnutls_bye, 2, 2, 0,
476 doc: /* Terminate current GnuTLS connection for process PROC.
477 The connection should have been initiated using `gnutls-handshake'.
479 If CONT is not nil the TLS connection gets terminated and further
480 receives and sends will be disallowed. If the return value is zero you
481 may continue using the connection. If CONT is nil, GnuTLS actually
482 sends an alert containing a close request and waits for the peer to
483 reply with the same message. In order to reuse the connection you
484 should wait for an EOF from the peer.
486 This function may also return `gnutls-e-again', or
487 `gnutls-e-interrupted'. */)
488 (Lisp_Object proc, Lisp_Object cont)
490 gnutls_session_t state;
491 int ret;
493 CHECK_PROCESS (proc);
495 state = XPROCESS (proc)->gnutls_state;
497 ret = gnutls_bye (state,
498 NILP (cont) ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR);
500 return gnutls_make_error (ret);
503 void
504 syms_of_gnutls (void)
506 global_initialized = 0;
508 Qgnutls_code = intern_c_string ("gnutls-code");
509 staticpro (&Qgnutls_code);
511 Qgnutls_anon = intern_c_string ("gnutls-anon");
512 staticpro (&Qgnutls_anon);
514 Qgnutls_x509pki = intern_c_string ("gnutls-x509pki");
515 staticpro (&Qgnutls_x509pki);
517 Qgnutls_e_interrupted = intern_c_string ("gnutls-e-interrupted");
518 staticpro (&Qgnutls_e_interrupted);
519 Fput (Qgnutls_e_interrupted, Qgnutls_code,
520 make_number (GNUTLS_E_INTERRUPTED));
522 Qgnutls_e_again = intern_c_string ("gnutls-e-again");
523 staticpro (&Qgnutls_e_again);
524 Fput (Qgnutls_e_again, Qgnutls_code,
525 make_number (GNUTLS_E_AGAIN));
527 Qgnutls_e_invalid_session = intern_c_string ("gnutls-e-invalid-session");
528 staticpro (&Qgnutls_e_invalid_session);
529 Fput (Qgnutls_e_invalid_session, Qgnutls_code,
530 make_number (GNUTLS_E_INVALID_SESSION));
532 Qgnutls_e_not_ready_for_handshake =
533 intern_c_string ("gnutls-e-not-ready-for-handshake");
534 staticpro (&Qgnutls_e_not_ready_for_handshake);
535 Fput (Qgnutls_e_not_ready_for_handshake, Qgnutls_code,
536 make_number (GNUTLS_E_APPLICATION_ERROR_MIN));
538 defsubr (&Sgnutls_get_initstage);
539 defsubr (&Sgnutls_errorp);
540 defsubr (&Sgnutls_error_fatalp);
541 defsubr (&Sgnutls_error_string);
542 defsubr (&Sgnutls_boot);
543 defsubr (&Sgnutls_deinit);
544 defsubr (&Sgnutls_bye);
546 #endif