Fix bug #8487 with invisible text at EOB under bidi.
[bpt/emacs.git] / src / gnutls.c
1 /* GnuTLS glue for GNU Emacs.
2 Copyright (C) 2010-2011 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
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.
10
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.
15
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/>. */
18
19 #include <config.h>
20 #include <errno.h>
21 #include <setjmp.h>
22
23 #include "lisp.h"
24 #include "process.h"
25
26 #ifdef HAVE_GNUTLS
27 #include <gnutls/gnutls.h>
28
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;
34
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;
41
42 static void
43 emacs_gnutls_handshake (struct Lisp_Process *proc)
44 {
45 gnutls_session_t state = proc->gnutls_state;
46 int ret;
47
48 if (proc->gnutls_initstage < GNUTLS_STAGE_HANDSHAKE_CANDO)
49 return;
50
51 if (proc->gnutls_initstage < GNUTLS_STAGE_TRANSPORT_POINTERS_SET)
52 {
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);
59
60 proc->gnutls_initstage = GNUTLS_STAGE_TRANSPORT_POINTERS_SET;
61 }
62
63 ret = gnutls_handshake (state);
64 proc->gnutls_initstage = GNUTLS_STAGE_HANDSHAKE_TRIED;
65
66 if (ret == GNUTLS_E_SUCCESS)
67 {
68 /* here we're finally done. */
69 proc->gnutls_initstage = GNUTLS_STAGE_READY;
70 }
71 }
72
73 ssize_t
74 emacs_gnutls_write (int fildes, struct Lisp_Process *proc, const char *buf,
75 size_t nbyte)
76 {
77 ssize_t rtnval;
78 size_t bytes_written;
79 gnutls_session_t state = proc->gnutls_state;
80
81 if (proc->gnutls_initstage != GNUTLS_STAGE_READY) {
82 #ifdef EWOULDBLOCK
83 errno = EWOULDBLOCK;
84 #endif
85 #ifdef EAGAIN
86 errno = EAGAIN;
87 #endif
88 return -1;
89 }
90
91 bytes_written = 0;
92
93 while (nbyte > 0)
94 {
95 rtnval = gnutls_write (state, buf, nbyte);
96
97 if (rtnval < 0)
98 {
99 if (rtnval == GNUTLS_E_AGAIN || rtnval == GNUTLS_E_INTERRUPTED)
100 continue;
101 else
102 return (bytes_written ? bytes_written : -1);
103 }
104
105 buf += rtnval;
106 nbyte -= rtnval;
107 bytes_written += rtnval;
108 }
109
110 return (bytes_written);
111 }
112
113 ssize_t
114 emacs_gnutls_read (int fildes, struct Lisp_Process *proc, char *buf,
115 size_t nbyte)
116 {
117 ssize_t rtnval;
118 gnutls_session_t state = proc->gnutls_state;
119
120 if (proc->gnutls_initstage != GNUTLS_STAGE_READY)
121 {
122 emacs_gnutls_handshake (proc);
123 return -1;
124 }
125
126 rtnval = gnutls_read (state, buf, nbyte);
127 if (rtnval >= 0)
128 return rtnval;
129 else {
130 if (rtnval == GNUTLS_E_AGAIN ||
131 rtnval == GNUTLS_E_INTERRUPTED)
132 return -1;
133 else
134 return 0;
135 }
136 }
137
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
141 to Qt. */
142 static Lisp_Object
143 gnutls_make_error (int error)
144 {
145 switch (error)
146 {
147 case GNUTLS_E_SUCCESS:
148 return Qt;
149 case GNUTLS_E_AGAIN:
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;
155 }
156
157 return make_number (error);
158 }
159
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'. */)
163 (Lisp_Object proc)
164 {
165 CHECK_PROCESS (proc);
166
167 return make_number (GNUTLS_INITSTAGE (proc));
168 }
169
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) */)
174 (Lisp_Object err)
175 {
176 if (EQ (err, Qt)) return Qnil;
177
178 return Qt;
179 }
180
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) */)
185 (Lisp_Object err)
186 {
187 Lisp_Object code;
188
189 if (EQ (err, Qt)) return Qnil;
190
191 if (SYMBOLP (err))
192 {
193 code = Fget (err, Qgnutls_code);
194 if (NUMBERP (code))
195 {
196 err = code;
197 }
198 else
199 {
200 error ("Symbol has no numeric gnutls-code property");
201 }
202 }
203
204 if (!NUMBERP (err))
205 error ("Not an error symbol or code");
206
207 if (0 == gnutls_error_is_fatal (XINT (err)))
208 return Qnil;
209
210 return Qt;
211 }
212
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) */)
217 (Lisp_Object err)
218 {
219 Lisp_Object code;
220
221 if (EQ (err, Qt)) return build_string ("Not an error");
222
223 if (SYMBOLP (err))
224 {
225 code = Fget (err, Qgnutls_code);
226 if (NUMBERP (code))
227 {
228 err = code;
229 }
230 else
231 {
232 return build_string ("Symbol has no numeric gnutls-code property");
233 }
234 }
235
236 if (!NUMBERP (err))
237 return build_string ("Not an error symbol or code");
238
239 return build_string (gnutls_strerror (XINT (err)));
240 }
241
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'. */)
245 (Lisp_Object proc)
246 {
247 gnutls_session_t state;
248
249 CHECK_PROCESS (proc);
250 state = XPROCESS (proc)->gnutls_state;
251
252 if (GNUTLS_INITSTAGE (proc) >= GNUTLS_STAGE_INIT)
253 {
254 gnutls_deinit (state);
255 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_INIT - 1;
256 }
257
258 return Qt;
259 }
260
261 /* Initializes global GnuTLS state to defaults.
262 Call `gnutls-global-deinit' when GnuTLS usage is no longer needed.
263 Returns zero on success. */
264 static Lisp_Object
265 gnutls_emacs_global_init (void)
266 {
267 int ret = GNUTLS_E_SUCCESS;
268
269 if (!global_initialized)
270 ret = gnutls_global_init ();
271
272 global_initialized = 1;
273
274 return gnutls_make_error (ret);
275 }
276
277 /* Deinitializes global GnuTLS state.
278 See also `gnutls-global-init'. */
279 static Lisp_Object
280 gnutls_emacs_global_deinit (void)
281 {
282 if (global_initialized)
283 gnutls_global_deinit ();
284
285 global_initialized = 0;
286
287 return gnutls_make_error (GNUTLS_E_SUCCESS);
288 }
289
290 static void
291 gnutls_log_function (int level, const char* string)
292 {
293 message ("gnutls.c: [%d] %s", level, string);
294 }
295
296 static void
297 gnutls_log_function2 (int level, const char* string, const char* extra)
298 {
299 message ("gnutls.c: [%d] %s %s", level, string, extra);
300 }
301
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'.
306
307 TYPE is a symbol, either `gnutls-anon' or `gnutls-x509pki'.
308 PROPLIST is a property list with the following keys:
309
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.
315
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
318 debugging.
319
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
322 specified.
323
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.
327
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)
332 {
333 int ret = GNUTLS_E_SUCCESS;
334
335 int max_log_level = 0;
336
337 /* TODO: GNUTLS_X509_FMT_DER is also an option. */
338 int file_format = GNUTLS_X509_FMT_PEM;
339
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. */
345 Lisp_Object tail;
346
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;
353
354 CHECK_PROCESS (proc);
355 CHECK_SYMBOL (type);
356 CHECK_LIST (proplist);
357
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);
363
364 state = XPROCESS (proc)->gnutls_state;
365 XPROCESS (proc)->gnutls_p = 1;
366
367 if (NUMBERP (loglevel))
368 {
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;
373 }
374
375 /* always initialize globals. */
376 global_init = gnutls_emacs_global_init ();
377 if (! NILP (Fgnutls_errorp (global_init)))
378 return global_init;
379
380 /* deinit and free resources. */
381 if (GNUTLS_INITSTAGE (proc) >= GNUTLS_STAGE_CRED_ALLOC)
382 {
383 GNUTLS_LOG (1, max_log_level, "deallocating credentials");
384
385 if (EQ (type, Qgnutls_x509pki))
386 {
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);
390 }
391 else if (EQ (type, Qgnutls_anon))
392 {
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);
396 }
397 else
398 {
399 error ("unknown credential type");
400 ret = GNUTLS_EMACS_ERROR_INVALID_TYPE;
401 }
402
403 if (GNUTLS_INITSTAGE (proc) >= GNUTLS_STAGE_INIT)
404 {
405 GNUTLS_LOG (1, max_log_level, "deallocating x509 credentials");
406 Fgnutls_deinit (proc);
407 }
408 }
409
410 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_EMPTY;
411
412 GNUTLS_LOG (1, max_log_level, "allocating credentials");
413
414 if (EQ (type, Qgnutls_x509pki))
415 {
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)
419 memory_full ();
420 }
421 else if (EQ (type, Qgnutls_anon))
422 {
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)
426 memory_full ();
427 }
428 else
429 {
430 error ("unknown credential type");
431 ret = GNUTLS_EMACS_ERROR_INVALID_TYPE;
432 }
433
434 if (ret < GNUTLS_E_SUCCESS)
435 return gnutls_make_error (ret);
436
437 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_CRED_ALLOC;
438
439 if (EQ (type, Qgnutls_x509pki))
440 {
441 for (tail = trustfiles; !NILP (tail); tail = Fcdr (tail))
442 {
443 Lisp_Object trustfile = Fcar (tail);
444 if (STRINGP (trustfile))
445 {
446 GNUTLS_LOG2 (1, max_log_level, "setting the trustfile: ",
447 SDATA (trustfile));
448 ret = gnutls_certificate_set_x509_trust_file
449 (x509_cred,
450 SDATA (trustfile),
451 file_format);
452
453 if (ret < GNUTLS_E_SUCCESS)
454 return gnutls_make_error (ret);
455 }
456 else
457 {
458 error ("Sorry, GnuTLS can't use non-string trustfile %s",
459 trustfile);
460 }
461 }
462
463 for (tail = keyfiles; !NILP (tail); tail = Fcdr (tail))
464 {
465 Lisp_Object keyfile = Fcar (tail);
466 if (STRINGP (keyfile))
467 {
468 GNUTLS_LOG2 (1, max_log_level, "setting the keyfile: ",
469 SDATA (keyfile));
470 ret = gnutls_certificate_set_x509_crl_file
471 (x509_cred,
472 SDATA (keyfile),
473 file_format);
474
475 if (ret < GNUTLS_E_SUCCESS)
476 return gnutls_make_error (ret);
477 }
478 else
479 {
480 error ("Sorry, GnuTLS can't use non-string keyfile %s",
481 keyfile);
482 }
483 }
484 }
485
486 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_FILES;
487
488 GNUTLS_LOG (1, max_log_level, "gnutls_init");
489
490 ret = gnutls_init (&state, GNUTLS_CLIENT);
491
492 if (ret < GNUTLS_E_SUCCESS)
493 return gnutls_make_error (ret);
494
495 XPROCESS (proc)->gnutls_state = state;
496
497 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_INIT;
498
499 if (STRINGP (priority_string))
500 {
501 priority_string_ptr = SSDATA (priority_string);
502 GNUTLS_LOG2 (1, max_log_level, "got non-default priority string:",
503 priority_string_ptr);
504 }
505 else
506 {
507 GNUTLS_LOG2 (1, max_log_level, "using default priority string:",
508 priority_string_ptr);
509 }
510
511 GNUTLS_LOG (1, max_log_level, "setting the priority string");
512
513 ret = gnutls_priority_set_direct (state,
514 priority_string_ptr,
515 NULL);
516
517 if (ret < GNUTLS_E_SUCCESS)
518 return gnutls_make_error (ret);
519
520 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_PRIORITY;
521
522 if (EQ (type, Qgnutls_x509pki))
523 {
524 ret = gnutls_cred_set (state, GNUTLS_CRD_CERTIFICATE, x509_cred);
525 }
526 else if (EQ (type, Qgnutls_anon))
527 {
528 ret = gnutls_cred_set (state, GNUTLS_CRD_ANON, anon_cred);
529 }
530 else
531 {
532 error ("unknown credential type");
533 ret = GNUTLS_EMACS_ERROR_INVALID_TYPE;
534 }
535
536 if (ret < GNUTLS_E_SUCCESS)
537 return gnutls_make_error (ret);
538
539 XPROCESS (proc)->gnutls_anon_cred = anon_cred;
540 XPROCESS (proc)->gnutls_x509_cred = x509_cred;
541 XPROCESS (proc)->gnutls_cred_type = type;
542
543 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_CRED_SET;
544
545 emacs_gnutls_handshake (XPROCESS (proc));
546
547 return gnutls_make_error (GNUTLS_E_SUCCESS);
548 }
549
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'.
554
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.
561
562 This function may also return `gnutls-e-again', or
563 `gnutls-e-interrupted'. */)
564 (Lisp_Object proc, Lisp_Object cont)
565 {
566 gnutls_session_t state;
567 int ret;
568
569 CHECK_PROCESS (proc);
570
571 state = XPROCESS (proc)->gnutls_state;
572
573 ret = gnutls_bye (state,
574 NILP (cont) ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR);
575
576 return gnutls_make_error (ret);
577 }
578
579 void
580 syms_of_gnutls (void)
581 {
582 global_initialized = 0;
583
584 Qgnutls_code = intern_c_string ("gnutls-code");
585 staticpro (&Qgnutls_code);
586
587 Qgnutls_anon = intern_c_string ("gnutls-anon");
588 staticpro (&Qgnutls_anon);
589
590 Qgnutls_x509pki = intern_c_string ("gnutls-x509pki");
591 staticpro (&Qgnutls_x509pki);
592
593 Qgnutls_bootprop_priority = intern_c_string (":priority");
594 staticpro (&Qgnutls_bootprop_priority);
595
596 Qgnutls_bootprop_trustfiles = intern_c_string (":trustfiles");
597 staticpro (&Qgnutls_bootprop_trustfiles);
598
599 Qgnutls_bootprop_keyfiles = intern_c_string (":keyfiles");
600 staticpro (&Qgnutls_bootprop_keyfiles);
601
602 Qgnutls_bootprop_callbacks = intern_c_string (":callbacks");
603 staticpro (&Qgnutls_bootprop_callbacks);
604
605 Qgnutls_bootprop_loglevel = intern_c_string (":loglevel");
606 staticpro (&Qgnutls_bootprop_loglevel);
607
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));
612
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));
617
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));
622
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));
628
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);
636 }
637 #endif