Merge: Make the Lisp reader and string-to-float more consistent.
[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 EMACS_INT
74 emacs_gnutls_write (int fildes, struct Lisp_Process *proc, const char *buf,
75 EMACS_INT nbyte)
76 {
77 ssize_t rtnval;
78 EMACS_INT 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 0;
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 break;
103 }
104
105 buf += rtnval;
106 nbyte -= rtnval;
107 bytes_written += rtnval;
108 }
109
110 return (bytes_written);
111 }
112
113 EMACS_INT
114 emacs_gnutls_read (int fildes, struct Lisp_Process *proc, char *buf,
115 EMACS_INT 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 err)
144 {
145 switch (err)
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 (err);
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 #if 0
278 /* Deinitializes global GnuTLS state.
279 See also `gnutls-global-init'. */
280 static Lisp_Object
281 gnutls_emacs_global_deinit (void)
282 {
283 if (global_initialized)
284 gnutls_global_deinit ();
285
286 global_initialized = 0;
287
288 return gnutls_make_error (GNUTLS_E_SUCCESS);
289 }
290 #endif
291
292 static void
293 gnutls_log_function (int level, const char* string)
294 {
295 message ("gnutls.c: [%d] %s", level, string);
296 }
297
298 static void
299 gnutls_log_function2 (int level, const char* string, const char* extra)
300 {
301 message ("gnutls.c: [%d] %s %s", level, string, extra);
302 }
303
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'.
308
309 TYPE is a symbol, either `gnutls-anon' or `gnutls-x509pki'.
310 PROPLIST is a property list with the following keys:
311
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.
317
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
320 debugging.
321
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
324 specified.
325
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.
329
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)
334 {
335 int ret = GNUTLS_E_SUCCESS;
336
337 int max_log_level = 0;
338
339 /* TODO: GNUTLS_X509_FMT_DER is also an option. */
340 int file_format = GNUTLS_X509_FMT_PEM;
341
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. */
347 Lisp_Object tail;
348
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;
355
356 CHECK_PROCESS (proc);
357 CHECK_SYMBOL (type);
358 CHECK_LIST (proplist);
359
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);
365
366 state = XPROCESS (proc)->gnutls_state;
367 XPROCESS (proc)->gnutls_p = 1;
368
369 if (NUMBERP (loglevel))
370 {
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;
375 }
376
377 /* always initialize globals. */
378 global_init = gnutls_emacs_global_init ();
379 if (! NILP (Fgnutls_errorp (global_init)))
380 return global_init;
381
382 /* deinit and free resources. */
383 if (GNUTLS_INITSTAGE (proc) >= GNUTLS_STAGE_CRED_ALLOC)
384 {
385 GNUTLS_LOG (1, max_log_level, "deallocating credentials");
386
387 if (EQ (type, Qgnutls_x509pki))
388 {
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);
392 }
393 else if (EQ (type, Qgnutls_anon))
394 {
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);
398 }
399 else
400 {
401 error ("unknown credential type");
402 ret = GNUTLS_EMACS_ERROR_INVALID_TYPE;
403 }
404
405 if (GNUTLS_INITSTAGE (proc) >= GNUTLS_STAGE_INIT)
406 {
407 GNUTLS_LOG (1, max_log_level, "deallocating x509 credentials");
408 Fgnutls_deinit (proc);
409 }
410 }
411
412 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_EMPTY;
413
414 GNUTLS_LOG (1, max_log_level, "allocating credentials");
415
416 if (EQ (type, Qgnutls_x509pki))
417 {
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)
421 memory_full ();
422 }
423 else if (EQ (type, Qgnutls_anon))
424 {
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)
428 memory_full ();
429 }
430 else
431 {
432 error ("unknown credential type");
433 ret = GNUTLS_EMACS_ERROR_INVALID_TYPE;
434 }
435
436 if (ret < GNUTLS_E_SUCCESS)
437 return gnutls_make_error (ret);
438
439 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_CRED_ALLOC;
440
441 if (EQ (type, Qgnutls_x509pki))
442 {
443 for (tail = trustfiles; !NILP (tail); tail = Fcdr (tail))
444 {
445 Lisp_Object trustfile = Fcar (tail);
446 if (STRINGP (trustfile))
447 {
448 GNUTLS_LOG2 (1, max_log_level, "setting the trustfile: ",
449 SSDATA (trustfile));
450 ret = gnutls_certificate_set_x509_trust_file
451 (x509_cred,
452 SSDATA (trustfile),
453 file_format);
454
455 if (ret < GNUTLS_E_SUCCESS)
456 return gnutls_make_error (ret);
457 }
458 else
459 {
460 error ("Sorry, GnuTLS can't use non-string trustfile %s",
461 SDATA (trustfile));
462 }
463 }
464
465 for (tail = keyfiles; !NILP (tail); tail = Fcdr (tail))
466 {
467 Lisp_Object keyfile = Fcar (tail);
468 if (STRINGP (keyfile))
469 {
470 GNUTLS_LOG2 (1, max_log_level, "setting the keyfile: ",
471 SSDATA (keyfile));
472 ret = gnutls_certificate_set_x509_crl_file
473 (x509_cred,
474 SSDATA (keyfile),
475 file_format);
476
477 if (ret < GNUTLS_E_SUCCESS)
478 return gnutls_make_error (ret);
479 }
480 else
481 {
482 error ("Sorry, GnuTLS can't use non-string keyfile %s",
483 SDATA (keyfile));
484 }
485 }
486 }
487
488 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_FILES;
489
490 GNUTLS_LOG (1, max_log_level, "gnutls_init");
491
492 ret = gnutls_init (&state, GNUTLS_CLIENT);
493
494 if (ret < GNUTLS_E_SUCCESS)
495 return gnutls_make_error (ret);
496
497 XPROCESS (proc)->gnutls_state = state;
498
499 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_INIT;
500
501 if (STRINGP (priority_string))
502 {
503 priority_string_ptr = SSDATA (priority_string);
504 GNUTLS_LOG2 (1, max_log_level, "got non-default priority string:",
505 priority_string_ptr);
506 }
507 else
508 {
509 GNUTLS_LOG2 (1, max_log_level, "using default priority string:",
510 priority_string_ptr);
511 }
512
513 GNUTLS_LOG (1, max_log_level, "setting the priority string");
514
515 ret = gnutls_priority_set_direct (state,
516 priority_string_ptr,
517 NULL);
518
519 if (ret < GNUTLS_E_SUCCESS)
520 return gnutls_make_error (ret);
521
522 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_PRIORITY;
523
524 if (EQ (type, Qgnutls_x509pki))
525 {
526 ret = gnutls_cred_set (state, GNUTLS_CRD_CERTIFICATE, x509_cred);
527 }
528 else if (EQ (type, Qgnutls_anon))
529 {
530 ret = gnutls_cred_set (state, GNUTLS_CRD_ANON, anon_cred);
531 }
532 else
533 {
534 error ("unknown credential type");
535 ret = GNUTLS_EMACS_ERROR_INVALID_TYPE;
536 }
537
538 if (ret < GNUTLS_E_SUCCESS)
539 return gnutls_make_error (ret);
540
541 XPROCESS (proc)->gnutls_anon_cred = anon_cred;
542 XPROCESS (proc)->gnutls_x509_cred = x509_cred;
543 XPROCESS (proc)->gnutls_cred_type = type;
544
545 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_CRED_SET;
546
547 emacs_gnutls_handshake (XPROCESS (proc));
548
549 return gnutls_make_error (GNUTLS_E_SUCCESS);
550 }
551
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'.
556
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.
563
564 This function may also return `gnutls-e-again', or
565 `gnutls-e-interrupted'. */)
566 (Lisp_Object proc, Lisp_Object cont)
567 {
568 gnutls_session_t state;
569 int ret;
570
571 CHECK_PROCESS (proc);
572
573 state = XPROCESS (proc)->gnutls_state;
574
575 ret = gnutls_bye (state,
576 NILP (cont) ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR);
577
578 return gnutls_make_error (ret);
579 }
580
581 void
582 syms_of_gnutls (void)
583 {
584 global_initialized = 0;
585
586 Qgnutls_code = intern_c_string ("gnutls-code");
587 staticpro (&Qgnutls_code);
588
589 Qgnutls_anon = intern_c_string ("gnutls-anon");
590 staticpro (&Qgnutls_anon);
591
592 Qgnutls_x509pki = intern_c_string ("gnutls-x509pki");
593 staticpro (&Qgnutls_x509pki);
594
595 Qgnutls_bootprop_priority = intern_c_string (":priority");
596 staticpro (&Qgnutls_bootprop_priority);
597
598 Qgnutls_bootprop_trustfiles = intern_c_string (":trustfiles");
599 staticpro (&Qgnutls_bootprop_trustfiles);
600
601 Qgnutls_bootprop_keyfiles = intern_c_string (":keyfiles");
602 staticpro (&Qgnutls_bootprop_keyfiles);
603
604 Qgnutls_bootprop_callbacks = intern_c_string (":callbacks");
605 staticpro (&Qgnutls_bootprop_callbacks);
606
607 Qgnutls_bootprop_loglevel = intern_c_string (":loglevel");
608 staticpro (&Qgnutls_bootprop_loglevel);
609
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));
614
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));
619
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));
624
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));
630
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);
638 }
639 #endif