1 /* GnuTLS glue for GNU Emacs.
2 Copyright (C) 2010-2011 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/>. */
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 /* The following are for the property list of `gnutls-boot'. */
36 Lisp_Object Qgnutls_bootprop_priority
;
37 Lisp_Object Qgnutls_bootprop_trustfiles
;
38 Lisp_Object Qgnutls_bootprop_keyfiles
;
39 Lisp_Object Qgnutls_bootprop_callbacks
;
40 Lisp_Object Qgnutls_bootprop_loglevel
;
43 emacs_gnutls_handshake (struct Lisp_Process
*proc
)
45 gnutls_session_t state
= proc
->gnutls_state
;
48 if (proc
->gnutls_initstage
< GNUTLS_STAGE_HANDSHAKE_CANDO
)
51 if (proc
->gnutls_initstage
< GNUTLS_STAGE_TRANSPORT_POINTERS_SET
)
53 /* This is how GnuTLS takes sockets: as file descriptors passed
54 in. For an Emacs process socket, infd and outfd are the
55 same but we use this two-argument version for clarity. */
56 gnutls_transport_set_ptr2 (state
,
57 (gnutls_transport_ptr_t
) (long) proc
->infd
,
58 (gnutls_transport_ptr_t
) (long) proc
->outfd
);
60 proc
->gnutls_initstage
= GNUTLS_STAGE_TRANSPORT_POINTERS_SET
;
63 ret
= gnutls_handshake (state
);
64 proc
->gnutls_initstage
= GNUTLS_STAGE_HANDSHAKE_TRIED
;
66 if (ret
== GNUTLS_E_SUCCESS
)
68 /* here we're finally done. */
69 proc
->gnutls_initstage
= GNUTLS_STAGE_READY
;
74 emacs_gnutls_write (int fildes
, struct Lisp_Process
*proc
, const char *buf
,
78 EMACS_INT bytes_written
;
79 gnutls_session_t state
= proc
->gnutls_state
;
81 if (proc
->gnutls_initstage
!= GNUTLS_STAGE_READY
) {
95 rtnval
= gnutls_write (state
, buf
, nbyte
);
99 if (rtnval
== GNUTLS_E_AGAIN
|| rtnval
== GNUTLS_E_INTERRUPTED
)
107 bytes_written
+= rtnval
;
110 return (bytes_written
);
114 emacs_gnutls_read (int fildes
, struct Lisp_Process
*proc
, char *buf
,
118 gnutls_session_t state
= proc
->gnutls_state
;
120 if (proc
->gnutls_initstage
!= GNUTLS_STAGE_READY
)
122 emacs_gnutls_handshake (proc
);
126 rtnval
= gnutls_read (state
, buf
, nbyte
);
130 if (rtnval
== GNUTLS_E_AGAIN
||
131 rtnval
== GNUTLS_E_INTERRUPTED
)
138 /* convert an integer error to a Lisp_Object; it will be either a
139 known symbol like `gnutls_e_interrupted' and `gnutls_e_again' or
140 simply the integer value of the error. GNUTLS_E_SUCCESS is mapped
143 gnutls_make_error (int err
)
147 case GNUTLS_E_SUCCESS
:
150 return Qgnutls_e_again
;
151 case GNUTLS_E_INTERRUPTED
:
152 return Qgnutls_e_interrupted
;
153 case GNUTLS_E_INVALID_SESSION
:
154 return Qgnutls_e_invalid_session
;
157 return make_number (err
);
160 DEFUN ("gnutls-get-initstage", Fgnutls_get_initstage
, Sgnutls_get_initstage
, 1, 1, 0,
161 doc
: /* Return the GnuTLS init stage of process PROC.
162 See also `gnutls-boot'. */)
165 CHECK_PROCESS (proc
);
167 return make_number (GNUTLS_INITSTAGE (proc
));
170 DEFUN ("gnutls-errorp", Fgnutls_errorp
, Sgnutls_errorp
, 1, 1, 0,
171 doc
: /* Return t if ERROR indicates a GnuTLS problem.
172 ERROR is an integer or a symbol with an integer `gnutls-code' property.
173 usage: (gnutls-errorp ERROR) */)
176 if (EQ (err
, Qt
)) return Qnil
;
181 DEFUN ("gnutls-error-fatalp", Fgnutls_error_fatalp
, Sgnutls_error_fatalp
, 1, 1, 0,
182 doc
: /* Check if ERROR is fatal.
183 ERROR is an integer or a symbol with an integer `gnutls-code' property.
184 usage: (gnutls-error-fatalp ERROR) */)
189 if (EQ (err
, Qt
)) return Qnil
;
193 code
= Fget (err
, Qgnutls_code
);
200 error ("Symbol has no numeric gnutls-code property");
205 error ("Not an error symbol or code");
207 if (0 == gnutls_error_is_fatal (XINT (err
)))
213 DEFUN ("gnutls-error-string", Fgnutls_error_string
, Sgnutls_error_string
, 1, 1, 0,
214 doc
: /* Return a description of ERROR.
215 ERROR is an integer or a symbol with an integer `gnutls-code' property.
216 usage: (gnutls-error-string ERROR) */)
221 if (EQ (err
, Qt
)) return build_string ("Not an error");
225 code
= Fget (err
, Qgnutls_code
);
232 return build_string ("Symbol has no numeric gnutls-code property");
237 return build_string ("Not an error symbol or code");
239 return build_string (gnutls_strerror (XINT (err
)));
242 DEFUN ("gnutls-deinit", Fgnutls_deinit
, Sgnutls_deinit
, 1, 1, 0,
243 doc
: /* Deallocate GnuTLS resources associated with process PROC.
244 See also `gnutls-init'. */)
247 gnutls_session_t state
;
249 CHECK_PROCESS (proc
);
250 state
= XPROCESS (proc
)->gnutls_state
;
252 if (GNUTLS_INITSTAGE (proc
) >= GNUTLS_STAGE_INIT
)
254 gnutls_deinit (state
);
255 GNUTLS_INITSTAGE (proc
) = GNUTLS_STAGE_INIT
- 1;
261 /* Initializes global GnuTLS state to defaults.
262 Call `gnutls-global-deinit' when GnuTLS usage is no longer needed.
263 Returns zero on success. */
265 gnutls_emacs_global_init (void)
267 int ret
= GNUTLS_E_SUCCESS
;
269 if (!global_initialized
)
270 ret
= gnutls_global_init ();
272 global_initialized
= 1;
274 return gnutls_make_error (ret
);
278 /* Deinitializes global GnuTLS state.
279 See also `gnutls-global-init'. */
281 gnutls_emacs_global_deinit (void)
283 if (global_initialized
)
284 gnutls_global_deinit ();
286 global_initialized
= 0;
288 return gnutls_make_error (GNUTLS_E_SUCCESS
);
293 gnutls_log_function (int level
, const char* string
)
295 message ("gnutls.c: [%d] %s", level
, string
);
299 gnutls_log_function2 (int level
, const char* string
, const char* extra
)
301 message ("gnutls.c: [%d] %s %s", level
, string
, extra
);
304 DEFUN ("gnutls-boot", Fgnutls_boot
, Sgnutls_boot
, 3, 3, 0,
305 doc
: /* Initialize GnuTLS client for process PROC with TYPE+PROPLIST.
306 Currently only client mode is supported. Returns a success/failure
307 value you can check with `gnutls-errorp'.
309 TYPE is a symbol, either `gnutls-anon' or `gnutls-x509pki'.
310 PROPLIST is a property list with the following keys:
312 :priority is a GnuTLS priority string, defaults to "NORMAL".
313 :trustfiles is a list of PEM-encoded trust files for `gnutls-x509pki'.
314 :keyfiles is a list of PEM-encoded key files for `gnutls-x509pki'.
315 :callbacks is an alist of callback functions (TODO).
316 :loglevel is the debug level requested from GnuTLS, try 4.
318 The debug level will be set for this process AND globally for GnuTLS.
319 So if you set it higher or lower at any point, it affects global
322 Note that the priority is set on the client. The server does not use
323 the protocols's priority except for disabling protocols that were not
326 Processes must be initialized with this function before other GnuTLS
327 functions are used. This function allocates resources which can only
328 be deallocated by calling `gnutls-deinit' or by calling it again.
330 Each authentication type may need additional information in order to
331 work. For X.509 PKI (`gnutls-x509pki'), you probably need at least
332 one trustfile (usually a CA bundle). */)
333 (Lisp_Object proc
, Lisp_Object type
, Lisp_Object proplist
)
335 int ret
= GNUTLS_E_SUCCESS
;
337 int max_log_level
= 0;
339 /* TODO: GNUTLS_X509_FMT_DER is also an option. */
340 int file_format
= GNUTLS_X509_FMT_PEM
;
342 gnutls_session_t state
;
343 gnutls_certificate_credentials_t x509_cred
;
344 gnutls_anon_client_credentials_t anon_cred
;
345 Lisp_Object global_init
;
346 char const *priority_string_ptr
= "NORMAL"; /* default priority string. */
349 /* Placeholders for the property list elements. */
350 Lisp_Object priority_string
;
351 Lisp_Object trustfiles
;
352 Lisp_Object keyfiles
;
353 /* Lisp_Object callbacks; */
354 Lisp_Object loglevel
;
356 CHECK_PROCESS (proc
);
358 CHECK_LIST (proplist
);
360 priority_string
= Fplist_get (proplist
, Qgnutls_bootprop_priority
);
361 trustfiles
= Fplist_get (proplist
, Qgnutls_bootprop_trustfiles
);
362 keyfiles
= Fplist_get (proplist
, Qgnutls_bootprop_keyfiles
);
363 /* callbacks = Fplist_get (proplist, Qgnutls_bootprop_callbacks); */
364 loglevel
= Fplist_get (proplist
, Qgnutls_bootprop_loglevel
);
366 state
= XPROCESS (proc
)->gnutls_state
;
367 XPROCESS (proc
)->gnutls_p
= 1;
369 if (NUMBERP (loglevel
))
371 gnutls_global_set_log_function (gnutls_log_function
);
372 gnutls_global_set_log_level (XINT (loglevel
));
373 max_log_level
= XINT (loglevel
);
374 XPROCESS (proc
)->gnutls_log_level
= max_log_level
;
377 /* always initialize globals. */
378 global_init
= gnutls_emacs_global_init ();
379 if (! NILP (Fgnutls_errorp (global_init
)))
382 /* deinit and free resources. */
383 if (GNUTLS_INITSTAGE (proc
) >= GNUTLS_STAGE_CRED_ALLOC
)
385 GNUTLS_LOG (1, max_log_level
, "deallocating credentials");
387 if (EQ (type
, Qgnutls_x509pki
))
389 GNUTLS_LOG (2, max_log_level
, "deallocating x509 credentials");
390 x509_cred
= XPROCESS (proc
)->gnutls_x509_cred
;
391 gnutls_certificate_free_credentials (x509_cred
);
393 else if (EQ (type
, Qgnutls_anon
))
395 GNUTLS_LOG (2, max_log_level
, "deallocating anon credentials");
396 anon_cred
= XPROCESS (proc
)->gnutls_anon_cred
;
397 gnutls_anon_free_client_credentials (anon_cred
);
401 error ("unknown credential type");
402 ret
= GNUTLS_EMACS_ERROR_INVALID_TYPE
;
405 if (GNUTLS_INITSTAGE (proc
) >= GNUTLS_STAGE_INIT
)
407 GNUTLS_LOG (1, max_log_level
, "deallocating x509 credentials");
408 Fgnutls_deinit (proc
);
412 GNUTLS_INITSTAGE (proc
) = GNUTLS_STAGE_EMPTY
;
414 GNUTLS_LOG (1, max_log_level
, "allocating credentials");
416 if (EQ (type
, Qgnutls_x509pki
))
418 GNUTLS_LOG (2, max_log_level
, "allocating x509 credentials");
419 x509_cred
= XPROCESS (proc
)->gnutls_x509_cred
;
420 if (gnutls_certificate_allocate_credentials (&x509_cred
) < 0)
423 else if (EQ (type
, Qgnutls_anon
))
425 GNUTLS_LOG (2, max_log_level
, "allocating anon credentials");
426 anon_cred
= XPROCESS (proc
)->gnutls_anon_cred
;
427 if (gnutls_anon_allocate_client_credentials (&anon_cred
) < 0)
432 error ("unknown credential type");
433 ret
= GNUTLS_EMACS_ERROR_INVALID_TYPE
;
436 if (ret
< GNUTLS_E_SUCCESS
)
437 return gnutls_make_error (ret
);
439 GNUTLS_INITSTAGE (proc
) = GNUTLS_STAGE_CRED_ALLOC
;
441 if (EQ (type
, Qgnutls_x509pki
))
443 for (tail
= trustfiles
; !NILP (tail
); tail
= Fcdr (tail
))
445 Lisp_Object trustfile
= Fcar (tail
);
446 if (STRINGP (trustfile
))
448 GNUTLS_LOG2 (1, max_log_level
, "setting the trustfile: ",
450 ret
= gnutls_certificate_set_x509_trust_file
455 if (ret
< GNUTLS_E_SUCCESS
)
456 return gnutls_make_error (ret
);
460 error ("Sorry, GnuTLS can't use non-string trustfile %s",
465 for (tail
= keyfiles
; !NILP (tail
); tail
= Fcdr (tail
))
467 Lisp_Object keyfile
= Fcar (tail
);
468 if (STRINGP (keyfile
))
470 GNUTLS_LOG2 (1, max_log_level
, "setting the keyfile: ",
472 ret
= gnutls_certificate_set_x509_crl_file
477 if (ret
< GNUTLS_E_SUCCESS
)
478 return gnutls_make_error (ret
);
482 error ("Sorry, GnuTLS can't use non-string keyfile %s",
488 GNUTLS_INITSTAGE (proc
) = GNUTLS_STAGE_FILES
;
490 GNUTLS_LOG (1, max_log_level
, "gnutls_init");
492 ret
= gnutls_init (&state
, GNUTLS_CLIENT
);
494 if (ret
< GNUTLS_E_SUCCESS
)
495 return gnutls_make_error (ret
);
497 XPROCESS (proc
)->gnutls_state
= state
;
499 GNUTLS_INITSTAGE (proc
) = GNUTLS_STAGE_INIT
;
501 if (STRINGP (priority_string
))
503 priority_string_ptr
= SSDATA (priority_string
);
504 GNUTLS_LOG2 (1, max_log_level
, "got non-default priority string:",
505 priority_string_ptr
);
509 GNUTLS_LOG2 (1, max_log_level
, "using default priority string:",
510 priority_string_ptr
);
513 GNUTLS_LOG (1, max_log_level
, "setting the priority string");
515 ret
= gnutls_priority_set_direct (state
,
519 if (ret
< GNUTLS_E_SUCCESS
)
520 return gnutls_make_error (ret
);
522 GNUTLS_INITSTAGE (proc
) = GNUTLS_STAGE_PRIORITY
;
524 if (EQ (type
, Qgnutls_x509pki
))
526 ret
= gnutls_cred_set (state
, GNUTLS_CRD_CERTIFICATE
, x509_cred
);
528 else if (EQ (type
, Qgnutls_anon
))
530 ret
= gnutls_cred_set (state
, GNUTLS_CRD_ANON
, anon_cred
);
534 error ("unknown credential type");
535 ret
= GNUTLS_EMACS_ERROR_INVALID_TYPE
;
538 if (ret
< GNUTLS_E_SUCCESS
)
539 return gnutls_make_error (ret
);
541 XPROCESS (proc
)->gnutls_anon_cred
= anon_cred
;
542 XPROCESS (proc
)->gnutls_x509_cred
= x509_cred
;
543 XPROCESS (proc
)->gnutls_cred_type
= type
;
545 GNUTLS_INITSTAGE (proc
) = GNUTLS_STAGE_CRED_SET
;
547 emacs_gnutls_handshake (XPROCESS (proc
));
549 return gnutls_make_error (GNUTLS_E_SUCCESS
);
552 DEFUN ("gnutls-bye", Fgnutls_bye
,
553 Sgnutls_bye
, 2, 2, 0,
554 doc
: /* Terminate current GnuTLS connection for process PROC.
555 The connection should have been initiated using `gnutls-handshake'.
557 If CONT is not nil the TLS connection gets terminated and further
558 receives and sends will be disallowed. If the return value is zero you
559 may continue using the connection. If CONT is nil, GnuTLS actually
560 sends an alert containing a close request and waits for the peer to
561 reply with the same message. In order to reuse the connection you
562 should wait for an EOF from the peer.
564 This function may also return `gnutls-e-again', or
565 `gnutls-e-interrupted'. */)
566 (Lisp_Object proc
, Lisp_Object cont
)
568 gnutls_session_t state
;
571 CHECK_PROCESS (proc
);
573 state
= XPROCESS (proc
)->gnutls_state
;
575 ret
= gnutls_bye (state
,
576 NILP (cont
) ? GNUTLS_SHUT_RDWR
: GNUTLS_SHUT_WR
);
578 return gnutls_make_error (ret
);
582 syms_of_gnutls (void)
584 global_initialized
= 0;
586 Qgnutls_code
= intern_c_string ("gnutls-code");
587 staticpro (&Qgnutls_code
);
589 Qgnutls_anon
= intern_c_string ("gnutls-anon");
590 staticpro (&Qgnutls_anon
);
592 Qgnutls_x509pki
= intern_c_string ("gnutls-x509pki");
593 staticpro (&Qgnutls_x509pki
);
595 Qgnutls_bootprop_priority
= intern_c_string (":priority");
596 staticpro (&Qgnutls_bootprop_priority
);
598 Qgnutls_bootprop_trustfiles
= intern_c_string (":trustfiles");
599 staticpro (&Qgnutls_bootprop_trustfiles
);
601 Qgnutls_bootprop_keyfiles
= intern_c_string (":keyfiles");
602 staticpro (&Qgnutls_bootprop_keyfiles
);
604 Qgnutls_bootprop_callbacks
= intern_c_string (":callbacks");
605 staticpro (&Qgnutls_bootprop_callbacks
);
607 Qgnutls_bootprop_loglevel
= intern_c_string (":loglevel");
608 staticpro (&Qgnutls_bootprop_loglevel
);
610 Qgnutls_e_interrupted
= intern_c_string ("gnutls-e-interrupted");
611 staticpro (&Qgnutls_e_interrupted
);
612 Fput (Qgnutls_e_interrupted
, Qgnutls_code
,
613 make_number (GNUTLS_E_INTERRUPTED
));
615 Qgnutls_e_again
= intern_c_string ("gnutls-e-again");
616 staticpro (&Qgnutls_e_again
);
617 Fput (Qgnutls_e_again
, Qgnutls_code
,
618 make_number (GNUTLS_E_AGAIN
));
620 Qgnutls_e_invalid_session
= intern_c_string ("gnutls-e-invalid-session");
621 staticpro (&Qgnutls_e_invalid_session
);
622 Fput (Qgnutls_e_invalid_session
, Qgnutls_code
,
623 make_number (GNUTLS_E_INVALID_SESSION
));
625 Qgnutls_e_not_ready_for_handshake
=
626 intern_c_string ("gnutls-e-not-ready-for-handshake");
627 staticpro (&Qgnutls_e_not_ready_for_handshake
);
628 Fput (Qgnutls_e_not_ready_for_handshake
, Qgnutls_code
,
629 make_number (GNUTLS_E_APPLICATION_ERROR_MIN
));
631 defsubr (&Sgnutls_get_initstage
);
632 defsubr (&Sgnutls_errorp
);
633 defsubr (&Sgnutls_error_fatalp
);
634 defsubr (&Sgnutls_error_string
);
635 defsubr (&Sgnutls_boot
);
636 defsubr (&Sgnutls_deinit
);
637 defsubr (&Sgnutls_bye
);