Unify FRAME_window_system_DISPLAY_INFO macros between all ports.
[bpt/emacs.git] / src / gnutls.c
CommitLineData
8af55556 1/* GnuTLS glue for GNU Emacs.
ab422c4d 2 Copyright (C) 2010-2013 Free Software Foundation, Inc.
8af55556
TZ
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
18
19#include <config.h>
20#include <errno.h>
8af55556
TZ
21
22#include "lisp.h"
23#include "process.h"
24
25#ifdef HAVE_GNUTLS
26#include <gnutls/gnutls.h>
27
e061a11b
TZ
28#ifdef WINDOWSNT
29#include <windows.h>
30#include "w32.h"
31#endif
32
18e27ea8 33static bool emacs_gnutls_handle_error (gnutls_session_t, int);
e061a11b 34
0898ca10 35static Lisp_Object Qgnutls_dll;
bafcf6a5
JB
36static Lisp_Object Qgnutls_code;
37static Lisp_Object Qgnutls_anon, Qgnutls_x509pki;
38static Lisp_Object Qgnutls_e_interrupted, Qgnutls_e_again,
8af55556 39 Qgnutls_e_invalid_session, Qgnutls_e_not_ready_for_handshake;
18e27ea8 40static bool gnutls_global_initialized;
8af55556 41
c1ae068b 42/* The following are for the property list of `gnutls-boot'. */
a3720aa2
AS
43static Lisp_Object QCgnutls_bootprop_priority;
44static Lisp_Object QCgnutls_bootprop_trustfiles;
45static Lisp_Object QCgnutls_bootprop_keylist;
46static Lisp_Object QCgnutls_bootprop_crlfiles;
47static Lisp_Object QCgnutls_bootprop_callbacks;
48static Lisp_Object QCgnutls_bootprop_loglevel;
49static Lisp_Object QCgnutls_bootprop_hostname;
50static Lisp_Object QCgnutls_bootprop_min_prime_bits;
51static Lisp_Object QCgnutls_bootprop_verify_flags;
52static Lisp_Object QCgnutls_bootprop_verify_hostname_error;
e061a11b
TZ
53
54/* Callback keys for `gnutls-boot'. Unused currently. */
a3720aa2 55static Lisp_Object QCgnutls_bootprop_callbacks_verify;
c1ae068b 56
0898ca10
JB
57static void gnutls_log_function (int, const char *);
58static void gnutls_log_function2 (int, const char*, const char*);
59
60\f
61#ifdef WINDOWSNT
62
63/* Macro for defining functions that will be loaded from the GnuTLS DLL. */
dbdb9a7c 64#define DEF_GNUTLS_FN(rettype,func,args) static rettype (FAR CDECL *fn_##func)args
0898ca10
JB
65
66/* Macro for loading GnuTLS functions from the library. */
67#define LOAD_GNUTLS_FN(lib,func) { \
68 fn_##func = (void *) GetProcAddress (lib, #func); \
69 if (!fn_##func) return 0; \
70 }
71
72DEF_GNUTLS_FN (gnutls_alert_description_t, gnutls_alert_get,
b5f03016 73 (gnutls_session_t));
0898ca10 74DEF_GNUTLS_FN (const char *, gnutls_alert_get_name,
b5f03016 75 (gnutls_alert_description_t));
0898ca10
JB
76DEF_GNUTLS_FN (int, gnutls_alert_send_appropriate, (gnutls_session_t, int));
77DEF_GNUTLS_FN (int, gnutls_anon_allocate_client_credentials,
b5f03016 78 (gnutls_anon_client_credentials_t *));
0898ca10 79DEF_GNUTLS_FN (void, gnutls_anon_free_client_credentials,
b5f03016 80 (gnutls_anon_client_credentials_t));
0898ca10
JB
81DEF_GNUTLS_FN (int, gnutls_bye, (gnutls_session_t, gnutls_close_request_t));
82DEF_GNUTLS_FN (int, gnutls_certificate_allocate_credentials,
b5f03016 83 (gnutls_certificate_credentials_t *));
0898ca10 84DEF_GNUTLS_FN (void, gnutls_certificate_free_credentials,
b5f03016 85 (gnutls_certificate_credentials_t));
0898ca10 86DEF_GNUTLS_FN (const gnutls_datum_t *, gnutls_certificate_get_peers,
b5f03016 87 (gnutls_session_t, unsigned int *));
0898ca10 88DEF_GNUTLS_FN (void, gnutls_certificate_set_verify_flags,
b5f03016 89 (gnutls_certificate_credentials_t, unsigned int));
0898ca10 90DEF_GNUTLS_FN (int, gnutls_certificate_set_x509_crl_file,
b5f03016
AS
91 (gnutls_certificate_credentials_t, const char *,
92 gnutls_x509_crt_fmt_t));
0898ca10 93DEF_GNUTLS_FN (int, gnutls_certificate_set_x509_key_file,
b5f03016
AS
94 (gnutls_certificate_credentials_t, const char *, const char *,
95 gnutls_x509_crt_fmt_t));
0898ca10 96DEF_GNUTLS_FN (int, gnutls_certificate_set_x509_trust_file,
b5f03016
AS
97 (gnutls_certificate_credentials_t, const char *,
98 gnutls_x509_crt_fmt_t));
0898ca10 99DEF_GNUTLS_FN (gnutls_certificate_type_t, gnutls_certificate_type_get,
b5f03016 100 (gnutls_session_t));
0898ca10 101DEF_GNUTLS_FN (int, gnutls_certificate_verify_peers2,
b5f03016 102 (gnutls_session_t, unsigned int *));
0898ca10 103DEF_GNUTLS_FN (int, gnutls_credentials_set,
b5f03016 104 (gnutls_session_t, gnutls_credentials_type_t, void *));
0898ca10 105DEF_GNUTLS_FN (void, gnutls_deinit, (gnutls_session_t));
87e86684 106DEF_GNUTLS_FN (void, gnutls_dh_set_prime_bits,
b5f03016 107 (gnutls_session_t, unsigned int));
0898ca10
JB
108DEF_GNUTLS_FN (int, gnutls_error_is_fatal, (int));
109DEF_GNUTLS_FN (int, gnutls_global_init, (void));
110DEF_GNUTLS_FN (void, gnutls_global_set_log_function, (gnutls_log_func));
111DEF_GNUTLS_FN (void, gnutls_global_set_log_level, (int));
9cf9f756
PE
112DEF_GNUTLS_FN (void, gnutls_global_set_mem_functions,
113 (gnutls_alloc_function, gnutls_alloc_function,
114 gnutls_is_secure_function, gnutls_realloc_function,
115 gnutls_free_function));
0898ca10
JB
116DEF_GNUTLS_FN (int, gnutls_handshake, (gnutls_session_t));
117DEF_GNUTLS_FN (int, gnutls_init, (gnutls_session_t *, gnutls_connection_end_t));
118DEF_GNUTLS_FN (int, gnutls_priority_set_direct,
b5f03016 119 (gnutls_session_t, const char *, const char **));
0898ca10
JB
120DEF_GNUTLS_FN (size_t, gnutls_record_check_pending, (gnutls_session_t));
121DEF_GNUTLS_FN (ssize_t, gnutls_record_recv, (gnutls_session_t, void *, size_t));
122DEF_GNUTLS_FN (ssize_t, gnutls_record_send,
b5f03016 123 (gnutls_session_t, const void *, size_t));
0898ca10
JB
124DEF_GNUTLS_FN (const char *, gnutls_strerror, (int));
125DEF_GNUTLS_FN (void, gnutls_transport_set_errno, (gnutls_session_t, int));
651e947e 126DEF_GNUTLS_FN (const char *, gnutls_check_version, (const char *));
0898ca10
JB
127DEF_GNUTLS_FN (void, gnutls_transport_set_lowat, (gnutls_session_t, int));
128DEF_GNUTLS_FN (void, gnutls_transport_set_ptr2,
b5f03016
AS
129 (gnutls_session_t, gnutls_transport_ptr_t,
130 gnutls_transport_ptr_t));
0898ca10 131DEF_GNUTLS_FN (void, gnutls_transport_set_pull_function,
b5f03016 132 (gnutls_session_t, gnutls_pull_func));
0898ca10 133DEF_GNUTLS_FN (void, gnutls_transport_set_push_function,
b5f03016 134 (gnutls_session_t, gnutls_push_func));
0898ca10 135DEF_GNUTLS_FN (int, gnutls_x509_crt_check_hostname,
b5f03016 136 (gnutls_x509_crt_t, const char *));
0898ca10
JB
137DEF_GNUTLS_FN (void, gnutls_x509_crt_deinit, (gnutls_x509_crt_t));
138DEF_GNUTLS_FN (int, gnutls_x509_crt_import,
b5f03016
AS
139 (gnutls_x509_crt_t, const gnutls_datum_t *,
140 gnutls_x509_crt_fmt_t));
0898ca10
JB
141DEF_GNUTLS_FN (int, gnutls_x509_crt_init, (gnutls_x509_crt_t *));
142
18e27ea8 143static bool
d07ff9db 144init_gnutls_functions (void)
0898ca10
JB
145{
146 HMODULE library;
ac389d0c 147 int max_log_level = 1;
0898ca10 148
d07ff9db 149 if (!(library = w32_delayed_load (Qgnutls_dll)))
0898ca10 150 {
ac389d0c 151 GNUTLS_LOG (1, max_log_level, "GnuTLS library not found");
0898ca10
JB
152 return 0;
153 }
154
155 LOAD_GNUTLS_FN (library, gnutls_alert_get);
156 LOAD_GNUTLS_FN (library, gnutls_alert_get_name);
157 LOAD_GNUTLS_FN (library, gnutls_alert_send_appropriate);
158 LOAD_GNUTLS_FN (library, gnutls_anon_allocate_client_credentials);
159 LOAD_GNUTLS_FN (library, gnutls_anon_free_client_credentials);
160 LOAD_GNUTLS_FN (library, gnutls_bye);
161 LOAD_GNUTLS_FN (library, gnutls_certificate_allocate_credentials);
162 LOAD_GNUTLS_FN (library, gnutls_certificate_free_credentials);
163 LOAD_GNUTLS_FN (library, gnutls_certificate_get_peers);
164 LOAD_GNUTLS_FN (library, gnutls_certificate_set_verify_flags);
165 LOAD_GNUTLS_FN (library, gnutls_certificate_set_x509_crl_file);
166 LOAD_GNUTLS_FN (library, gnutls_certificate_set_x509_key_file);
167 LOAD_GNUTLS_FN (library, gnutls_certificate_set_x509_trust_file);
168 LOAD_GNUTLS_FN (library, gnutls_certificate_type_get);
169 LOAD_GNUTLS_FN (library, gnutls_certificate_verify_peers2);
170 LOAD_GNUTLS_FN (library, gnutls_credentials_set);
171 LOAD_GNUTLS_FN (library, gnutls_deinit);
87e86684 172 LOAD_GNUTLS_FN (library, gnutls_dh_set_prime_bits);
0898ca10
JB
173 LOAD_GNUTLS_FN (library, gnutls_error_is_fatal);
174 LOAD_GNUTLS_FN (library, gnutls_global_init);
175 LOAD_GNUTLS_FN (library, gnutls_global_set_log_function);
176 LOAD_GNUTLS_FN (library, gnutls_global_set_log_level);
9cf9f756 177 LOAD_GNUTLS_FN (library, gnutls_global_set_mem_functions);
0898ca10
JB
178 LOAD_GNUTLS_FN (library, gnutls_handshake);
179 LOAD_GNUTLS_FN (library, gnutls_init);
180 LOAD_GNUTLS_FN (library, gnutls_priority_set_direct);
181 LOAD_GNUTLS_FN (library, gnutls_record_check_pending);
182 LOAD_GNUTLS_FN (library, gnutls_record_recv);
183 LOAD_GNUTLS_FN (library, gnutls_record_send);
184 LOAD_GNUTLS_FN (library, gnutls_strerror);
185 LOAD_GNUTLS_FN (library, gnutls_transport_set_errno);
651e947e
EZ
186 LOAD_GNUTLS_FN (library, gnutls_check_version);
187 /* We don't need to call gnutls_transport_set_lowat in GnuTLS 2.11.1
188 and later, and the function was removed entirely in 3.0.0. */
189 if (!fn_gnutls_check_version ("2.11.1"))
190 LOAD_GNUTLS_FN (library, gnutls_transport_set_lowat);
0898ca10
JB
191 LOAD_GNUTLS_FN (library, gnutls_transport_set_ptr2);
192 LOAD_GNUTLS_FN (library, gnutls_transport_set_pull_function);
193 LOAD_GNUTLS_FN (library, gnutls_transport_set_push_function);
194 LOAD_GNUTLS_FN (library, gnutls_x509_crt_check_hostname);
195 LOAD_GNUTLS_FN (library, gnutls_x509_crt_deinit);
196 LOAD_GNUTLS_FN (library, gnutls_x509_crt_import);
197 LOAD_GNUTLS_FN (library, gnutls_x509_crt_init);
198
925a6be7 199 max_log_level = global_gnutls_log_level;
ac389d0c 200
d69621cc
JB
201 {
202 Lisp_Object name = CAR_SAFE (Fget (Qgnutls_dll, QCloaded_from));
203 GNUTLS_LOG2 (1, max_log_level, "GnuTLS library loaded:",
204 STRINGP (name) ? (const char *) SDATA (name) : "unknown");
205 }
206
0898ca10
JB
207 return 1;
208}
209
210#else /* !WINDOWSNT */
211
212#define fn_gnutls_alert_get gnutls_alert_get
213#define fn_gnutls_alert_get_name gnutls_alert_get_name
214#define fn_gnutls_alert_send_appropriate gnutls_alert_send_appropriate
215#define fn_gnutls_anon_allocate_client_credentials gnutls_anon_allocate_client_credentials
216#define fn_gnutls_anon_free_client_credentials gnutls_anon_free_client_credentials
217#define fn_gnutls_bye gnutls_bye
218#define fn_gnutls_certificate_allocate_credentials gnutls_certificate_allocate_credentials
219#define fn_gnutls_certificate_free_credentials gnutls_certificate_free_credentials
220#define fn_gnutls_certificate_get_peers gnutls_certificate_get_peers
221#define fn_gnutls_certificate_set_verify_flags gnutls_certificate_set_verify_flags
222#define fn_gnutls_certificate_set_x509_crl_file gnutls_certificate_set_x509_crl_file
639c109b 223#define fn_gnutls_certificate_set_x509_key_file gnutls_certificate_set_x509_key_file
520cf78a 224#define fn_gnutls_certificate_set_x509_trust_file gnutls_certificate_set_x509_trust_file
0898ca10
JB
225#define fn_gnutls_certificate_type_get gnutls_certificate_type_get
226#define fn_gnutls_certificate_verify_peers2 gnutls_certificate_verify_peers2
227#define fn_gnutls_credentials_set gnutls_credentials_set
228#define fn_gnutls_deinit gnutls_deinit
87e86684 229#define fn_gnutls_dh_set_prime_bits gnutls_dh_set_prime_bits
0898ca10
JB
230#define fn_gnutls_error_is_fatal gnutls_error_is_fatal
231#define fn_gnutls_global_init gnutls_global_init
232#define fn_gnutls_global_set_log_function gnutls_global_set_log_function
233#define fn_gnutls_global_set_log_level gnutls_global_set_log_level
9cf9f756 234#define fn_gnutls_global_set_mem_functions gnutls_global_set_mem_functions
0898ca10
JB
235#define fn_gnutls_handshake gnutls_handshake
236#define fn_gnutls_init gnutls_init
237#define fn_gnutls_priority_set_direct gnutls_priority_set_direct
238#define fn_gnutls_record_check_pending gnutls_record_check_pending
239#define fn_gnutls_record_recv gnutls_record_recv
240#define fn_gnutls_record_send gnutls_record_send
241#define fn_gnutls_strerror gnutls_strerror
242#define fn_gnutls_transport_set_errno gnutls_transport_set_errno
0898ca10 243#define fn_gnutls_transport_set_ptr2 gnutls_transport_set_ptr2
0898ca10
JB
244#define fn_gnutls_x509_crt_check_hostname gnutls_x509_crt_check_hostname
245#define fn_gnutls_x509_crt_deinit gnutls_x509_crt_deinit
246#define fn_gnutls_x509_crt_import gnutls_x509_crt_import
247#define fn_gnutls_x509_crt_init gnutls_x509_crt_init
248
249#endif /* !WINDOWSNT */
250
251\f
a18ecafa 252/* Function to log a simple message. */
74f1829d 253static void
e061a11b
TZ
254gnutls_log_function (int level, const char* string)
255{
256 message ("gnutls.c: [%d] %s", level, string);
257}
258
a18ecafa 259/* Function to log a message and a string. */
e061a11b
TZ
260static void
261gnutls_log_function2 (int level, const char* string, const char* extra)
262{
263 message ("gnutls.c: [%d] %s %s", level, string, extra);
264}
265
a18ecafa
TZ
266/* Function to log a message and an integer. */
267static void
268gnutls_log_function2i (int level, const char* string, int extra)
269{
270 message ("gnutls.c: [%d] %s %d", level, string, extra);
271}
272
e061a11b 273static int
bac5cef8
LMI
274emacs_gnutls_handshake (struct Lisp_Process *proc)
275{
276 gnutls_session_t state = proc->gnutls_state;
277 int ret;
278
279 if (proc->gnutls_initstage < GNUTLS_STAGE_HANDSHAKE_CANDO)
6a7a1b0b 280 return -1;
bac5cef8
LMI
281
282 if (proc->gnutls_initstage < GNUTLS_STAGE_TRANSPORT_POINTERS_SET)
e6059fa2 283 {
e061a11b
TZ
284#ifdef WINDOWSNT
285 /* On W32 we cannot transfer socket handles between different runtime
b5f03016
AS
286 libraries, so we tell GnuTLS to use our special push/pull
287 functions. */
0898ca10 288 fn_gnutls_transport_set_ptr2 (state,
b5f03016
AS
289 (gnutls_transport_ptr_t) proc,
290 (gnutls_transport_ptr_t) proc);
0898ca10
JB
291 fn_gnutls_transport_set_push_function (state, &emacs_gnutls_push);
292 fn_gnutls_transport_set_pull_function (state, &emacs_gnutls_pull);
e061a11b
TZ
293
294 /* For non blocking sockets or other custom made pull/push
b5f03016
AS
295 functions the gnutls_transport_set_lowat must be called, with
296 a zero low water mark value. (GnuTLS 2.10.4 documentation)
e061a11b 297
b5f03016
AS
298 (Note: this is probably not strictly necessary as the lowat
299 value is only used when no custom pull/push functions are
300 set.) */
651e947e
EZ
301 /* According to GnuTLS NEWS file, lowat level has been set to
302 zero by default in version 2.11.1, and the function
303 gnutls_transport_set_lowat was removed from the library in
304 version 2.99.0. */
305 if (!fn_gnutls_check_version ("2.11.1"))
306 fn_gnutls_transport_set_lowat (state, 0);
e061a11b 307#else
c1ae068b 308 /* This is how GnuTLS takes sockets: as file descriptors passed
b5f03016
AS
309 in. For an Emacs process socket, infd and outfd are the
310 same but we use this two-argument version for clarity. */
0898ca10 311 fn_gnutls_transport_set_ptr2 (state,
b5f03016
AS
312 (gnutls_transport_ptr_t) (long) proc->infd,
313 (gnutls_transport_ptr_t) (long) proc->outfd);
e061a11b 314#endif
bac5cef8 315
e6059fa2
LMI
316 proc->gnutls_initstage = GNUTLS_STAGE_TRANSPORT_POINTERS_SET;
317 }
bac5cef8 318
e061a11b
TZ
319 do
320 {
0898ca10 321 ret = fn_gnutls_handshake (state);
e061a11b 322 emacs_gnutls_handle_error (state, ret);
57570cd3 323 QUIT;
e061a11b 324 }
0898ca10 325 while (ret < 0 && fn_gnutls_error_is_fatal (ret) == 0);
e061a11b 326
bac5cef8
LMI
327 proc->gnutls_initstage = GNUTLS_STAGE_HANDSHAKE_TRIED;
328
329 if (ret == GNUTLS_E_SUCCESS)
e6059fa2 330 {
e061a11b 331 /* Here we're finally done. */
e6059fa2
LMI
332 proc->gnutls_initstage = GNUTLS_STAGE_READY;
333 }
e061a11b
TZ
334 else
335 {
0898ca10 336 fn_gnutls_alert_send_appropriate (state, ret);
e061a11b
TZ
337 }
338 return ret;
bac5cef8
LMI
339}
340
0898ca10
JB
341int
342emacs_gnutls_record_check_pending (gnutls_session_t state)
343{
344 return fn_gnutls_record_check_pending (state);
345}
346
347void
348emacs_gnutls_transport_set_errno (gnutls_session_t state, int err)
349{
350 fn_gnutls_transport_set_errno (state, err);
351}
352
d311d28c
PE
353ptrdiff_t
354emacs_gnutls_write (struct Lisp_Process *proc, const char *buf, ptrdiff_t nbyte)
8af55556 355{
c8926152 356 ssize_t rtnval = 0;
d311d28c 357 ptrdiff_t bytes_written;
df7fcaff
LMI
358 gnutls_session_t state = proc->gnutls_state;
359
0ca43699
AS
360 if (proc->gnutls_initstage != GNUTLS_STAGE_READY)
361 {
0ca43699 362 errno = EAGAIN;
0ca43699
AS
363 return 0;
364 }
8af55556
TZ
365
366 bytes_written = 0;
367
368 while (nbyte > 0)
369 {
0898ca10 370 rtnval = fn_gnutls_record_send (state, buf, nbyte);
8af55556 371
2e6c74c5 372 if (rtnval < 0)
b5f03016 373 {
77abcbc2 374 if (rtnval == GNUTLS_E_INTERRUPTED)
b5f03016
AS
375 continue;
376 else
0ca43699
AS
377 {
378 /* If we get GNUTLS_E_AGAIN, then set errno
379 appropriately so that send_process retries the
380 correct way instead of erroring out. */
381 if (rtnval == GNUTLS_E_AGAIN)
22626a85 382 errno = EAGAIN;
0ca43699 383 break;
2e8f3c56 384 }
b5f03016 385 }
8af55556
TZ
386
387 buf += rtnval;
388 nbyte -= rtnval;
389 bytes_written += rtnval;
390 }
8af55556 391
e061a11b 392 emacs_gnutls_handle_error (state, rtnval);
8af55556
TZ
393 return (bytes_written);
394}
395
d311d28c
PE
396ptrdiff_t
397emacs_gnutls_read (struct Lisp_Process *proc, char *buf, ptrdiff_t nbyte)
8af55556 398{
368f4090 399 ssize_t rtnval;
df7fcaff
LMI
400 gnutls_session_t state = proc->gnutls_state;
401
a18ecafa
TZ
402 int log_level = proc->gnutls_log_level;
403
e6059fa2
LMI
404 if (proc->gnutls_initstage != GNUTLS_STAGE_READY)
405 {
a18ecafa
TZ
406 /* If the handshake count is under the limit, try the handshake
407 again and increment the handshake count. This count is kept
408 per process (connection), not globally. */
409 if (proc->gnutls_handshakes_tried < GNUTLS_EMACS_HANDSHAKES_LIMIT)
410 {
411 proc->gnutls_handshakes_tried++;
412 emacs_gnutls_handshake (proc);
02fd101b 413 GNUTLS_LOG2i (5, log_level, "Retried handshake",
a18ecafa
TZ
414 proc->gnutls_handshakes_tried);
415 return -1;
416 }
417
418 GNUTLS_LOG (2, log_level, "Giving up on handshake; resetting retries");
419 proc->gnutls_handshakes_tried = 0;
420 return 0;
e6059fa2 421 }
0898ca10 422 rtnval = fn_gnutls_record_recv (state, buf, nbyte);
ec9f09be
LMI
423 if (rtnval >= 0)
424 return rtnval;
dbf38e02
LMI
425 else if (rtnval == GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
426 /* The peer closed the connection. */
427 return 0;
18e27ea8 428 else if (emacs_gnutls_handle_error (state, rtnval))
e061a11b
TZ
429 /* non-fatal error */
430 return -1;
4b2d9ec2 431 else {
9173deec 432 /* a fatal error occurred */
e061a11b 433 return 0;
4b2d9ec2 434 }
8af55556
TZ
435}
436
18e27ea8
PE
437/* Report a GnuTLS error to the user.
438 Return true if the error code was successfully handled. */
439static bool
e061a11b
TZ
440emacs_gnutls_handle_error (gnutls_session_t session, int err)
441{
e061a11b
TZ
442 int max_log_level = 0;
443
18e27ea8 444 bool ret;
e061a11b
TZ
445 const char *str;
446
447 /* TODO: use a Lisp_Object generated by gnutls_make_error? */
448 if (err >= 0)
18e27ea8 449 return 1;
e061a11b 450
925a6be7 451 max_log_level = global_gnutls_log_level;
e061a11b
TZ
452
453 /* TODO: use gnutls-error-fatalp and gnutls-error-string. */
454
0898ca10 455 str = fn_gnutls_strerror (err);
e061a11b
TZ
456 if (!str)
457 str = "unknown";
458
0898ca10 459 if (fn_gnutls_error_is_fatal (err))
e061a11b 460 {
18e27ea8 461 ret = 0;
e061a11b
TZ
462 GNUTLS_LOG2 (0, max_log_level, "fatal error:", str);
463 }
464 else
465 {
18e27ea8 466 ret = 1;
e061a11b
TZ
467 GNUTLS_LOG2 (1, max_log_level, "non-fatal error:", str);
468 /* TODO: EAGAIN AKA Qgnutls_e_again should be level 2. */
469 }
470
471 if (err == GNUTLS_E_WARNING_ALERT_RECEIVED
472 || err == GNUTLS_E_FATAL_ALERT_RECEIVED)
473 {
0898ca10 474 int alert = fn_gnutls_alert_get (session);
e061a11b 475 int level = (err == GNUTLS_E_FATAL_ALERT_RECEIVED) ? 0 : 1;
0898ca10 476 str = fn_gnutls_alert_get_name (alert);
e061a11b
TZ
477 if (!str)
478 str = "unknown";
479
480 GNUTLS_LOG2 (level, max_log_level, "Received alert: ", str);
481 }
482 return ret;
483}
484
8af55556
TZ
485/* convert an integer error to a Lisp_Object; it will be either a
486 known symbol like `gnutls_e_interrupted' and `gnutls_e_again' or
487 simply the integer value of the error. GNUTLS_E_SUCCESS is mapped
488 to Qt. */
74f1829d 489static Lisp_Object
ec8df744 490gnutls_make_error (int err)
8af55556 491{
ec8df744 492 switch (err)
e6059fa2
LMI
493 {
494 case GNUTLS_E_SUCCESS:
495 return Qt;
496 case GNUTLS_E_AGAIN:
497 return Qgnutls_e_again;
498 case GNUTLS_E_INTERRUPTED:
499 return Qgnutls_e_interrupted;
500 case GNUTLS_E_INVALID_SESSION:
501 return Qgnutls_e_invalid_session;
502 }
8af55556 503
ec8df744 504 return make_number (err);
8af55556
TZ
505}
506
9c6c6f49
CY
507Lisp_Object
508emacs_gnutls_deinit (Lisp_Object proc)
509{
510 int log_level;
511
512 CHECK_PROCESS (proc);
513
514 if (XPROCESS (proc)->gnutls_p == 0)
515 return Qnil;
516
517 log_level = XPROCESS (proc)->gnutls_log_level;
518
519 if (XPROCESS (proc)->gnutls_x509_cred)
520 {
521 GNUTLS_LOG (2, log_level, "Deallocating x509 credentials");
522 fn_gnutls_certificate_free_credentials (XPROCESS (proc)->gnutls_x509_cred);
523 XPROCESS (proc)->gnutls_x509_cred = NULL;
524 }
525
526 if (XPROCESS (proc)->gnutls_anon_cred)
527 {
528 GNUTLS_LOG (2, log_level, "Deallocating anon credentials");
529 fn_gnutls_anon_free_client_credentials (XPROCESS (proc)->gnutls_anon_cred);
530 XPROCESS (proc)->gnutls_anon_cred = NULL;
531 }
532
435c1d67 533 if (XPROCESS (proc)->gnutls_state)
9c6c6f49
CY
534 {
535 fn_gnutls_deinit (XPROCESS (proc)->gnutls_state);
435c1d67
CY
536 XPROCESS (proc)->gnutls_state = NULL;
537 if (GNUTLS_INITSTAGE (proc) >= GNUTLS_STAGE_INIT)
538 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_INIT - 1;
9c6c6f49
CY
539 }
540
541 XPROCESS (proc)->gnutls_p = 0;
542 return Qt;
543}
544
8af55556 545DEFUN ("gnutls-get-initstage", Fgnutls_get_initstage, Sgnutls_get_initstage, 1, 1, 0,
74f1829d 546 doc: /* Return the GnuTLS init stage of process PROC.
8af55556 547See also `gnutls-boot'. */)
74f1829d 548 (Lisp_Object proc)
8af55556
TZ
549{
550 CHECK_PROCESS (proc);
551
552 return make_number (GNUTLS_INITSTAGE (proc));
553}
554
555DEFUN ("gnutls-errorp", Fgnutls_errorp, Sgnutls_errorp, 1, 1, 0,
74f1829d
JB
556 doc: /* Return t if ERROR indicates a GnuTLS problem.
557ERROR is an integer or a symbol with an integer `gnutls-code' property.
558usage: (gnutls-errorp ERROR) */)
559 (Lisp_Object err)
8af55556 560{
74f1829d 561 if (EQ (err, Qt)) return Qnil;
8af55556
TZ
562
563 return Qt;
564}
565
566DEFUN ("gnutls-error-fatalp", Fgnutls_error_fatalp, Sgnutls_error_fatalp, 1, 1, 0,
74f1829d
JB
567 doc: /* Check if ERROR is fatal.
568ERROR is an integer or a symbol with an integer `gnutls-code' property.
569usage: (gnutls-error-fatalp ERROR) */)
570 (Lisp_Object err)
8af55556
TZ
571{
572 Lisp_Object code;
573
574 if (EQ (err, Qt)) return Qnil;
575
576 if (SYMBOLP (err))
8af55556 577 {
e6059fa2
LMI
578 code = Fget (err, Qgnutls_code);
579 if (NUMBERP (code))
580 {
581 err = code;
582 }
583 else
584 {
585 error ("Symbol has no numeric gnutls-code property");
586 }
8af55556 587 }
8af55556 588
d311d28c 589 if (! TYPE_RANGED_INTEGERP (int, err))
8af55556
TZ
590 error ("Not an error symbol or code");
591
0898ca10 592 if (0 == fn_gnutls_error_is_fatal (XINT (err)))
8af55556
TZ
593 return Qnil;
594
595 return Qt;
596}
597
598DEFUN ("gnutls-error-string", Fgnutls_error_string, Sgnutls_error_string, 1, 1, 0,
74f1829d
JB
599 doc: /* Return a description of ERROR.
600ERROR is an integer or a symbol with an integer `gnutls-code' property.
601usage: (gnutls-error-string ERROR) */)
602 (Lisp_Object err)
8af55556
TZ
603{
604 Lisp_Object code;
605
606 if (EQ (err, Qt)) return build_string ("Not an error");
607
608 if (SYMBOLP (err))
8af55556 609 {
e6059fa2
LMI
610 code = Fget (err, Qgnutls_code);
611 if (NUMBERP (code))
612 {
613 err = code;
614 }
615 else
616 {
617 return build_string ("Symbol has no numeric gnutls-code property");
618 }
8af55556 619 }
8af55556 620
d311d28c 621 if (! TYPE_RANGED_INTEGERP (int, err))
8af55556
TZ
622 return build_string ("Not an error symbol or code");
623
0898ca10 624 return build_string (fn_gnutls_strerror (XINT (err)));
8af55556
TZ
625}
626
627DEFUN ("gnutls-deinit", Fgnutls_deinit, Sgnutls_deinit, 1, 1, 0,
e1b69165 628 doc: /* Deallocate GnuTLS resources associated with process PROC.
8af55556 629See also `gnutls-init'. */)
74f1829d 630 (Lisp_Object proc)
8af55556 631{
9c6c6f49 632 return emacs_gnutls_deinit (proc);
8af55556
TZ
633}
634
0898ca10
JB
635DEFUN ("gnutls-available-p", Fgnutls_available_p, Sgnutls_available_p, 0, 0, 0,
636 doc: /* Return t if GnuTLS is available in this instance of Emacs. */)
637 (void)
638{
639#ifdef WINDOWSNT
640 Lisp_Object found = Fassq (Qgnutls_dll, Vlibrary_cache);
641 if (CONSP (found))
642 return XCDR (found);
643 else
644 {
645 Lisp_Object status;
d07ff9db 646 status = init_gnutls_functions () ? Qt : Qnil;
0898ca10
JB
647 Vlibrary_cache = Fcons (Fcons (Qgnutls_dll, status), Vlibrary_cache);
648 return status;
649 }
650#else
651 return Qt;
652#endif
653}
654
655
e1b69165
JB
656/* Initializes global GnuTLS state to defaults.
657Call `gnutls-global-deinit' when GnuTLS usage is no longer needed.
8af55556 658Returns zero on success. */
74f1829d 659static Lisp_Object
e061a11b 660emacs_gnutls_global_init (void)
8af55556
TZ
661{
662 int ret = GNUTLS_E_SUCCESS;
663
e061a11b 664 if (!gnutls_global_initialized)
9cf9f756
PE
665 {
666 fn_gnutls_global_set_mem_functions (xmalloc, xmalloc, NULL,
667 xrealloc, xfree);
668 ret = fn_gnutls_global_init ();
669 }
e061a11b 670 gnutls_global_initialized = 1;
8af55556
TZ
671
672 return gnutls_make_error (ret);
673}
674
ec8df744 675#if 0
e1b69165 676/* Deinitializes global GnuTLS state.
8af55556 677See also `gnutls-global-init'. */
74f1829d 678static Lisp_Object
e061a11b 679emacs_gnutls_global_deinit (void)
8af55556 680{
e061a11b 681 if (gnutls_global_initialized)
8af55556
TZ
682 gnutls_global_deinit ();
683
e061a11b 684 gnutls_global_initialized = 0;
8af55556
TZ
685
686 return gnutls_make_error (GNUTLS_E_SUCCESS);
687}
ec8df744 688#endif
8af55556 689
c1ae068b
LMI
690DEFUN ("gnutls-boot", Fgnutls_boot, Sgnutls_boot, 3, 3, 0,
691 doc: /* Initialize GnuTLS client for process PROC with TYPE+PROPLIST.
435c1d67 692Currently only client mode is supported. Return a success/failure
8af55556
TZ
693value you can check with `gnutls-errorp'.
694
c1ae068b
LMI
695TYPE is a symbol, either `gnutls-anon' or `gnutls-x509pki'.
696PROPLIST is a property list with the following keys:
697
e061a11b
TZ
698:hostname is a string naming the remote host.
699
c1ae068b 700:priority is a GnuTLS priority string, defaults to "NORMAL".
e061a11b 701
c1ae068b 702:trustfiles is a list of PEM-encoded trust files for `gnutls-x509pki'.
e061a11b 703
ff4de4aa
TZ
704:crlfiles is a list of PEM-encoded CRL lists for `gnutls-x509pki'.
705
706:keylist is an alist of PEM-encoded key files and PEM-encoded
707certificates for `gnutls-x509pki'.
e061a11b
TZ
708
709:callbacks is an alist of callback functions, see below.
710
c1ae068b 711:loglevel is the debug level requested from GnuTLS, try 4.
8ed70bf3 712
e061a11b
TZ
713:verify-flags is a bitset as per GnuTLS'
714gnutls_certificate_set_verify_flags.
715
e061a11b
TZ
716:verify-hostname-error, if non-nil, makes a hostname mismatch an
717error. Otherwise it will be just a warning.
718
87e86684
LM
719:min-prime-bits is the minimum accepted number of bits the client will
720accept in Diffie-Hellman key exchange.
721
c1ae068b
LMI
722The debug level will be set for this process AND globally for GnuTLS.
723So if you set it higher or lower at any point, it affects global
724debugging.
8af55556
TZ
725
726Note that the priority is set on the client. The server does not use
727the protocols's priority except for disabling protocols that were not
728specified.
729
74f1829d 730Processes must be initialized with this function before other GnuTLS
8af55556
TZ
731functions are used. This function allocates resources which can only
732be deallocated by calling `gnutls-deinit' or by calling it again.
733
e061a11b
TZ
734The callbacks alist can have a `verify' key, associated with a
735verification function (UNUSED).
736
8af55556 737Each authentication type may need additional information in order to
c1ae068b
LMI
738work. For X.509 PKI (`gnutls-x509pki'), you probably need at least
739one trustfile (usually a CA bundle). */)
740 (Lisp_Object proc, Lisp_Object type, Lisp_Object proplist)
8af55556
TZ
741{
742 int ret = GNUTLS_E_SUCCESS;
8ed70bf3
LMI
743 int max_log_level = 0;
744
8af55556 745 gnutls_session_t state;
435c1d67
CY
746 gnutls_certificate_credentials_t x509_cred = NULL;
747 gnutls_anon_client_credentials_t anon_cred = NULL;
8af55556 748 Lisp_Object global_init;
ec8df744 749 char const *priority_string_ptr = "NORMAL"; /* default priority string. */
7754e151 750 unsigned int peer_verification;
e061a11b 751 char* c_hostname;
c1ae068b
LMI
752
753 /* Placeholders for the property list elements. */
754 Lisp_Object priority_string;
755 Lisp_Object trustfiles;
ff4de4aa
TZ
756 Lisp_Object crlfiles;
757 Lisp_Object keylist;
ec8df744 758 /* Lisp_Object callbacks; */
c1ae068b 759 Lisp_Object loglevel;
e061a11b 760 Lisp_Object hostname;
8d4c3955 761 /* Lisp_Object verify_error; */
e061a11b 762 Lisp_Object verify_hostname_error;
87e86684 763 Lisp_Object prime_bits;
8af55556
TZ
764
765 CHECK_PROCESS (proc);
766 CHECK_SYMBOL (type);
c1ae068b
LMI
767 CHECK_LIST (proplist);
768
0898ca10
JB
769 if (NILP (Fgnutls_available_p ()))
770 {
771 error ("GnuTLS not available");
772 return gnutls_make_error (GNUTLS_EMACS_ERROR_NOT_LOADED);
773 }
774
435c1d67
CY
775 if (!EQ (type, Qgnutls_x509pki) && !EQ (type, Qgnutls_anon))
776 {
777 error ("Invalid GnuTLS credential type");
778 return gnutls_make_error (GNUTLS_EMACS_ERROR_INVALID_TYPE);
779 }
780
a3720aa2
AS
781 hostname = Fplist_get (proplist, QCgnutls_bootprop_hostname);
782 priority_string = Fplist_get (proplist, QCgnutls_bootprop_priority);
783 trustfiles = Fplist_get (proplist, QCgnutls_bootprop_trustfiles);
784 keylist = Fplist_get (proplist, QCgnutls_bootprop_keylist);
785 crlfiles = Fplist_get (proplist, QCgnutls_bootprop_crlfiles);
a3720aa2 786 loglevel = Fplist_get (proplist, QCgnutls_bootprop_loglevel);
a3720aa2
AS
787 verify_hostname_error = Fplist_get (proplist, QCgnutls_bootprop_verify_hostname_error);
788 prime_bits = Fplist_get (proplist, QCgnutls_bootprop_min_prime_bits);
e061a11b
TZ
789
790 if (!STRINGP (hostname))
791 error ("gnutls-boot: invalid :hostname parameter");
e061a11b 792 c_hostname = SSDATA (hostname);
8af55556
TZ
793
794 state = XPROCESS (proc)->gnutls_state;
df7fcaff 795 XPROCESS (proc)->gnutls_p = 1;
8af55556 796
d311d28c 797 if (TYPE_RANGED_INTEGERP (int, loglevel))
8ed70bf3 798 {
0898ca10
JB
799 fn_gnutls_global_set_log_function (gnutls_log_function);
800 fn_gnutls_global_set_log_level (XINT (loglevel));
8ed70bf3
LMI
801 max_log_level = XINT (loglevel);
802 XPROCESS (proc)->gnutls_log_level = max_log_level;
803 }
df7fcaff 804
8af55556 805 /* always initialize globals. */
e061a11b 806 global_init = emacs_gnutls_global_init ();
8af55556
TZ
807 if (! NILP (Fgnutls_errorp (global_init)))
808 return global_init;
809
9c6c6f49
CY
810 /* Before allocating new credentials, deallocate any credentials
811 that PROC might already have. */
812 emacs_gnutls_deinit (proc);
8af55556 813
9c6c6f49
CY
814 /* Mark PROC as a GnuTLS process. */
815 XPROCESS (proc)->gnutls_p = 1;
435c1d67 816 XPROCESS (proc)->gnutls_state = NULL;
9c6c6f49
CY
817 XPROCESS (proc)->gnutls_x509_cred = NULL;
818 XPROCESS (proc)->gnutls_anon_cred = NULL;
6a09a33b 819 pset_gnutls_cred_type (XPROCESS (proc), type);
8af55556
TZ
820 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_EMPTY;
821
8ed70bf3 822 GNUTLS_LOG (1, max_log_level, "allocating credentials");
8af55556 823 if (EQ (type, Qgnutls_x509pki))
e6059fa2 824 {
435c1d67
CY
825 Lisp_Object verify_flags;
826 unsigned int gnutls_verify_flags = GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT;
827
8ed70bf3 828 GNUTLS_LOG (2, max_log_level, "allocating x509 credentials");
9cf9f756 829 fn_gnutls_certificate_allocate_credentials (&x509_cred);
435c1d67 830 XPROCESS (proc)->gnutls_x509_cred = x509_cred;
e061a11b 831
435c1d67 832 verify_flags = Fplist_get (proplist, QCgnutls_bootprop_verify_flags);
e061a11b 833 if (NUMBERP (verify_flags))
b5f03016
AS
834 {
835 gnutls_verify_flags = XINT (verify_flags);
836 GNUTLS_LOG (2, max_log_level, "setting verification flags");
837 }
e061a11b 838 else if (NILP (verify_flags))
435c1d67 839 GNUTLS_LOG (2, max_log_level, "using default verification flags");
e061a11b 840 else
435c1d67
CY
841 GNUTLS_LOG (2, max_log_level, "ignoring invalid verify-flags");
842
0898ca10 843 fn_gnutls_certificate_set_verify_flags (x509_cred, gnutls_verify_flags);
e6059fa2 844 }
435c1d67 845 else /* Qgnutls_anon: */
e6059fa2 846 {
8ed70bf3 847 GNUTLS_LOG (2, max_log_level, "allocating anon credentials");
9cf9f756 848 fn_gnutls_anon_allocate_client_credentials (&anon_cred);
435c1d67 849 XPROCESS (proc)->gnutls_anon_cred = anon_cred;
e6059fa2 850 }
8af55556
TZ
851
852 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_CRED_ALLOC;
853
8af55556 854 if (EQ (type, Qgnutls_x509pki))
e6059fa2 855 {
435c1d67
CY
856 /* TODO: GNUTLS_X509_FMT_DER is also an option. */
857 int file_format = GNUTLS_X509_FMT_PEM;
858 Lisp_Object tail;
859
7d7bbefd 860 for (tail = trustfiles; CONSP (tail); tail = XCDR (tail))
e6059fa2 861 {
34348bd4 862 Lisp_Object trustfile = XCAR (tail);
b5f03016
AS
863 if (STRINGP (trustfile))
864 {
865 GNUTLS_LOG2 (1, max_log_level, "setting the trustfile: ",
866 SSDATA (trustfile));
867 ret = fn_gnutls_certificate_set_x509_trust_file
868 (x509_cred,
869 SSDATA (trustfile),
870 file_format);
871
872 if (ret < GNUTLS_E_SUCCESS)
873 return gnutls_make_error (ret);
874 }
875 else
876 {
435c1d67
CY
877 emacs_gnutls_deinit (proc);
878 error ("Invalid trustfile");
b5f03016
AS
879 }
880 }
8af55556 881
7d7bbefd 882 for (tail = crlfiles; CONSP (tail); tail = XCDR (tail))
e6059fa2 883 {
34348bd4 884 Lisp_Object crlfile = XCAR (tail);
b5f03016
AS
885 if (STRINGP (crlfile))
886 {
887 GNUTLS_LOG2 (1, max_log_level, "setting the CRL file: ",
888 SSDATA (crlfile));
889 ret = fn_gnutls_certificate_set_x509_crl_file
435c1d67 890 (x509_cred, SSDATA (crlfile), file_format);
b5f03016
AS
891
892 if (ret < GNUTLS_E_SUCCESS)
893 return gnutls_make_error (ret);
894 }
895 else
896 {
435c1d67
CY
897 emacs_gnutls_deinit (proc);
898 error ("Invalid CRL file");
b5f03016
AS
899 }
900 }
ff4de4aa 901
7d7bbefd 902 for (tail = keylist; CONSP (tail); tail = XCDR (tail))
ff4de4aa 903 {
34348bd4 904 Lisp_Object keyfile = Fcar (XCAR (tail));
d96a1e0c 905 Lisp_Object certfile = Fcar (Fcdr (XCAR (tail)));
b5f03016
AS
906 if (STRINGP (keyfile) && STRINGP (certfile))
907 {
908 GNUTLS_LOG2 (1, max_log_level, "setting the client key file: ",
909 SSDATA (keyfile));
910 GNUTLS_LOG2 (1, max_log_level, "setting the client cert file: ",
911 SSDATA (certfile));
912 ret = fn_gnutls_certificate_set_x509_key_file
435c1d67 913 (x509_cred, SSDATA (certfile), SSDATA (keyfile), file_format);
b5f03016
AS
914
915 if (ret < GNUTLS_E_SUCCESS)
916 return gnutls_make_error (ret);
917 }
918 else
919 {
435c1d67
CY
920 emacs_gnutls_deinit (proc);
921 error (STRINGP (keyfile) ? "Invalid client cert file"
922 : "Invalid client key file");
b5f03016
AS
923 }
924 }
e6059fa2 925 }
8af55556
TZ
926
927 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_FILES;
e061a11b 928 GNUTLS_LOG (1, max_log_level, "gnutls callbacks");
e061a11b
TZ
929 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_CALLBACKS;
930
435c1d67 931 /* Call gnutls_init here: */
e061a11b 932
8ed70bf3 933 GNUTLS_LOG (1, max_log_level, "gnutls_init");
0898ca10 934 ret = fn_gnutls_init (&state, GNUTLS_CLIENT);
435c1d67 935 XPROCESS (proc)->gnutls_state = state;
8af55556 936 if (ret < GNUTLS_E_SUCCESS)
e6059fa2 937 return gnutls_make_error (ret);
8af55556
TZ
938 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_INIT;
939
c1ae068b
LMI
940 if (STRINGP (priority_string))
941 {
51b59d79 942 priority_string_ptr = SSDATA (priority_string);
c1ae068b 943 GNUTLS_LOG2 (1, max_log_level, "got non-default priority string:",
b5f03016 944 priority_string_ptr);
c1ae068b
LMI
945 }
946 else
947 {
948 GNUTLS_LOG2 (1, max_log_level, "using default priority string:",
b5f03016 949 priority_string_ptr);
c1ae068b 950 }
51b59d79 951
8ed70bf3 952 GNUTLS_LOG (1, max_log_level, "setting the priority string");
0898ca10 953 ret = fn_gnutls_priority_set_direct (state,
b5f03016
AS
954 priority_string_ptr,
955 NULL);
8af55556 956 if (ret < GNUTLS_E_SUCCESS)
e6059fa2 957 return gnutls_make_error (ret);
8af55556
TZ
958
959 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_PRIORITY;
960
435c1d67
CY
961 if (INTEGERP (prime_bits))
962 fn_gnutls_dh_set_prime_bits (state, XUINT (prime_bits));
8af55556 963
435c1d67
CY
964 ret = EQ (type, Qgnutls_x509pki)
965 ? fn_gnutls_credentials_set (state, GNUTLS_CRD_CERTIFICATE, x509_cred)
966 : fn_gnutls_credentials_set (state, GNUTLS_CRD_ANON, anon_cred);
8af55556 967 if (ret < GNUTLS_E_SUCCESS)
e6059fa2 968 return gnutls_make_error (ret);
8af55556 969
8af55556 970 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_CRED_SET;
e061a11b 971 ret = emacs_gnutls_handshake (XPROCESS (proc));
e061a11b
TZ
972 if (ret < GNUTLS_E_SUCCESS)
973 return gnutls_make_error (ret);
974
975 /* Now verify the peer, following
976 http://www.gnu.org/software/gnutls/manual/html_node/Verifying-peer_0027s-certificate.html.
977 The peer should present at least one certificate in the chain; do a
978 check of the certificate's hostname with
979 gnutls_x509_crt_check_hostname() against :hostname. */
980
0898ca10 981 ret = fn_gnutls_certificate_verify_peers2 (state, &peer_verification);
e061a11b
TZ
982 if (ret < GNUTLS_E_SUCCESS)
983 return gnutls_make_error (ret);
671875da 984
e061a11b 985 if (XINT (loglevel) > 0 && peer_verification & GNUTLS_CERT_INVALID)
435c1d67
CY
986 message ("%s certificate could not be verified.", c_hostname);
987
988 if (peer_verification & GNUTLS_CERT_REVOKED)
989 GNUTLS_LOG2 (1, max_log_level, "certificate was revoked (CRL):",
990 c_hostname);
991
992 if (peer_verification & GNUTLS_CERT_SIGNER_NOT_FOUND)
993 GNUTLS_LOG2 (1, max_log_level, "certificate signer was not found:",
994 c_hostname);
995
996 if (peer_verification & GNUTLS_CERT_SIGNER_NOT_CA)
997 GNUTLS_LOG2 (1, max_log_level, "certificate signer is not a CA:",
998 c_hostname);
999
1000 if (peer_verification & GNUTLS_CERT_INSECURE_ALGORITHM)
1001 GNUTLS_LOG2 (1, max_log_level,
1002 "certificate was signed with an insecure algorithm:",
1003 c_hostname);
1004
1005 if (peer_verification & GNUTLS_CERT_NOT_ACTIVATED)
1006 GNUTLS_LOG2 (1, max_log_level, "certificate is not yet activated:",
1007 c_hostname);
1008
1009 if (peer_verification & GNUTLS_CERT_EXPIRED)
1010 GNUTLS_LOG2 (1, max_log_level, "certificate has expired:",
1011 c_hostname);
1012
1013 if (peer_verification != 0)
1014 {
1015 if (NILP (verify_hostname_error))
1016 GNUTLS_LOG2 (1, max_log_level, "certificate validation failed:",
1017 c_hostname);
1018 else
1019 {
1020 emacs_gnutls_deinit (proc);
1021 error ("Certificate validation failed %s, verification code %d",
1022 c_hostname, peer_verification);
1023 }
1024 }
e061a11b
TZ
1025
1026 /* Up to here the process is the same for X.509 certificates and
1027 OpenPGP keys. From now on X.509 certificates are assumed. This
1028 can be easily extended to work with openpgp keys as well. */
0898ca10 1029 if (fn_gnutls_certificate_type_get (state) == GNUTLS_CRT_X509)
e061a11b 1030 {
435c1d67
CY
1031 gnutls_x509_crt_t gnutls_verify_cert;
1032 const gnutls_datum_t *gnutls_verify_cert_list;
1033 unsigned int gnutls_verify_cert_list_size;
e061a11b 1034
435c1d67 1035 ret = fn_gnutls_x509_crt_init (&gnutls_verify_cert);
e061a11b 1036 if (ret < GNUTLS_E_SUCCESS)
b5f03016 1037 return gnutls_make_error (ret);
e061a11b 1038
671875da 1039 gnutls_verify_cert_list =
b5f03016 1040 fn_gnutls_certificate_get_peers (state, &gnutls_verify_cert_list_size);
e061a11b 1041
435c1d67 1042 if (gnutls_verify_cert_list == NULL)
b5f03016 1043 {
435c1d67
CY
1044 fn_gnutls_x509_crt_deinit (gnutls_verify_cert);
1045 emacs_gnutls_deinit (proc);
1046 error ("No x509 certificate was found\n");
b5f03016 1047 }
e061a11b
TZ
1048
1049 /* We only check the first certificate in the given chain. */
0898ca10 1050 ret = fn_gnutls_x509_crt_import (gnutls_verify_cert,
b5f03016
AS
1051 &gnutls_verify_cert_list[0],
1052 GNUTLS_X509_FMT_DER);
e061a11b
TZ
1053
1054 if (ret < GNUTLS_E_SUCCESS)
b5f03016
AS
1055 {
1056 fn_gnutls_x509_crt_deinit (gnutls_verify_cert);
1057 return gnutls_make_error (ret);
1058 }
e061a11b 1059
0898ca10 1060 if (!fn_gnutls_x509_crt_check_hostname (gnutls_verify_cert, c_hostname))
b5f03016
AS
1061 {
1062 if (NILP (verify_hostname_error))
435c1d67
CY
1063 GNUTLS_LOG2 (1, max_log_level, "x509 certificate does not match:",
1064 c_hostname);
b5f03016
AS
1065 else
1066 {
1067 fn_gnutls_x509_crt_deinit (gnutls_verify_cert);
435c1d67
CY
1068 emacs_gnutls_deinit (proc);
1069 error ("The x509 certificate does not match \"%s\"", c_hostname);
b5f03016
AS
1070 }
1071 }
0898ca10 1072 fn_gnutls_x509_crt_deinit (gnutls_verify_cert);
e061a11b
TZ
1073 }
1074
1075 return gnutls_make_error (ret);
8af55556
TZ
1076}
1077
1078DEFUN ("gnutls-bye", Fgnutls_bye,
1079 Sgnutls_bye, 2, 2, 0,
74f1829d 1080 doc: /* Terminate current GnuTLS connection for process PROC.
8af55556
TZ
1081The connection should have been initiated using `gnutls-handshake'.
1082
1083If CONT is not nil the TLS connection gets terminated and further
74f1829d 1084receives and sends will be disallowed. If the return value is zero you
8af55556
TZ
1085may continue using the connection. If CONT is nil, GnuTLS actually
1086sends an alert containing a close request and waits for the peer to
1087reply with the same message. In order to reuse the connection you
1088should wait for an EOF from the peer.
1089
1090This function may also return `gnutls-e-again', or
1091`gnutls-e-interrupted'. */)
1092 (Lisp_Object proc, Lisp_Object cont)
1093{
1094 gnutls_session_t state;
1095 int ret;
1096
1097 CHECK_PROCESS (proc);
1098
1099 state = XPROCESS (proc)->gnutls_state;
1100
0898ca10 1101 ret = fn_gnutls_bye (state,
b5f03016 1102 NILP (cont) ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR);
8af55556
TZ
1103
1104 return gnutls_make_error (ret);
1105}
1106
8af55556
TZ
1107void
1108syms_of_gnutls (void)
1109{
e061a11b
TZ
1110 gnutls_global_initialized = 0;
1111
a555cb87 1112 DEFSYM (Qgnutls_dll, "gnutls");
a555cb87
JB
1113 DEFSYM (Qgnutls_code, "gnutls-code");
1114 DEFSYM (Qgnutls_anon, "gnutls-anon");
1115 DEFSYM (Qgnutls_x509pki, "gnutls-x509pki");
a3720aa2
AS
1116 DEFSYM (QCgnutls_bootprop_hostname, ":hostname");
1117 DEFSYM (QCgnutls_bootprop_priority, ":priority");
1118 DEFSYM (QCgnutls_bootprop_trustfiles, ":trustfiles");
1119 DEFSYM (QCgnutls_bootprop_keylist, ":keylist");
1120 DEFSYM (QCgnutls_bootprop_crlfiles, ":crlfiles");
1121 DEFSYM (QCgnutls_bootprop_callbacks, ":callbacks");
1122 DEFSYM (QCgnutls_bootprop_callbacks_verify, "verify");
1123 DEFSYM (QCgnutls_bootprop_min_prime_bits, ":min-prime-bits");
1124 DEFSYM (QCgnutls_bootprop_loglevel, ":loglevel");
1125 DEFSYM (QCgnutls_bootprop_verify_flags, ":verify-flags");
1126 DEFSYM (QCgnutls_bootprop_verify_hostname_error, ":verify-hostname-error");
a555cb87
JB
1127
1128 DEFSYM (Qgnutls_e_interrupted, "gnutls-e-interrupted");
8af55556 1129 Fput (Qgnutls_e_interrupted, Qgnutls_code,
b5f03016 1130 make_number (GNUTLS_E_INTERRUPTED));
8af55556 1131
a555cb87 1132 DEFSYM (Qgnutls_e_again, "gnutls-e-again");
8af55556 1133 Fput (Qgnutls_e_again, Qgnutls_code,
b5f03016 1134 make_number (GNUTLS_E_AGAIN));
8af55556 1135
a555cb87 1136 DEFSYM (Qgnutls_e_invalid_session, "gnutls-e-invalid-session");
8af55556 1137 Fput (Qgnutls_e_invalid_session, Qgnutls_code,
b5f03016 1138 make_number (GNUTLS_E_INVALID_SESSION));
8af55556 1139
a555cb87 1140 DEFSYM (Qgnutls_e_not_ready_for_handshake, "gnutls-e-not-ready-for-handshake");
8af55556 1141 Fput (Qgnutls_e_not_ready_for_handshake, Qgnutls_code,
b5f03016 1142 make_number (GNUTLS_E_APPLICATION_ERROR_MIN));
8af55556
TZ
1143
1144 defsubr (&Sgnutls_get_initstage);
1145 defsubr (&Sgnutls_errorp);
1146 defsubr (&Sgnutls_error_fatalp);
1147 defsubr (&Sgnutls_error_string);
1148 defsubr (&Sgnutls_boot);
1149 defsubr (&Sgnutls_deinit);
8af55556 1150 defsubr (&Sgnutls_bye);
0898ca10 1151 defsubr (&Sgnutls_available_p);
750c33f7 1152
925a6be7 1153 DEFVAR_INT ("gnutls-log-level", global_gnutls_log_level,
31fd3586
GM
1154 doc: /* Logging level used by the GnuTLS functions.
1155Set this larger than 0 to get debug output in the *Messages* buffer.
11561 is for important messages, 2 is for debug data, and higher numbers
1157are as per the GnuTLS logging conventions. */);
925a6be7 1158 global_gnutls_log_level = 0;
8af55556 1159}
bafcf6a5
JB
1160
1161#endif /* HAVE_GNUTLS */