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
,
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
)
102 return (bytes_written
? bytes_written
: -1);
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 error
)
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 (error
);
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
);
277 /* Deinitializes global GnuTLS state.
278 See also `gnutls-global-init'. */
280 gnutls_emacs_global_deinit (void)
282 if (global_initialized
)
283 gnutls_global_deinit ();
285 global_initialized
= 0;
287 return gnutls_make_error (GNUTLS_E_SUCCESS
);
291 gnutls_log_function (int level
, const char* string
)
293 message ("gnutls.c: [%d] %s", level
, string
);
297 gnutls_log_function2 (int level
, const char* string
, const char* extra
)
299 message ("gnutls.c: [%d] %s %s", level
, string
, extra
);
302 DEFUN ("gnutls-boot", Fgnutls_boot
, Sgnutls_boot
, 3, 3, 0,
303 doc
: /* Initialize GnuTLS client for process PROC with TYPE+PROPLIST.
304 Currently only client mode is supported. Returns a success/failure
305 value you can check with `gnutls-errorp'.
307 TYPE is a symbol, either `gnutls-anon' or `gnutls-x509pki'.
308 PROPLIST is a property list with the following keys:
310 :priority is a GnuTLS priority string, defaults to "NORMAL".
311 :trustfiles is a list of PEM-encoded trust files for `gnutls-x509pki'.
312 :keyfiles is a list of PEM-encoded key files for `gnutls-x509pki'.
313 :callbacks is an alist of callback functions (TODO).
314 :loglevel is the debug level requested from GnuTLS, try 4.
316 The debug level will be set for this process AND globally for GnuTLS.
317 So if you set it higher or lower at any point, it affects global
320 Note that the priority is set on the client. The server does not use
321 the protocols's priority except for disabling protocols that were not
324 Processes must be initialized with this function before other GnuTLS
325 functions are used. This function allocates resources which can only
326 be deallocated by calling `gnutls-deinit' or by calling it again.
328 Each authentication type may need additional information in order to
329 work. For X.509 PKI (`gnutls-x509pki'), you probably need at least
330 one trustfile (usually a CA bundle). */)
331 (Lisp_Object proc
, Lisp_Object type
, Lisp_Object proplist
)
333 int ret
= GNUTLS_E_SUCCESS
;
335 int max_log_level
= 0;
337 /* TODO: GNUTLS_X509_FMT_DER is also an option. */
338 int file_format
= GNUTLS_X509_FMT_PEM
;
340 gnutls_session_t state
;
341 gnutls_certificate_credentials_t x509_cred
;
342 gnutls_anon_client_credentials_t anon_cred
;
343 Lisp_Object global_init
;
344 char* priority_string_ptr
= "NORMAL"; /* default priority string. */
347 /* Placeholders for the property list elements. */
348 Lisp_Object priority_string
;
349 Lisp_Object trustfiles
;
350 Lisp_Object keyfiles
;
351 Lisp_Object callbacks
;
352 Lisp_Object loglevel
;
354 CHECK_PROCESS (proc
);
356 CHECK_LIST (proplist
);
358 priority_string
= Fplist_get (proplist
, Qgnutls_bootprop_priority
);
359 trustfiles
= Fplist_get (proplist
, Qgnutls_bootprop_trustfiles
);
360 keyfiles
= Fplist_get (proplist
, Qgnutls_bootprop_keyfiles
);
361 callbacks
= Fplist_get (proplist
, Qgnutls_bootprop_callbacks
);
362 loglevel
= Fplist_get (proplist
, Qgnutls_bootprop_loglevel
);
364 state
= XPROCESS (proc
)->gnutls_state
;
365 XPROCESS (proc
)->gnutls_p
= 1;
367 if (NUMBERP (loglevel
))
369 gnutls_global_set_log_function (gnutls_log_function
);
370 gnutls_global_set_log_level (XINT (loglevel
));
371 max_log_level
= XINT (loglevel
);
372 XPROCESS (proc
)->gnutls_log_level
= max_log_level
;
375 /* always initialize globals. */
376 global_init
= gnutls_emacs_global_init ();
377 if (! NILP (Fgnutls_errorp (global_init
)))
380 /* deinit and free resources. */
381 if (GNUTLS_INITSTAGE (proc
) >= GNUTLS_STAGE_CRED_ALLOC
)
383 GNUTLS_LOG (1, max_log_level
, "deallocating credentials");
385 if (EQ (type
, Qgnutls_x509pki
))
387 GNUTLS_LOG (2, max_log_level
, "deallocating x509 credentials");
388 x509_cred
= XPROCESS (proc
)->gnutls_x509_cred
;
389 gnutls_certificate_free_credentials (x509_cred
);
391 else if (EQ (type
, Qgnutls_anon
))
393 GNUTLS_LOG (2, max_log_level
, "deallocating anon credentials");
394 anon_cred
= XPROCESS (proc
)->gnutls_anon_cred
;
395 gnutls_anon_free_client_credentials (anon_cred
);
399 error ("unknown credential type");
400 ret
= GNUTLS_EMACS_ERROR_INVALID_TYPE
;
403 if (GNUTLS_INITSTAGE (proc
) >= GNUTLS_STAGE_INIT
)
405 GNUTLS_LOG (1, max_log_level
, "deallocating x509 credentials");
406 Fgnutls_deinit (proc
);
410 GNUTLS_INITSTAGE (proc
) = GNUTLS_STAGE_EMPTY
;
412 GNUTLS_LOG (1, max_log_level
, "allocating credentials");
414 if (EQ (type
, Qgnutls_x509pki
))
416 GNUTLS_LOG (2, max_log_level
, "allocating x509 credentials");
417 x509_cred
= XPROCESS (proc
)->gnutls_x509_cred
;
418 if (gnutls_certificate_allocate_credentials (&x509_cred
) < 0)
421 else if (EQ (type
, Qgnutls_anon
))
423 GNUTLS_LOG (2, max_log_level
, "allocating anon credentials");
424 anon_cred
= XPROCESS (proc
)->gnutls_anon_cred
;
425 if (gnutls_anon_allocate_client_credentials (&anon_cred
) < 0)
430 error ("unknown credential type");
431 ret
= GNUTLS_EMACS_ERROR_INVALID_TYPE
;
434 if (ret
< GNUTLS_E_SUCCESS
)
435 return gnutls_make_error (ret
);
437 GNUTLS_INITSTAGE (proc
) = GNUTLS_STAGE_CRED_ALLOC
;
439 if (EQ (type
, Qgnutls_x509pki
))
441 for (tail
= trustfiles
; !NILP (tail
); tail
= Fcdr (tail
))
443 Lisp_Object trustfile
= Fcar (tail
);
444 if (STRINGP (trustfile
))
446 GNUTLS_LOG2 (1, max_log_level
, "setting the trustfile: ",
448 ret
= gnutls_certificate_set_x509_trust_file
453 if (ret
< GNUTLS_E_SUCCESS
)
454 return gnutls_make_error (ret
);
458 error ("Sorry, GnuTLS can't use non-string trustfile %s",
463 for (tail
= keyfiles
; !NILP (tail
); tail
= Fcdr (tail
))
465 Lisp_Object keyfile
= Fcar (tail
);
466 if (STRINGP (keyfile
))
468 GNUTLS_LOG2 (1, max_log_level
, "setting the keyfile: ",
470 ret
= gnutls_certificate_set_x509_crl_file
475 if (ret
< GNUTLS_E_SUCCESS
)
476 return gnutls_make_error (ret
);
480 error ("Sorry, GnuTLS can't use non-string keyfile %s",
486 GNUTLS_INITSTAGE (proc
) = GNUTLS_STAGE_FILES
;
488 GNUTLS_LOG (1, max_log_level
, "gnutls_init");
490 ret
= gnutls_init (&state
, GNUTLS_CLIENT
);
492 if (ret
< GNUTLS_E_SUCCESS
)
493 return gnutls_make_error (ret
);
495 XPROCESS (proc
)->gnutls_state
= state
;
497 GNUTLS_INITSTAGE (proc
) = GNUTLS_STAGE_INIT
;
499 if (STRINGP (priority_string
))
501 priority_string_ptr
= SSDATA (priority_string
);
502 GNUTLS_LOG2 (1, max_log_level
, "got non-default priority string:",
503 priority_string_ptr
);
507 GNUTLS_LOG2 (1, max_log_level
, "using default priority string:",
508 priority_string_ptr
);
511 GNUTLS_LOG (1, max_log_level
, "setting the priority string");
513 ret
= gnutls_priority_set_direct (state
,
517 if (ret
< GNUTLS_E_SUCCESS
)
518 return gnutls_make_error (ret
);
520 GNUTLS_INITSTAGE (proc
) = GNUTLS_STAGE_PRIORITY
;
522 if (EQ (type
, Qgnutls_x509pki
))
524 ret
= gnutls_cred_set (state
, GNUTLS_CRD_CERTIFICATE
, x509_cred
);
526 else if (EQ (type
, Qgnutls_anon
))
528 ret
= gnutls_cred_set (state
, GNUTLS_CRD_ANON
, anon_cred
);
532 error ("unknown credential type");
533 ret
= GNUTLS_EMACS_ERROR_INVALID_TYPE
;
536 if (ret
< GNUTLS_E_SUCCESS
)
537 return gnutls_make_error (ret
);
539 XPROCESS (proc
)->gnutls_anon_cred
= anon_cred
;
540 XPROCESS (proc
)->gnutls_x509_cred
= x509_cred
;
541 XPROCESS (proc
)->gnutls_cred_type
= type
;
543 GNUTLS_INITSTAGE (proc
) = GNUTLS_STAGE_CRED_SET
;
545 emacs_gnutls_handshake (XPROCESS (proc
));
547 return gnutls_make_error (GNUTLS_E_SUCCESS
);
550 DEFUN ("gnutls-bye", Fgnutls_bye
,
551 Sgnutls_bye
, 2, 2, 0,
552 doc
: /* Terminate current GnuTLS connection for process PROC.
553 The connection should have been initiated using `gnutls-handshake'.
555 If CONT is not nil the TLS connection gets terminated and further
556 receives and sends will be disallowed. If the return value is zero you
557 may continue using the connection. If CONT is nil, GnuTLS actually
558 sends an alert containing a close request and waits for the peer to
559 reply with the same message. In order to reuse the connection you
560 should wait for an EOF from the peer.
562 This function may also return `gnutls-e-again', or
563 `gnutls-e-interrupted'. */)
564 (Lisp_Object proc
, Lisp_Object cont
)
566 gnutls_session_t state
;
569 CHECK_PROCESS (proc
);
571 state
= XPROCESS (proc
)->gnutls_state
;
573 ret
= gnutls_bye (state
,
574 NILP (cont
) ? GNUTLS_SHUT_RDWR
: GNUTLS_SHUT_WR
);
576 return gnutls_make_error (ret
);
580 syms_of_gnutls (void)
582 global_initialized
= 0;
584 Qgnutls_code
= intern_c_string ("gnutls-code");
585 staticpro (&Qgnutls_code
);
587 Qgnutls_anon
= intern_c_string ("gnutls-anon");
588 staticpro (&Qgnutls_anon
);
590 Qgnutls_x509pki
= intern_c_string ("gnutls-x509pki");
591 staticpro (&Qgnutls_x509pki
);
593 Qgnutls_bootprop_priority
= intern_c_string (":priority");
594 staticpro (&Qgnutls_bootprop_priority
);
596 Qgnutls_bootprop_trustfiles
= intern_c_string (":trustfiles");
597 staticpro (&Qgnutls_bootprop_trustfiles
);
599 Qgnutls_bootprop_keyfiles
= intern_c_string (":keyfiles");
600 staticpro (&Qgnutls_bootprop_keyfiles
);
602 Qgnutls_bootprop_callbacks
= intern_c_string (":callbacks");
603 staticpro (&Qgnutls_bootprop_callbacks
);
605 Qgnutls_bootprop_loglevel
= intern_c_string (":loglevel");
606 staticpro (&Qgnutls_bootprop_loglevel
);
608 Qgnutls_e_interrupted
= intern_c_string ("gnutls-e-interrupted");
609 staticpro (&Qgnutls_e_interrupted
);
610 Fput (Qgnutls_e_interrupted
, Qgnutls_code
,
611 make_number (GNUTLS_E_INTERRUPTED
));
613 Qgnutls_e_again
= intern_c_string ("gnutls-e-again");
614 staticpro (&Qgnutls_e_again
);
615 Fput (Qgnutls_e_again
, Qgnutls_code
,
616 make_number (GNUTLS_E_AGAIN
));
618 Qgnutls_e_invalid_session
= intern_c_string ("gnutls-e-invalid-session");
619 staticpro (&Qgnutls_e_invalid_session
);
620 Fput (Qgnutls_e_invalid_session
, Qgnutls_code
,
621 make_number (GNUTLS_E_INVALID_SESSION
));
623 Qgnutls_e_not_ready_for_handshake
=
624 intern_c_string ("gnutls-e-not-ready-for-handshake");
625 staticpro (&Qgnutls_e_not_ready_for_handshake
);
626 Fput (Qgnutls_e_not_ready_for_handshake
, Qgnutls_code
,
627 make_number (GNUTLS_E_APPLICATION_ERROR_MIN
));
629 defsubr (&Sgnutls_get_initstage
);
630 defsubr (&Sgnutls_errorp
);
631 defsubr (&Sgnutls_error_fatalp
);
632 defsubr (&Sgnutls_error_string
);
633 defsubr (&Sgnutls_boot
);
634 defsubr (&Sgnutls_deinit
);
635 defsubr (&Sgnutls_bye
);