aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTed Zlatanov2011-04-24 20:30:51 -0500
committerTed Zlatanov2011-04-24 20:30:51 -0500
commite061a11b5a59f02fac66184e991f01a433f6dc8d (patch)
treeccff6a6012dbc1ed4ce247b9e4e84a38c5eb34af /src
parent33630d51504adc5b2a0289f356c0a1a49f0bd10a (diff)
downloademacs-e061a11b5a59f02fac66184e991f01a433f6dc8d.tar.gz
emacs-e061a11b5a59f02fac66184e991f01a433f6dc8d.zip
Add GnuTLS support for W32 and certificate and hostname verification in GnuTLS.
* src/gnutls.c: Renamed global_initialized to gnutls_global_initialized. Added internals for the :verify-hostname-error, :verify-error, and :verify-flags parameters of `gnutls-boot' and documented those parameters in the docstring. Start callback support. (emacs_gnutls_handshake): Add Woe32 support. Retry handshake unless a fatal error occured. Call gnutls_alert_send_appropriate on error. Return error code. (emacs_gnutls_write): Call emacs_gnutls_handle_error. (emacs_gnutls_read): Likewise. (Fgnutls_boot): Return handshake error code. (emacs_gnutls_handle_error): New function. (wsaerror_to_errno): Likewise. * src/gnutls.h: Add GNUTLS_STAGE_CALLBACKS enum to denote we're in the callbacks stage. * src/w32.c (emacs_gnutls_pull): New function for GnuTLS on Woe32. (emacs_gnutls_push): Likewise. * src/w32.h (emacs_gnutls_pull): Add prototype. (emacs_gnutls_push): Likewise.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog35
-rw-r--r--src/gnutls.c360
-rw-r--r--src/gnutls.h2
-rw-r--r--src/makefile.w32-in10
-rw-r--r--src/process.c16
-rw-r--r--src/w32.c69
-rw-r--r--src/w32.h12
7 files changed, 464 insertions, 40 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index f1d195c4544..410a3b15ffb 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,38 @@
12011-04-24 Teodor Zlatanov <tzz@lifelogs.com>
2
3 * gnutls.h: Add GNUTLS_STAGE_CALLBACKS enum to denote we're in the
4 callbacks stage.
5
6 * gnutls.c: Renamed global_initialized to
7 gnutls_global_initialized. Added internals for the
8 :verify-hostname-error, :verify-error, and :verify-flags
9 parameters of `gnutls-boot' and documented those parameters in the
10 docstring. Start callback support.
11 (emacs_gnutls_handshake): Add Woe32 support. Retry handshake
12 unless a fatal error occured. Call gnutls_alert_send_appropriate
13 on error. Return error code.
14 (emacs_gnutls_write): Call emacs_gnutls_handle_error.
15 (emacs_gnutls_read): Likewise.
16 (Fgnutls_boot): Return handshake error code.
17 (emacs_gnutls_handle_error): New function.
18 (wsaerror_to_errno): Likewise.
19
20 * w32.h (emacs_gnutls_pull): Add prototype.
21 (emacs_gnutls_push): Likewise.
22
23 * w32.c (emacs_gnutls_pull): New function for GnuTLS on Woe32.
24 (emacs_gnutls_push): Likewise.
25
262011-04-24 Claudio Bley <claudio.bley@gmail.com> (tiny change)
27
28 * process.c (wait_reading_process_output): Check if GnuTLS
29 buffered some data internally if no FDs are set for TLS
30 connections.
31
32 * makefile.w32-in (OBJ2): Add gnutls.$(O).
33 (LIBS): Link to USER_LIBS.
34 ($(BLD)/gnutls.$(0)): New target.
35
12011-04-24 Eli Zaretskii <eliz@gnu.org> 362011-04-24 Eli Zaretskii <eliz@gnu.org>
2 37
3 * xdisp.c (handle_single_display_spec): Rename the 38 * xdisp.c (handle_single_display_spec): Rename the
diff --git a/src/gnutls.c b/src/gnutls.c
index f4f2b9bbd35..18ceb79193b 100644
--- a/src/gnutls.c
+++ b/src/gnutls.c
@@ -26,11 +26,20 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
26#ifdef HAVE_GNUTLS 26#ifdef HAVE_GNUTLS
27#include <gnutls/gnutls.h> 27#include <gnutls/gnutls.h>
28 28
29#ifdef WINDOWSNT
30#include <windows.h>
31#include "w32.h"
32#endif
33
34static int
35emacs_gnutls_handle_error (gnutls_session_t, int err);
36
37Lisp_Object Qgnutls_log_level;
29Lisp_Object Qgnutls_code; 38Lisp_Object Qgnutls_code;
30Lisp_Object Qgnutls_anon, Qgnutls_x509pki; 39Lisp_Object Qgnutls_anon, Qgnutls_x509pki;
31Lisp_Object Qgnutls_e_interrupted, Qgnutls_e_again, 40Lisp_Object Qgnutls_e_interrupted, Qgnutls_e_again,
32 Qgnutls_e_invalid_session, Qgnutls_e_not_ready_for_handshake; 41 Qgnutls_e_invalid_session, Qgnutls_e_not_ready_for_handshake;
33int global_initialized; 42int gnutls_global_initialized;
34 43
35/* The following are for the property list of `gnutls-boot'. */ 44/* The following are for the property list of `gnutls-boot'. */
36Lisp_Object Qgnutls_bootprop_priority; 45Lisp_Object Qgnutls_bootprop_priority;
@@ -38,8 +47,27 @@ Lisp_Object Qgnutls_bootprop_trustfiles;
38Lisp_Object Qgnutls_bootprop_keyfiles; 47Lisp_Object Qgnutls_bootprop_keyfiles;
39Lisp_Object Qgnutls_bootprop_callbacks; 48Lisp_Object Qgnutls_bootprop_callbacks;
40Lisp_Object Qgnutls_bootprop_loglevel; 49Lisp_Object Qgnutls_bootprop_loglevel;
50Lisp_Object Qgnutls_bootprop_hostname;
51Lisp_Object Qgnutls_bootprop_verify_flags;
52Lisp_Object Qgnutls_bootprop_verify_error;
53Lisp_Object Qgnutls_bootprop_verify_hostname_error;
54
55/* Callback keys for `gnutls-boot'. Unused currently. */
56Lisp_Object Qgnutls_bootprop_callbacks_verify;
41 57
42static void 58static void
59gnutls_log_function (int level, const char* string)
60{
61 message ("gnutls.c: [%d] %s", level, string);
62}
63
64static void
65gnutls_log_function2 (int level, const char* string, const char* extra)
66{
67 message ("gnutls.c: [%d] %s %s", level, string, extra);
68}
69
70static int
43emacs_gnutls_handshake (struct Lisp_Process *proc) 71emacs_gnutls_handshake (struct Lisp_Process *proc)
44{ 72{
45 gnutls_session_t state = proc->gnutls_state; 73 gnutls_session_t state = proc->gnutls_state;
@@ -50,24 +78,55 @@ emacs_gnutls_handshake (struct Lisp_Process *proc)
50 78
51 if (proc->gnutls_initstage < GNUTLS_STAGE_TRANSPORT_POINTERS_SET) 79 if (proc->gnutls_initstage < GNUTLS_STAGE_TRANSPORT_POINTERS_SET)
52 { 80 {
81#ifdef WINDOWSNT
82 /* On W32 we cannot transfer socket handles between different runtime
83 libraries, so we tell GnuTLS to use our special push/pull
84 functions. */
85 gnutls_transport_set_ptr2 (state,
86 (gnutls_transport_ptr_t) proc,
87 (gnutls_transport_ptr_t) proc);
88 gnutls_transport_set_push_function (state, &emacs_gnutls_push);
89 gnutls_transport_set_pull_function (state, &emacs_gnutls_pull);
90
91 /* For non blocking sockets or other custom made pull/push
92 functions the gnutls_transport_set_lowat must be called, with
93 a zero low water mark value. (GnuTLS 2.10.4 documentation)
94
95 (Note: this is probably not strictly necessary as the lowat
96 value is only used when no custom pull/push functions are
97 set.) */
98 gnutls_transport_set_lowat (state, 0);
99#else
53 /* This is how GnuTLS takes sockets: as file descriptors passed 100 /* This is how GnuTLS takes sockets: as file descriptors passed
54 in. For an Emacs process socket, infd and outfd are the 101 in. For an Emacs process socket, infd and outfd are the
55 same but we use this two-argument version for clarity. */ 102 same but we use this two-argument version for clarity. */
56 gnutls_transport_set_ptr2 (state, 103 gnutls_transport_set_ptr2 (state,
57 (gnutls_transport_ptr_t) (long) proc->infd, 104 (gnutls_transport_ptr_t) proc->infd,
58 (gnutls_transport_ptr_t) (long) proc->outfd); 105 (gnutls_transport_ptr_t) proc->outfd);
106#endif
59 107
60 proc->gnutls_initstage = GNUTLS_STAGE_TRANSPORT_POINTERS_SET; 108 proc->gnutls_initstage = GNUTLS_STAGE_TRANSPORT_POINTERS_SET;
61 } 109 }
62 110
63 ret = gnutls_handshake (state); 111 do
112 {
113 ret = gnutls_handshake (state);
114 emacs_gnutls_handle_error (state, ret);
115 }
116 while (ret < 0 && gnutls_error_is_fatal (ret) == 0);
117
64 proc->gnutls_initstage = GNUTLS_STAGE_HANDSHAKE_TRIED; 118 proc->gnutls_initstage = GNUTLS_STAGE_HANDSHAKE_TRIED;
65 119
66 if (ret == GNUTLS_E_SUCCESS) 120 if (ret == GNUTLS_E_SUCCESS)
67 { 121 {
68 /* here we're finally done. */ 122 /* Here we're finally done. */
69 proc->gnutls_initstage = GNUTLS_STAGE_READY; 123 proc->gnutls_initstage = GNUTLS_STAGE_READY;
70 } 124 }
125 else
126 {
127 gnutls_alert_send_appropriate (state, ret);
128 }
129 return ret;
71} 130}
72 131
73EMACS_INT 132EMACS_INT
@@ -107,6 +166,7 @@ emacs_gnutls_write (int fildes, struct Lisp_Process *proc, const char *buf,
107 bytes_written += rtnval; 166 bytes_written += rtnval;
108 } 167 }
109 168
169 emacs_gnutls_handle_error (state, rtnval);
110 return (bytes_written); 170 return (bytes_written);
111} 171}
112 172
@@ -122,19 +182,68 @@ emacs_gnutls_read (int fildes, struct Lisp_Process *proc, char *buf,
122 emacs_gnutls_handshake (proc); 182 emacs_gnutls_handshake (proc);
123 return -1; 183 return -1;
124 } 184 }
125
126 rtnval = gnutls_read (state, buf, nbyte); 185 rtnval = gnutls_read (state, buf, nbyte);
127 if (rtnval >= 0) 186 if (rtnval >= 0)
128 return rtnval; 187 return rtnval;
188 else if (emacs_gnutls_handle_error (state, rtnval) == 0)
189 /* non-fatal error */
190 return -1;
129 else { 191 else {
130 if (rtnval == GNUTLS_E_AGAIN || 192 /* a fatal error occured */
131 rtnval == GNUTLS_E_INTERRUPTED) 193 return 0;
132 return -1;
133 else
134 return 0;
135 } 194 }
136} 195}
137 196
197/* report a GnuTLS error to the user.
198 Returns zero if the error code was successfully handled. */
199static int
200emacs_gnutls_handle_error (gnutls_session_t session, int err)
201{
202 Lisp_Object gnutls_log_level = Fsymbol_value (Qgnutls_log_level);
203 int max_log_level = 0;
204
205 int alert, ret;
206 const char *str;
207
208 /* TODO: use a Lisp_Object generated by gnutls_make_error? */
209 if (err >= 0)
210 return 0;
211
212 if (NUMBERP (gnutls_log_level))
213 max_log_level = XINT (gnutls_log_level);
214
215 /* TODO: use gnutls-error-fatalp and gnutls-error-string. */
216
217 str = gnutls_strerror (err);
218 if (!str)
219 str = "unknown";
220
221 if (gnutls_error_is_fatal (err))
222 {
223 ret = err;
224 GNUTLS_LOG2 (0, max_log_level, "fatal error:", str);
225 }
226 else
227 {
228 ret = 0;
229 GNUTLS_LOG2 (1, max_log_level, "non-fatal error:", str);
230 /* TODO: EAGAIN AKA Qgnutls_e_again should be level 2. */
231 }
232
233 if (err == GNUTLS_E_WARNING_ALERT_RECEIVED
234 || err == GNUTLS_E_FATAL_ALERT_RECEIVED)
235 {
236 int alert = gnutls_alert_get (session);
237 int level = (err == GNUTLS_E_FATAL_ALERT_RECEIVED) ? 0 : 1;
238 str = gnutls_alert_get_name (alert);
239 if (!str)
240 str = "unknown";
241
242 GNUTLS_LOG2 (level, max_log_level, "Received alert: ", str);
243 }
244 return ret;
245}
246
138/* convert an integer error to a Lisp_Object; it will be either a 247/* 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 248 known symbol like `gnutls_e_interrupted' and `gnutls_e_again' or
140 simply the integer value of the error. GNUTLS_E_SUCCESS is mapped 249 simply the integer value of the error. GNUTLS_E_SUCCESS is mapped
@@ -262,14 +371,14 @@ See also `gnutls-init'. */)
262Call `gnutls-global-deinit' when GnuTLS usage is no longer needed. 371Call `gnutls-global-deinit' when GnuTLS usage is no longer needed.
263Returns zero on success. */ 372Returns zero on success. */
264static Lisp_Object 373static Lisp_Object
265gnutls_emacs_global_init (void) 374emacs_gnutls_global_init (void)
266{ 375{
267 int ret = GNUTLS_E_SUCCESS; 376 int ret = GNUTLS_E_SUCCESS;
268 377
269 if (!global_initialized) 378 if (!gnutls_global_initialized)
270 ret = gnutls_global_init (); 379 ret = gnutls_global_init ();
271 380
272 global_initialized = 1; 381 gnutls_global_initialized = 1;
273 382
274 return gnutls_make_error (ret); 383 return gnutls_make_error (ret);
275} 384}
@@ -277,28 +386,16 @@ gnutls_emacs_global_init (void)
277/* Deinitializes global GnuTLS state. 386/* Deinitializes global GnuTLS state.
278See also `gnutls-global-init'. */ 387See also `gnutls-global-init'. */
279static Lisp_Object 388static Lisp_Object
280gnutls_emacs_global_deinit (void) 389emacs_gnutls_global_deinit (void)
281{ 390{
282 if (global_initialized) 391 if (gnutls_global_initialized)
283 gnutls_global_deinit (); 392 gnutls_global_deinit ();
284 393
285 global_initialized = 0; 394 gnutls_global_initialized = 0;
286 395
287 return gnutls_make_error (GNUTLS_E_SUCCESS); 396 return gnutls_make_error (GNUTLS_E_SUCCESS);
288} 397}
289 398
290static void
291gnutls_log_function (int level, const char* string)
292{
293 message ("gnutls.c: [%d] %s", level, string);
294}
295
296static void
297gnutls_log_function2 (int level, const char* string, const char* extra)
298{
299 message ("gnutls.c: [%d] %s %s", level, string, extra);
300}
301
302DEFUN ("gnutls-boot", Fgnutls_boot, Sgnutls_boot, 3, 3, 0, 399DEFUN ("gnutls-boot", Fgnutls_boot, Sgnutls_boot, 3, 3, 0,
303 doc: /* Initialize GnuTLS client for process PROC with TYPE+PROPLIST. 400 doc: /* Initialize GnuTLS client for process PROC with TYPE+PROPLIST.
304Currently only client mode is supported. Returns a success/failure 401Currently only client mode is supported. Returns a success/failure
@@ -307,12 +404,27 @@ value you can check with `gnutls-errorp'.
307TYPE is a symbol, either `gnutls-anon' or `gnutls-x509pki'. 404TYPE is a symbol, either `gnutls-anon' or `gnutls-x509pki'.
308PROPLIST is a property list with the following keys: 405PROPLIST is a property list with the following keys:
309 406
407:hostname is a string naming the remote host.
408
310:priority is a GnuTLS priority string, defaults to "NORMAL". 409:priority is a GnuTLS priority string, defaults to "NORMAL".
410
311:trustfiles is a list of PEM-encoded trust files for `gnutls-x509pki'. 411:trustfiles is a list of PEM-encoded trust files for `gnutls-x509pki'.
412
312:keyfiles is a list of PEM-encoded key files for `gnutls-x509pki'. 413:keyfiles is a list of PEM-encoded key files for `gnutls-x509pki'.
313:callbacks is an alist of callback functions (TODO). 414
415:callbacks is an alist of callback functions, see below.
416
314:loglevel is the debug level requested from GnuTLS, try 4. 417:loglevel is the debug level requested from GnuTLS, try 4.
315 418
419:verify-flags is a bitset as per GnuTLS'
420gnutls_certificate_set_verify_flags.
421
422:verify-error, if non-nil, makes failure of the certificate validation
423an error. Otherwise it will be just a series of warnings.
424
425:verify-hostname-error, if non-nil, makes a hostname mismatch an
426error. Otherwise it will be just a warning.
427
316The debug level will be set for this process AND globally for GnuTLS. 428The debug level will be set for this process AND globally for GnuTLS.
317So if you set it higher or lower at any point, it affects global 429So if you set it higher or lower at any point, it affects global
318debugging. 430debugging.
@@ -325,6 +437,9 @@ Processes must be initialized with this function before other GnuTLS
325functions are used. This function allocates resources which can only 437functions are used. This function allocates resources which can only
326be deallocated by calling `gnutls-deinit' or by calling it again. 438be deallocated by calling `gnutls-deinit' or by calling it again.
327 439
440The callbacks alist can have a `verify' key, associated with a
441verification function (UNUSED).
442
328Each authentication type may need additional information in order to 443Each authentication type may need additional information in order to
329work. For X.509 PKI (`gnutls-x509pki'), you probably need at least 444work. For X.509 PKI (`gnutls-x509pki'), you probably need at least
330one trustfile (usually a CA bundle). */) 445one trustfile (usually a CA bundle). */)
@@ -337,12 +452,19 @@ one trustfile (usually a CA bundle). */)
337 /* TODO: GNUTLS_X509_FMT_DER is also an option. */ 452 /* TODO: GNUTLS_X509_FMT_DER is also an option. */
338 int file_format = GNUTLS_X509_FMT_PEM; 453 int file_format = GNUTLS_X509_FMT_PEM;
339 454
455 unsigned int gnutls_verify_flags = GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT;
456 gnutls_x509_crt_t gnutls_verify_cert;
457 unsigned int gnutls_verify_cert_list_size;
458 const gnutls_datum_t *gnutls_verify_cert_list;
459
340 gnutls_session_t state; 460 gnutls_session_t state;
341 gnutls_certificate_credentials_t x509_cred; 461 gnutls_certificate_credentials_t x509_cred;
342 gnutls_anon_client_credentials_t anon_cred; 462 gnutls_anon_client_credentials_t anon_cred;
343 Lisp_Object global_init; 463 Lisp_Object global_init;
344 char* priority_string_ptr = "NORMAL"; /* default priority string. */ 464 char* priority_string_ptr = "NORMAL"; /* default priority string. */
345 Lisp_Object tail; 465 Lisp_Object tail;
466 int peer_verification;
467 char* c_hostname;
346 468
347 /* Placeholders for the property list elements. */ 469 /* Placeholders for the property list elements. */
348 Lisp_Object priority_string; 470 Lisp_Object priority_string;
@@ -350,16 +472,29 @@ one trustfile (usually a CA bundle). */)
350 Lisp_Object keyfiles; 472 Lisp_Object keyfiles;
351 Lisp_Object callbacks; 473 Lisp_Object callbacks;
352 Lisp_Object loglevel; 474 Lisp_Object loglevel;
475 Lisp_Object hostname;
476 Lisp_Object verify_flags;
477 Lisp_Object verify_error;
478 Lisp_Object verify_hostname_error;
353 479
354 CHECK_PROCESS (proc); 480 CHECK_PROCESS (proc);
355 CHECK_SYMBOL (type); 481 CHECK_SYMBOL (type);
356 CHECK_LIST (proplist); 482 CHECK_LIST (proplist);
357 483
358 priority_string = Fplist_get (proplist, Qgnutls_bootprop_priority); 484 hostname = Fplist_get (proplist, Qgnutls_bootprop_hostname);
359 trustfiles = Fplist_get (proplist, Qgnutls_bootprop_trustfiles); 485 priority_string = Fplist_get (proplist, Qgnutls_bootprop_priority);
360 keyfiles = Fplist_get (proplist, Qgnutls_bootprop_keyfiles); 486 trustfiles = Fplist_get (proplist, Qgnutls_bootprop_trustfiles);
361 callbacks = Fplist_get (proplist, Qgnutls_bootprop_callbacks); 487 keyfiles = Fplist_get (proplist, Qgnutls_bootprop_keyfiles);
362 loglevel = Fplist_get (proplist, Qgnutls_bootprop_loglevel); 488 callbacks = Fplist_get (proplist, Qgnutls_bootprop_callbacks);
489 loglevel = Fplist_get (proplist, Qgnutls_bootprop_loglevel);
490 verify_flags = Fplist_get (proplist, Qgnutls_bootprop_verify_flags);
491 verify_error = Fplist_get (proplist, Qgnutls_bootprop_verify_error);
492 verify_hostname_error = Fplist_get (proplist, Qgnutls_bootprop_verify_hostname_error);
493
494 if (!STRINGP (hostname))
495 error ("gnutls-boot: invalid :hostname parameter");
496
497 c_hostname = SSDATA (hostname);
363 498
364 state = XPROCESS (proc)->gnutls_state; 499 state = XPROCESS (proc)->gnutls_state;
365 XPROCESS (proc)->gnutls_p = 1; 500 XPROCESS (proc)->gnutls_p = 1;
@@ -373,7 +508,7 @@ one trustfile (usually a CA bundle). */)
373 } 508 }
374 509
375 /* always initialize globals. */ 510 /* always initialize globals. */
376 global_init = gnutls_emacs_global_init (); 511 global_init = emacs_gnutls_global_init ();
377 if (! NILP (Fgnutls_errorp (global_init))) 512 if (! NILP (Fgnutls_errorp (global_init)))
378 return global_init; 513 return global_init;
379 514
@@ -417,6 +552,23 @@ one trustfile (usually a CA bundle). */)
417 x509_cred = XPROCESS (proc)->gnutls_x509_cred; 552 x509_cred = XPROCESS (proc)->gnutls_x509_cred;
418 if (gnutls_certificate_allocate_credentials (&x509_cred) < 0) 553 if (gnutls_certificate_allocate_credentials (&x509_cred) < 0)
419 memory_full (); 554 memory_full ();
555
556 if (NUMBERP (verify_flags))
557 {
558 gnutls_verify_flags = XINT (verify_flags);
559 GNUTLS_LOG (2, max_log_level, "setting verification flags");
560 }
561 else if (NILP (verify_flags))
562 {
563 /* The default is already GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT. */
564 GNUTLS_LOG (2, max_log_level, "using default verification flags");
565 }
566 else
567 {
568 /* The default is already GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT. */
569 GNUTLS_LOG (2, max_log_level, "ignoring invalid verify-flags");
570 }
571 gnutls_certificate_set_verify_flags (x509_cred, gnutls_verify_flags);
420 } 572 }
421 else if (EQ (type, Qgnutls_anon)) 573 else if (EQ (type, Qgnutls_anon))
422 { 574 {
@@ -485,6 +637,14 @@ one trustfile (usually a CA bundle). */)
485 637
486 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_FILES; 638 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_FILES;
487 639
640 GNUTLS_LOG (1, max_log_level, "gnutls callbacks");
641
642 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_CALLBACKS;
643
644#ifdef HAVE_GNUTLS_CALLBACK_CERTIFICATE_VERIFY
645#else
646#endif
647
488 GNUTLS_LOG (1, max_log_level, "gnutls_init"); 648 GNUTLS_LOG (1, max_log_level, "gnutls_init");
489 649
490 ret = gnutls_init (&state, GNUTLS_CLIENT); 650 ret = gnutls_init (&state, GNUTLS_CLIENT);
@@ -542,9 +702,113 @@ one trustfile (usually a CA bundle). */)
542 702
543 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_CRED_SET; 703 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_CRED_SET;
544 704
545 emacs_gnutls_handshake (XPROCESS (proc)); 705 ret = emacs_gnutls_handshake (XPROCESS (proc));
546 706
547 return gnutls_make_error (GNUTLS_E_SUCCESS); 707 if (ret < GNUTLS_E_SUCCESS)
708 return gnutls_make_error (ret);
709
710 /* Now verify the peer, following
711 http://www.gnu.org/software/gnutls/manual/html_node/Verifying-peer_0027s-certificate.html.
712 The peer should present at least one certificate in the chain; do a
713 check of the certificate's hostname with
714 gnutls_x509_crt_check_hostname() against :hostname. */
715
716 ret = gnutls_certificate_verify_peers2 (state, &peer_verification);
717
718 if (ret < GNUTLS_E_SUCCESS)
719 return gnutls_make_error (ret);
720
721 if (XINT (loglevel) > 0 && peer_verification & GNUTLS_CERT_INVALID)
722 message ("%s certificate could not be verified.",
723 c_hostname);
724
725 if (peer_verification & GNUTLS_CERT_REVOKED)
726 GNUTLS_LOG2 (1, max_log_level, "certificate was revoked (CRL):",
727 c_hostname);
728
729 if (peer_verification & GNUTLS_CERT_SIGNER_NOT_FOUND)
730 GNUTLS_LOG2 (1, max_log_level, "certificate signer was not found:",
731 c_hostname);
732
733 if (peer_verification & GNUTLS_CERT_SIGNER_NOT_CA)
734 GNUTLS_LOG2 (1, max_log_level, "certificate signer is not a CA:",
735 c_hostname);
736
737 if (peer_verification & GNUTLS_CERT_INSECURE_ALGORITHM)
738 GNUTLS_LOG2 (1, max_log_level,
739 "certificate was signed with an insecure algorithm:",
740 c_hostname);
741
742 if (peer_verification & GNUTLS_CERT_NOT_ACTIVATED)
743 GNUTLS_LOG2 (1, max_log_level, "certificate is not yet activated:",
744 c_hostname);
745
746 if (peer_verification & GNUTLS_CERT_EXPIRED)
747 GNUTLS_LOG2 (1, max_log_level, "certificate has expired:",
748 c_hostname);
749
750 if (peer_verification != 0)
751 {
752 if (NILP (verify_hostname_error))
753 {
754 GNUTLS_LOG2 (1, max_log_level, "certificate validation failed:",
755 c_hostname);
756 }
757 else
758 {
759 error ("Certificate validation failed %s, verification code %d",
760 c_hostname, peer_verification);
761 }
762 }
763
764 /* Up to here the process is the same for X.509 certificates and
765 OpenPGP keys. From now on X.509 certificates are assumed. This
766 can be easily extended to work with openpgp keys as well. */
767 if (gnutls_certificate_type_get (state) == GNUTLS_CRT_X509)
768 {
769 ret = gnutls_x509_crt_init (&gnutls_verify_cert);
770
771 if (ret < GNUTLS_E_SUCCESS)
772 return gnutls_make_error (ret);
773
774 gnutls_verify_cert_list =
775 gnutls_certificate_get_peers (state, &gnutls_verify_cert_list_size);
776
777 if (NULL == gnutls_verify_cert_list)
778 {
779 error ("No x509 certificate was found!\n");
780 }
781
782 /* We only check the first certificate in the given chain. */
783 ret = gnutls_x509_crt_import (gnutls_verify_cert,
784 &gnutls_verify_cert_list[0],
785 GNUTLS_X509_FMT_DER);
786
787 if (ret < GNUTLS_E_SUCCESS)
788 {
789 gnutls_x509_crt_deinit (gnutls_verify_cert);
790 return gnutls_make_error (ret);
791 }
792
793 if (!gnutls_x509_crt_check_hostname (gnutls_verify_cert, c_hostname))
794 {
795 if (NILP (verify_hostname_error))
796 {
797 GNUTLS_LOG2 (1, max_log_level, "x509 certificate does not match:",
798 c_hostname);
799 }
800 else
801 {
802 gnutls_x509_crt_deinit (gnutls_verify_cert);
803 error ("The x509 certificate does not match \"%s\"",
804 c_hostname);
805 }
806 }
807
808 gnutls_x509_crt_deinit (gnutls_verify_cert);
809 }
810
811 return gnutls_make_error (ret);
548} 812}
549 813
550DEFUN ("gnutls-bye", Fgnutls_bye, 814DEFUN ("gnutls-bye", Fgnutls_bye,
@@ -579,7 +843,10 @@ This function may also return `gnutls-e-again', or
579void 843void
580syms_of_gnutls (void) 844syms_of_gnutls (void)
581{ 845{
582 global_initialized = 0; 846 gnutls_global_initialized = 0;
847
848 Qgnutls_log_level = intern_c_string ("gnutls-log-level");
849 staticpro (&Qgnutls_log_level);
583 850
584 Qgnutls_code = intern_c_string ("gnutls-code"); 851 Qgnutls_code = intern_c_string ("gnutls-code");
585 staticpro (&Qgnutls_code); 852 staticpro (&Qgnutls_code);
@@ -590,6 +857,9 @@ syms_of_gnutls (void)
590 Qgnutls_x509pki = intern_c_string ("gnutls-x509pki"); 857 Qgnutls_x509pki = intern_c_string ("gnutls-x509pki");
591 staticpro (&Qgnutls_x509pki); 858 staticpro (&Qgnutls_x509pki);
592 859
860 Qgnutls_bootprop_hostname = intern_c_string (":hostname");
861 staticpro (&Qgnutls_bootprop_hostname);
862
593 Qgnutls_bootprop_priority = intern_c_string (":priority"); 863 Qgnutls_bootprop_priority = intern_c_string (":priority");
594 staticpro (&Qgnutls_bootprop_priority); 864 staticpro (&Qgnutls_bootprop_priority);
595 865
@@ -602,9 +872,21 @@ syms_of_gnutls (void)
602 Qgnutls_bootprop_callbacks = intern_c_string (":callbacks"); 872 Qgnutls_bootprop_callbacks = intern_c_string (":callbacks");
603 staticpro (&Qgnutls_bootprop_callbacks); 873 staticpro (&Qgnutls_bootprop_callbacks);
604 874
875 Qgnutls_bootprop_callbacks_verify = intern_c_string ("verify");
876 staticpro (&Qgnutls_bootprop_callbacks_verify);
877
605 Qgnutls_bootprop_loglevel = intern_c_string (":loglevel"); 878 Qgnutls_bootprop_loglevel = intern_c_string (":loglevel");
606 staticpro (&Qgnutls_bootprop_loglevel); 879 staticpro (&Qgnutls_bootprop_loglevel);
607 880
881 Qgnutls_bootprop_verify_flags = intern_c_string (":verify-flags");
882 staticpro (&Qgnutls_bootprop_verify_flags);
883
884 Qgnutls_bootprop_verify_hostname_error = intern_c_string (":verify-error");
885 staticpro (&Qgnutls_bootprop_verify_error);
886
887 Qgnutls_bootprop_verify_hostname_error = intern_c_string (":verify-hostname-error");
888 staticpro (&Qgnutls_bootprop_verify_hostname_error);
889
608 Qgnutls_e_interrupted = intern_c_string ("gnutls-e-interrupted"); 890 Qgnutls_e_interrupted = intern_c_string ("gnutls-e-interrupted");
609 staticpro (&Qgnutls_e_interrupted); 891 staticpro (&Qgnutls_e_interrupted);
610 Fput (Qgnutls_e_interrupted, Qgnutls_code, 892 Fput (Qgnutls_e_interrupted, Qgnutls_code,
diff --git a/src/gnutls.h b/src/gnutls.h
index 5240d94c2ad..6c2e4c69523 100644
--- a/src/gnutls.h
+++ b/src/gnutls.h
@@ -21,6 +21,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 21
22#ifdef HAVE_GNUTLS 22#ifdef HAVE_GNUTLS
23#include <gnutls/gnutls.h> 23#include <gnutls/gnutls.h>
24#include <gnutls/x509.h>
24 25
25typedef enum 26typedef enum
26{ 27{
@@ -28,6 +29,7 @@ typedef enum
28 GNUTLS_STAGE_EMPTY = 0, 29 GNUTLS_STAGE_EMPTY = 0,
29 GNUTLS_STAGE_CRED_ALLOC, 30 GNUTLS_STAGE_CRED_ALLOC,
30 GNUTLS_STAGE_FILES, 31 GNUTLS_STAGE_FILES,
32 GNUTLS_STAGE_CALLBACKS,
31 GNUTLS_STAGE_INIT, 33 GNUTLS_STAGE_INIT,
32 GNUTLS_STAGE_PRIORITY, 34 GNUTLS_STAGE_PRIORITY,
33 GNUTLS_STAGE_CRED_SET, 35 GNUTLS_STAGE_CRED_SET,
diff --git a/src/makefile.w32-in b/src/makefile.w32-in
index 0dd06b7efc3..4ba314318db 100644
--- a/src/makefile.w32-in
+++ b/src/makefile.w32-in
@@ -105,6 +105,7 @@ OBJ2 = $(BLD)/sysdep.$(O) \
105 $(BLD)/floatfns.$(O) \ 105 $(BLD)/floatfns.$(O) \
106 $(BLD)/frame.$(O) \ 106 $(BLD)/frame.$(O) \
107 $(BLD)/gmalloc.$(O) \ 107 $(BLD)/gmalloc.$(O) \
108 $(BLD)/gnutls.$(O) \
108 $(BLD)/intervals.$(O) \ 109 $(BLD)/intervals.$(O) \
109 $(BLD)/composite.$(O) \ 110 $(BLD)/composite.$(O) \
110 $(BLD)/ralloc.$(O) \ 111 $(BLD)/ralloc.$(O) \
@@ -150,6 +151,7 @@ LIBS = $(TLIB0) \
150 $(OLE32) \ 151 $(OLE32) \
151 $(COMCTL32) \ 152 $(COMCTL32) \
152 $(UNISCRIBE) \ 153 $(UNISCRIBE) \
154 $(USER_LIBS) \
153 $(libc) 155 $(libc)
154 156
155# 157#
@@ -950,6 +952,14 @@ $(BLD)/gmalloc.$(O) : \
950 $(EMACS_ROOT)/nt/inc/unistd.h \ 952 $(EMACS_ROOT)/nt/inc/unistd.h \
951 $(SRC)/getpagesize.h 953 $(SRC)/getpagesize.h
952 954
955$(BLD)/gnutls.$(O) : \
956 $(SRC)/gnutls.h \
957 $(SRC)/gnutls.c \
958 $(CONFIG_H) \
959 $(EMACS_ROOT)/nt/inc/sys/socket.h \
960 $(SRC)/lisp.h \
961 $(SRC)/process.h
962
953$(BLD)/image.$(O) : \ 963$(BLD)/image.$(O) : \
954 $(SRC)/image.c \ 964 $(SRC)/image.c \
955 $(CONFIG_H) \ 965 $(CONFIG_H) \
diff --git a/src/process.c b/src/process.c
index d8851c56cf0..4253286196c 100644
--- a/src/process.c
+++ b/src/process.c
@@ -4532,6 +4532,22 @@ wait_reading_process_output (int time_limit, int microsecs, int read_kbd,
4532 &Available, 4532 &Available,
4533 (check_write ? &Writeok : (SELECT_TYPE *)0), 4533 (check_write ? &Writeok : (SELECT_TYPE *)0),
4534 (SELECT_TYPE *)0, &timeout); 4534 (SELECT_TYPE *)0, &timeout);
4535
4536#ifdef HAVE_GNUTLS
4537 /* GnuTLS buffers data internally. In lowat mode it leaves
4538 some data in the TCP buffers so that select works, but
4539 with custom pull/push functions we need to check if some
4540 data is available in the buffers manually. */
4541 if (nfds == 0 &&
4542 wait_proc && wait_proc->gnutls_p /* Check for valid process. */
4543 /* Do we have pending data? */
4544 && gnutls_record_check_pending (wait_proc->gnutls_state) > 0)
4545 {
4546 nfds = 1;
4547 /* Set to Available. */
4548 FD_SET (wait_proc->infd, &Available);
4549 }
4550#endif
4535 } 4551 }
4536 4552
4537 xerrno = errno; 4553 xerrno = errno;
diff --git a/src/w32.c b/src/w32.c
index 85e4a2025b9..065d730333b 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -6124,5 +6124,72 @@ serial_configure (struct Lisp_Process *p, Lisp_Object contact)
6124 p->childp = childp2; 6124 p->childp = childp2;
6125} 6125}
6126 6126
6127/* end of w32.c */ 6127#ifdef HAVE_GNUTLS
6128
6129ssize_t
6130emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
6131{
6132 int n, sc, err;
6133 SELECT_TYPE fdset;
6134 EMACS_TIME timeout;
6135 struct Lisp_Process *process = (struct Lisp_Process *)p;
6136 int fd = process->infd;
6137
6138 for (;;)
6139 {
6140 n = sys_read(fd, (char*)buf, sz);
6141
6142 if (n >= 0)
6143 return n;
6144
6145 err = errno;
6146
6147 if (err == EWOULDBLOCK)
6148 {
6149 /* Set a small timeout. */
6150 EMACS_SET_SECS_USECS(timeout, 1, 0);
6151 FD_ZERO (&fdset);
6152 FD_SET ((int)fd, &fdset);
6153
6154 /* Use select with the timeout to poll the selector. */
6155 sc = select (fd + 1, &fdset, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
6156 &timeout);
6157
6158 if (sc > 0)
6159 continue; /* Try again. */
6160
6161 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN.
6162 Also accept select return 0 as an indicator to EAGAIN. */
6163 if (sc == 0 || errno == EWOULDBLOCK)
6164 err = EAGAIN;
6165 else
6166 err = errno; /* Other errors are just passed on. */
6167 }
6168
6169 gnutls_transport_set_errno (process->gnutls_state, err);
6170
6171 return -1;
6172 }
6173}
6128 6174
6175ssize_t
6176emacs_gnutls_push (gnutls_transport_ptr_t p, const void* buf, size_t sz)
6177{
6178 struct Lisp_Process *process = (struct Lisp_Process *)p;
6179 int fd = proc->outfd;
6180 ssize_t n = sys_write(fd, buf, sz);
6181
6182 /* 0 or more bytes written means everything went fine. */
6183 if (n >= 0)
6184 return n;
6185
6186 /* Negative bytes written means we got an error in errno.
6187 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
6188 gnutls_transport_set_errno (process->gnutls_state,
6189 errno == EWOULDBLOCK ? EAGAIN : errno);
6190
6191 return -1;
6192}
6193#endif /* HAVE_GNUTLS */
6194
6195/* end of w32.c */
diff --git a/src/w32.h b/src/w32.h
index 9279ddbe579..4086c4190e1 100644
--- a/src/w32.h
+++ b/src/w32.h
@@ -143,5 +143,17 @@ extern void syms_of_fontset (void);
143extern int _sys_read_ahead (int fd); 143extern int _sys_read_ahead (int fd);
144extern int _sys_wait_accept (int fd); 144extern int _sys_wait_accept (int fd);
145 145
146#ifdef HAVE_GNUTLS
147#include <gnutls/gnutls.h>
148
149/* GnuTLS pull (read from remote) interface. */
150extern ssize_t emacs_gnutls_pull (gnutls_transport_ptr_t p,
151 void* buf, size_t sz);
152
153/* GnuTLS push (write to remote) interface. */
154extern ssize_t emacs_gnutls_push (gnutls_transport_ptr_t p,
155 const void* buf, size_t sz);
156#endif /* HAVE_GNUTLS */
157
146#endif /* EMACS_W32_H */ 158#endif /* EMACS_W32_H */
147 159