xdisp.c (reseat_1): Make the information stored in it->cmp_it invalidate.
[bpt/emacs.git] / src / gnutls.c
CommitLineData
8af55556 1/* GnuTLS glue for GNU Emacs.
acaf905b 2 Copyright (C) 2010-2012 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 {
355cdaf3 362#ifdef EWOULDBLOCK
0ca43699 363 errno = EWOULDBLOCK;
355cdaf3
LMI
364#endif
365#ifdef EAGAIN
0ca43699 366 errno = EAGAIN;
355cdaf3 367#endif
0ca43699
AS
368 return 0;
369 }
8af55556
TZ
370
371 bytes_written = 0;
372
373 while (nbyte > 0)
374 {
0898ca10 375 rtnval = fn_gnutls_record_send (state, buf, nbyte);
8af55556 376
2e6c74c5 377 if (rtnval < 0)
b5f03016 378 {
77abcbc2 379 if (rtnval == GNUTLS_E_INTERRUPTED)
b5f03016
AS
380 continue;
381 else
0ca43699
AS
382 {
383 /* If we get GNUTLS_E_AGAIN, then set errno
384 appropriately so that send_process retries the
385 correct way instead of erroring out. */
386 if (rtnval == GNUTLS_E_AGAIN)
387 {
2e8f3c56 388#ifdef EWOULDBLOCK
0ca43699 389 errno = EWOULDBLOCK;
2e8f3c56
LI
390#endif
391#ifdef EAGAIN
0ca43699 392 errno = EAGAIN;
2e8f3c56 393#endif
0ca43699
AS
394 }
395 break;
2e8f3c56 396 }
b5f03016 397 }
8af55556
TZ
398
399 buf += rtnval;
400 nbyte -= rtnval;
401 bytes_written += rtnval;
402 }
8af55556 403
e061a11b 404 emacs_gnutls_handle_error (state, rtnval);
8af55556
TZ
405 return (bytes_written);
406}
407
d311d28c
PE
408ptrdiff_t
409emacs_gnutls_read (struct Lisp_Process *proc, char *buf, ptrdiff_t nbyte)
8af55556 410{
368f4090 411 ssize_t rtnval;
df7fcaff
LMI
412 gnutls_session_t state = proc->gnutls_state;
413
a18ecafa
TZ
414 int log_level = proc->gnutls_log_level;
415
e6059fa2
LMI
416 if (proc->gnutls_initstage != GNUTLS_STAGE_READY)
417 {
a18ecafa
TZ
418 /* If the handshake count is under the limit, try the handshake
419 again and increment the handshake count. This count is kept
420 per process (connection), not globally. */
421 if (proc->gnutls_handshakes_tried < GNUTLS_EMACS_HANDSHAKES_LIMIT)
422 {
423 proc->gnutls_handshakes_tried++;
424 emacs_gnutls_handshake (proc);
02fd101b 425 GNUTLS_LOG2i (5, log_level, "Retried handshake",
a18ecafa
TZ
426 proc->gnutls_handshakes_tried);
427 return -1;
428 }
429
430 GNUTLS_LOG (2, log_level, "Giving up on handshake; resetting retries");
431 proc->gnutls_handshakes_tried = 0;
432 return 0;
e6059fa2 433 }
0898ca10 434 rtnval = fn_gnutls_record_recv (state, buf, nbyte);
ec9f09be
LMI
435 if (rtnval >= 0)
436 return rtnval;
dbf38e02
LMI
437 else if (rtnval == GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
438 /* The peer closed the connection. */
439 return 0;
18e27ea8 440 else if (emacs_gnutls_handle_error (state, rtnval))
e061a11b
TZ
441 /* non-fatal error */
442 return -1;
4b2d9ec2 443 else {
9173deec 444 /* a fatal error occurred */
e061a11b 445 return 0;
4b2d9ec2 446 }
8af55556
TZ
447}
448
18e27ea8
PE
449/* Report a GnuTLS error to the user.
450 Return true if the error code was successfully handled. */
451static bool
e061a11b
TZ
452emacs_gnutls_handle_error (gnutls_session_t session, int err)
453{
e061a11b
TZ
454 int max_log_level = 0;
455
18e27ea8 456 bool ret;
e061a11b
TZ
457 const char *str;
458
459 /* TODO: use a Lisp_Object generated by gnutls_make_error? */
460 if (err >= 0)
18e27ea8 461 return 1;
e061a11b 462
925a6be7 463 max_log_level = global_gnutls_log_level;
e061a11b
TZ
464
465 /* TODO: use gnutls-error-fatalp and gnutls-error-string. */
466
0898ca10 467 str = fn_gnutls_strerror (err);
e061a11b
TZ
468 if (!str)
469 str = "unknown";
470
0898ca10 471 if (fn_gnutls_error_is_fatal (err))
e061a11b 472 {
18e27ea8 473 ret = 0;
e061a11b
TZ
474 GNUTLS_LOG2 (0, max_log_level, "fatal error:", str);
475 }
476 else
477 {
18e27ea8 478 ret = 1;
e061a11b
TZ
479 GNUTLS_LOG2 (1, max_log_level, "non-fatal error:", str);
480 /* TODO: EAGAIN AKA Qgnutls_e_again should be level 2. */
481 }
482
483 if (err == GNUTLS_E_WARNING_ALERT_RECEIVED
484 || err == GNUTLS_E_FATAL_ALERT_RECEIVED)
485 {
0898ca10 486 int alert = fn_gnutls_alert_get (session);
e061a11b 487 int level = (err == GNUTLS_E_FATAL_ALERT_RECEIVED) ? 0 : 1;
0898ca10 488 str = fn_gnutls_alert_get_name (alert);
e061a11b
TZ
489 if (!str)
490 str = "unknown";
491
492 GNUTLS_LOG2 (level, max_log_level, "Received alert: ", str);
493 }
494 return ret;
495}
496
8af55556
TZ
497/* convert an integer error to a Lisp_Object; it will be either a
498 known symbol like `gnutls_e_interrupted' and `gnutls_e_again' or
499 simply the integer value of the error. GNUTLS_E_SUCCESS is mapped
500 to Qt. */
74f1829d 501static Lisp_Object
ec8df744 502gnutls_make_error (int err)
8af55556 503{
ec8df744 504 switch (err)
e6059fa2
LMI
505 {
506 case GNUTLS_E_SUCCESS:
507 return Qt;
508 case GNUTLS_E_AGAIN:
509 return Qgnutls_e_again;
510 case GNUTLS_E_INTERRUPTED:
511 return Qgnutls_e_interrupted;
512 case GNUTLS_E_INVALID_SESSION:
513 return Qgnutls_e_invalid_session;
514 }
8af55556 515
ec8df744 516 return make_number (err);
8af55556
TZ
517}
518
9c6c6f49
CY
519Lisp_Object
520emacs_gnutls_deinit (Lisp_Object proc)
521{
522 int log_level;
523
524 CHECK_PROCESS (proc);
525
526 if (XPROCESS (proc)->gnutls_p == 0)
527 return Qnil;
528
529 log_level = XPROCESS (proc)->gnutls_log_level;
530
531 if (XPROCESS (proc)->gnutls_x509_cred)
532 {
533 GNUTLS_LOG (2, log_level, "Deallocating x509 credentials");
534 fn_gnutls_certificate_free_credentials (XPROCESS (proc)->gnutls_x509_cred);
535 XPROCESS (proc)->gnutls_x509_cred = NULL;
536 }
537
538 if (XPROCESS (proc)->gnutls_anon_cred)
539 {
540 GNUTLS_LOG (2, log_level, "Deallocating anon credentials");
541 fn_gnutls_anon_free_client_credentials (XPROCESS (proc)->gnutls_anon_cred);
542 XPROCESS (proc)->gnutls_anon_cred = NULL;
543 }
544
435c1d67 545 if (XPROCESS (proc)->gnutls_state)
9c6c6f49
CY
546 {
547 fn_gnutls_deinit (XPROCESS (proc)->gnutls_state);
435c1d67
CY
548 XPROCESS (proc)->gnutls_state = NULL;
549 if (GNUTLS_INITSTAGE (proc) >= GNUTLS_STAGE_INIT)
550 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_INIT - 1;
9c6c6f49
CY
551 }
552
553 XPROCESS (proc)->gnutls_p = 0;
554 return Qt;
555}
556
8af55556 557DEFUN ("gnutls-get-initstage", Fgnutls_get_initstage, Sgnutls_get_initstage, 1, 1, 0,
74f1829d 558 doc: /* Return the GnuTLS init stage of process PROC.
8af55556 559See also `gnutls-boot'. */)
74f1829d 560 (Lisp_Object proc)
8af55556
TZ
561{
562 CHECK_PROCESS (proc);
563
564 return make_number (GNUTLS_INITSTAGE (proc));
565}
566
567DEFUN ("gnutls-errorp", Fgnutls_errorp, Sgnutls_errorp, 1, 1, 0,
74f1829d
JB
568 doc: /* Return t if ERROR indicates a GnuTLS problem.
569ERROR is an integer or a symbol with an integer `gnutls-code' property.
570usage: (gnutls-errorp ERROR) */)
571 (Lisp_Object err)
8af55556 572{
74f1829d 573 if (EQ (err, Qt)) return Qnil;
8af55556
TZ
574
575 return Qt;
576}
577
578DEFUN ("gnutls-error-fatalp", Fgnutls_error_fatalp, Sgnutls_error_fatalp, 1, 1, 0,
74f1829d
JB
579 doc: /* Check if ERROR is fatal.
580ERROR is an integer or a symbol with an integer `gnutls-code' property.
581usage: (gnutls-error-fatalp ERROR) */)
582 (Lisp_Object err)
8af55556
TZ
583{
584 Lisp_Object code;
585
586 if (EQ (err, Qt)) return Qnil;
587
588 if (SYMBOLP (err))
8af55556 589 {
e6059fa2
LMI
590 code = Fget (err, Qgnutls_code);
591 if (NUMBERP (code))
592 {
593 err = code;
594 }
595 else
596 {
597 error ("Symbol has no numeric gnutls-code property");
598 }
8af55556 599 }
8af55556 600
d311d28c 601 if (! TYPE_RANGED_INTEGERP (int, err))
8af55556
TZ
602 error ("Not an error symbol or code");
603
0898ca10 604 if (0 == fn_gnutls_error_is_fatal (XINT (err)))
8af55556
TZ
605 return Qnil;
606
607 return Qt;
608}
609
610DEFUN ("gnutls-error-string", Fgnutls_error_string, Sgnutls_error_string, 1, 1, 0,
74f1829d
JB
611 doc: /* Return a description of ERROR.
612ERROR is an integer or a symbol with an integer `gnutls-code' property.
613usage: (gnutls-error-string ERROR) */)
614 (Lisp_Object err)
8af55556
TZ
615{
616 Lisp_Object code;
617
618 if (EQ (err, Qt)) return build_string ("Not an error");
619
620 if (SYMBOLP (err))
8af55556 621 {
e6059fa2
LMI
622 code = Fget (err, Qgnutls_code);
623 if (NUMBERP (code))
624 {
625 err = code;
626 }
627 else
628 {
629 return build_string ("Symbol has no numeric gnutls-code property");
630 }
8af55556 631 }
8af55556 632
d311d28c 633 if (! TYPE_RANGED_INTEGERP (int, err))
8af55556
TZ
634 return build_string ("Not an error symbol or code");
635
0898ca10 636 return build_string (fn_gnutls_strerror (XINT (err)));
8af55556
TZ
637}
638
639DEFUN ("gnutls-deinit", Fgnutls_deinit, Sgnutls_deinit, 1, 1, 0,
e1b69165 640 doc: /* Deallocate GnuTLS resources associated with process PROC.
8af55556 641See also `gnutls-init'. */)
74f1829d 642 (Lisp_Object proc)
8af55556 643{
9c6c6f49 644 return emacs_gnutls_deinit (proc);
8af55556
TZ
645}
646
0898ca10
JB
647DEFUN ("gnutls-available-p", Fgnutls_available_p, Sgnutls_available_p, 0, 0, 0,
648 doc: /* Return t if GnuTLS is available in this instance of Emacs. */)
649 (void)
650{
651#ifdef WINDOWSNT
652 Lisp_Object found = Fassq (Qgnutls_dll, Vlibrary_cache);
653 if (CONSP (found))
654 return XCDR (found);
655 else
656 {
657 Lisp_Object status;
d07ff9db 658 status = init_gnutls_functions () ? Qt : Qnil;
0898ca10
JB
659 Vlibrary_cache = Fcons (Fcons (Qgnutls_dll, status), Vlibrary_cache);
660 return status;
661 }
662#else
663 return Qt;
664#endif
665}
666
667
e1b69165
JB
668/* Initializes global GnuTLS state to defaults.
669Call `gnutls-global-deinit' when GnuTLS usage is no longer needed.
8af55556 670Returns zero on success. */
74f1829d 671static Lisp_Object
e061a11b 672emacs_gnutls_global_init (void)
8af55556
TZ
673{
674 int ret = GNUTLS_E_SUCCESS;
675
e061a11b 676 if (!gnutls_global_initialized)
9cf9f756
PE
677 {
678 fn_gnutls_global_set_mem_functions (xmalloc, xmalloc, NULL,
679 xrealloc, xfree);
680 ret = fn_gnutls_global_init ();
681 }
e061a11b 682 gnutls_global_initialized = 1;
8af55556
TZ
683
684 return gnutls_make_error (ret);
685}
686
ec8df744 687#if 0
e1b69165 688/* Deinitializes global GnuTLS state.
8af55556 689See also `gnutls-global-init'. */
74f1829d 690static Lisp_Object
e061a11b 691emacs_gnutls_global_deinit (void)
8af55556 692{
e061a11b 693 if (gnutls_global_initialized)
8af55556
TZ
694 gnutls_global_deinit ();
695
e061a11b 696 gnutls_global_initialized = 0;
8af55556
TZ
697
698 return gnutls_make_error (GNUTLS_E_SUCCESS);
699}
ec8df744 700#endif
8af55556 701
c1ae068b
LMI
702DEFUN ("gnutls-boot", Fgnutls_boot, Sgnutls_boot, 3, 3, 0,
703 doc: /* Initialize GnuTLS client for process PROC with TYPE+PROPLIST.
435c1d67 704Currently only client mode is supported. Return a success/failure
8af55556
TZ
705value you can check with `gnutls-errorp'.
706
c1ae068b
LMI
707TYPE is a symbol, either `gnutls-anon' or `gnutls-x509pki'.
708PROPLIST is a property list with the following keys:
709
e061a11b
TZ
710:hostname is a string naming the remote host.
711
c1ae068b 712:priority is a GnuTLS priority string, defaults to "NORMAL".
e061a11b 713
c1ae068b 714:trustfiles is a list of PEM-encoded trust files for `gnutls-x509pki'.
e061a11b 715
ff4de4aa
TZ
716:crlfiles is a list of PEM-encoded CRL lists for `gnutls-x509pki'.
717
718:keylist is an alist of PEM-encoded key files and PEM-encoded
719certificates for `gnutls-x509pki'.
e061a11b
TZ
720
721:callbacks is an alist of callback functions, see below.
722
c1ae068b 723:loglevel is the debug level requested from GnuTLS, try 4.
8ed70bf3 724
e061a11b
TZ
725:verify-flags is a bitset as per GnuTLS'
726gnutls_certificate_set_verify_flags.
727
e061a11b
TZ
728:verify-hostname-error, if non-nil, makes a hostname mismatch an
729error. Otherwise it will be just a warning.
730
87e86684
LM
731:min-prime-bits is the minimum accepted number of bits the client will
732accept in Diffie-Hellman key exchange.
733
c1ae068b
LMI
734The debug level will be set for this process AND globally for GnuTLS.
735So if you set it higher or lower at any point, it affects global
736debugging.
8af55556
TZ
737
738Note that the priority is set on the client. The server does not use
739the protocols's priority except for disabling protocols that were not
740specified.
741
74f1829d 742Processes must be initialized with this function before other GnuTLS
8af55556
TZ
743functions are used. This function allocates resources which can only
744be deallocated by calling `gnutls-deinit' or by calling it again.
745
e061a11b
TZ
746The callbacks alist can have a `verify' key, associated with a
747verification function (UNUSED).
748
8af55556 749Each authentication type may need additional information in order to
c1ae068b
LMI
750work. For X.509 PKI (`gnutls-x509pki'), you probably need at least
751one trustfile (usually a CA bundle). */)
752 (Lisp_Object proc, Lisp_Object type, Lisp_Object proplist)
8af55556
TZ
753{
754 int ret = GNUTLS_E_SUCCESS;
8ed70bf3
LMI
755 int max_log_level = 0;
756
8af55556 757 gnutls_session_t state;
435c1d67
CY
758 gnutls_certificate_credentials_t x509_cred = NULL;
759 gnutls_anon_client_credentials_t anon_cred = NULL;
8af55556 760 Lisp_Object global_init;
ec8df744 761 char const *priority_string_ptr = "NORMAL"; /* default priority string. */
7754e151 762 unsigned int peer_verification;
e061a11b 763 char* c_hostname;
c1ae068b
LMI
764
765 /* Placeholders for the property list elements. */
766 Lisp_Object priority_string;
767 Lisp_Object trustfiles;
ff4de4aa
TZ
768 Lisp_Object crlfiles;
769 Lisp_Object keylist;
ec8df744 770 /* Lisp_Object callbacks; */
c1ae068b 771 Lisp_Object loglevel;
e061a11b 772 Lisp_Object hostname;
8d4c3955 773 /* Lisp_Object verify_error; */
e061a11b 774 Lisp_Object verify_hostname_error;
87e86684 775 Lisp_Object prime_bits;
8af55556
TZ
776
777 CHECK_PROCESS (proc);
778 CHECK_SYMBOL (type);
c1ae068b
LMI
779 CHECK_LIST (proplist);
780
0898ca10
JB
781 if (NILP (Fgnutls_available_p ()))
782 {
783 error ("GnuTLS not available");
784 return gnutls_make_error (GNUTLS_EMACS_ERROR_NOT_LOADED);
785 }
786
435c1d67
CY
787 if (!EQ (type, Qgnutls_x509pki) && !EQ (type, Qgnutls_anon))
788 {
789 error ("Invalid GnuTLS credential type");
790 return gnutls_make_error (GNUTLS_EMACS_ERROR_INVALID_TYPE);
791 }
792
a3720aa2
AS
793 hostname = Fplist_get (proplist, QCgnutls_bootprop_hostname);
794 priority_string = Fplist_get (proplist, QCgnutls_bootprop_priority);
795 trustfiles = Fplist_get (proplist, QCgnutls_bootprop_trustfiles);
796 keylist = Fplist_get (proplist, QCgnutls_bootprop_keylist);
797 crlfiles = Fplist_get (proplist, QCgnutls_bootprop_crlfiles);
a3720aa2 798 loglevel = Fplist_get (proplist, QCgnutls_bootprop_loglevel);
a3720aa2
AS
799 verify_hostname_error = Fplist_get (proplist, QCgnutls_bootprop_verify_hostname_error);
800 prime_bits = Fplist_get (proplist, QCgnutls_bootprop_min_prime_bits);
e061a11b
TZ
801
802 if (!STRINGP (hostname))
803 error ("gnutls-boot: invalid :hostname parameter");
e061a11b 804 c_hostname = SSDATA (hostname);
8af55556
TZ
805
806 state = XPROCESS (proc)->gnutls_state;
df7fcaff 807 XPROCESS (proc)->gnutls_p = 1;
8af55556 808
d311d28c 809 if (TYPE_RANGED_INTEGERP (int, loglevel))
8ed70bf3 810 {
0898ca10
JB
811 fn_gnutls_global_set_log_function (gnutls_log_function);
812 fn_gnutls_global_set_log_level (XINT (loglevel));
8ed70bf3
LMI
813 max_log_level = XINT (loglevel);
814 XPROCESS (proc)->gnutls_log_level = max_log_level;
815 }
df7fcaff 816
8af55556 817 /* always initialize globals. */
e061a11b 818 global_init = emacs_gnutls_global_init ();
8af55556
TZ
819 if (! NILP (Fgnutls_errorp (global_init)))
820 return global_init;
821
9c6c6f49
CY
822 /* Before allocating new credentials, deallocate any credentials
823 that PROC might already have. */
824 emacs_gnutls_deinit (proc);
8af55556 825
9c6c6f49
CY
826 /* Mark PROC as a GnuTLS process. */
827 XPROCESS (proc)->gnutls_p = 1;
435c1d67 828 XPROCESS (proc)->gnutls_state = NULL;
9c6c6f49
CY
829 XPROCESS (proc)->gnutls_x509_cred = NULL;
830 XPROCESS (proc)->gnutls_anon_cred = NULL;
6a09a33b 831 pset_gnutls_cred_type (XPROCESS (proc), type);
8af55556
TZ
832 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_EMPTY;
833
8ed70bf3 834 GNUTLS_LOG (1, max_log_level, "allocating credentials");
8af55556 835 if (EQ (type, Qgnutls_x509pki))
e6059fa2 836 {
435c1d67
CY
837 Lisp_Object verify_flags;
838 unsigned int gnutls_verify_flags = GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT;
839
8ed70bf3 840 GNUTLS_LOG (2, max_log_level, "allocating x509 credentials");
9cf9f756 841 fn_gnutls_certificate_allocate_credentials (&x509_cred);
435c1d67 842 XPROCESS (proc)->gnutls_x509_cred = x509_cred;
e061a11b 843
435c1d67 844 verify_flags = Fplist_get (proplist, QCgnutls_bootprop_verify_flags);
e061a11b 845 if (NUMBERP (verify_flags))
b5f03016
AS
846 {
847 gnutls_verify_flags = XINT (verify_flags);
848 GNUTLS_LOG (2, max_log_level, "setting verification flags");
849 }
e061a11b 850 else if (NILP (verify_flags))
435c1d67 851 GNUTLS_LOG (2, max_log_level, "using default verification flags");
e061a11b 852 else
435c1d67
CY
853 GNUTLS_LOG (2, max_log_level, "ignoring invalid verify-flags");
854
0898ca10 855 fn_gnutls_certificate_set_verify_flags (x509_cred, gnutls_verify_flags);
e6059fa2 856 }
435c1d67 857 else /* Qgnutls_anon: */
e6059fa2 858 {
8ed70bf3 859 GNUTLS_LOG (2, max_log_level, "allocating anon credentials");
9cf9f756 860 fn_gnutls_anon_allocate_client_credentials (&anon_cred);
435c1d67 861 XPROCESS (proc)->gnutls_anon_cred = anon_cred;
e6059fa2 862 }
8af55556
TZ
863
864 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_CRED_ALLOC;
865
8af55556 866 if (EQ (type, Qgnutls_x509pki))
e6059fa2 867 {
435c1d67
CY
868 /* TODO: GNUTLS_X509_FMT_DER is also an option. */
869 int file_format = GNUTLS_X509_FMT_PEM;
870 Lisp_Object tail;
871
7d7bbefd 872 for (tail = trustfiles; CONSP (tail); tail = XCDR (tail))
e6059fa2 873 {
34348bd4 874 Lisp_Object trustfile = XCAR (tail);
b5f03016
AS
875 if (STRINGP (trustfile))
876 {
877 GNUTLS_LOG2 (1, max_log_level, "setting the trustfile: ",
878 SSDATA (trustfile));
879 ret = fn_gnutls_certificate_set_x509_trust_file
880 (x509_cred,
881 SSDATA (trustfile),
882 file_format);
883
884 if (ret < GNUTLS_E_SUCCESS)
885 return gnutls_make_error (ret);
886 }
887 else
888 {
435c1d67
CY
889 emacs_gnutls_deinit (proc);
890 error ("Invalid trustfile");
b5f03016
AS
891 }
892 }
8af55556 893
7d7bbefd 894 for (tail = crlfiles; CONSP (tail); tail = XCDR (tail))
e6059fa2 895 {
34348bd4 896 Lisp_Object crlfile = XCAR (tail);
b5f03016
AS
897 if (STRINGP (crlfile))
898 {
899 GNUTLS_LOG2 (1, max_log_level, "setting the CRL file: ",
900 SSDATA (crlfile));
901 ret = fn_gnutls_certificate_set_x509_crl_file
435c1d67 902 (x509_cred, SSDATA (crlfile), file_format);
b5f03016
AS
903
904 if (ret < GNUTLS_E_SUCCESS)
905 return gnutls_make_error (ret);
906 }
907 else
908 {
435c1d67
CY
909 emacs_gnutls_deinit (proc);
910 error ("Invalid CRL file");
b5f03016
AS
911 }
912 }
ff4de4aa 913
7d7bbefd 914 for (tail = keylist; CONSP (tail); tail = XCDR (tail))
ff4de4aa 915 {
34348bd4 916 Lisp_Object keyfile = Fcar (XCAR (tail));
d96a1e0c 917 Lisp_Object certfile = Fcar (Fcdr (XCAR (tail)));
b5f03016
AS
918 if (STRINGP (keyfile) && STRINGP (certfile))
919 {
920 GNUTLS_LOG2 (1, max_log_level, "setting the client key file: ",
921 SSDATA (keyfile));
922 GNUTLS_LOG2 (1, max_log_level, "setting the client cert file: ",
923 SSDATA (certfile));
924 ret = fn_gnutls_certificate_set_x509_key_file
435c1d67 925 (x509_cred, SSDATA (certfile), SSDATA (keyfile), file_format);
b5f03016
AS
926
927 if (ret < GNUTLS_E_SUCCESS)
928 return gnutls_make_error (ret);
929 }
930 else
931 {
435c1d67
CY
932 emacs_gnutls_deinit (proc);
933 error (STRINGP (keyfile) ? "Invalid client cert file"
934 : "Invalid client key file");
b5f03016
AS
935 }
936 }
e6059fa2 937 }
8af55556
TZ
938
939 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_FILES;
e061a11b 940 GNUTLS_LOG (1, max_log_level, "gnutls callbacks");
e061a11b
TZ
941 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_CALLBACKS;
942
435c1d67 943 /* Call gnutls_init here: */
e061a11b 944
8ed70bf3 945 GNUTLS_LOG (1, max_log_level, "gnutls_init");
0898ca10 946 ret = fn_gnutls_init (&state, GNUTLS_CLIENT);
435c1d67 947 XPROCESS (proc)->gnutls_state = state;
8af55556 948 if (ret < GNUTLS_E_SUCCESS)
e6059fa2 949 return gnutls_make_error (ret);
8af55556
TZ
950 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_INIT;
951
c1ae068b
LMI
952 if (STRINGP (priority_string))
953 {
51b59d79 954 priority_string_ptr = SSDATA (priority_string);
c1ae068b 955 GNUTLS_LOG2 (1, max_log_level, "got non-default priority string:",
b5f03016 956 priority_string_ptr);
c1ae068b
LMI
957 }
958 else
959 {
960 GNUTLS_LOG2 (1, max_log_level, "using default priority string:",
b5f03016 961 priority_string_ptr);
c1ae068b 962 }
51b59d79 963
8ed70bf3 964 GNUTLS_LOG (1, max_log_level, "setting the priority string");
0898ca10 965 ret = fn_gnutls_priority_set_direct (state,
b5f03016
AS
966 priority_string_ptr,
967 NULL);
8af55556 968 if (ret < GNUTLS_E_SUCCESS)
e6059fa2 969 return gnutls_make_error (ret);
8af55556
TZ
970
971 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_PRIORITY;
972
435c1d67
CY
973 if (INTEGERP (prime_bits))
974 fn_gnutls_dh_set_prime_bits (state, XUINT (prime_bits));
8af55556 975
435c1d67
CY
976 ret = EQ (type, Qgnutls_x509pki)
977 ? fn_gnutls_credentials_set (state, GNUTLS_CRD_CERTIFICATE, x509_cred)
978 : fn_gnutls_credentials_set (state, GNUTLS_CRD_ANON, anon_cred);
8af55556 979 if (ret < GNUTLS_E_SUCCESS)
e6059fa2 980 return gnutls_make_error (ret);
8af55556 981
8af55556 982 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_CRED_SET;
e061a11b 983 ret = emacs_gnutls_handshake (XPROCESS (proc));
e061a11b
TZ
984 if (ret < GNUTLS_E_SUCCESS)
985 return gnutls_make_error (ret);
986
987 /* Now verify the peer, following
988 http://www.gnu.org/software/gnutls/manual/html_node/Verifying-peer_0027s-certificate.html.
989 The peer should present at least one certificate in the chain; do a
990 check of the certificate's hostname with
991 gnutls_x509_crt_check_hostname() against :hostname. */
992
0898ca10 993 ret = fn_gnutls_certificate_verify_peers2 (state, &peer_verification);
e061a11b
TZ
994 if (ret < GNUTLS_E_SUCCESS)
995 return gnutls_make_error (ret);
671875da 996
e061a11b 997 if (XINT (loglevel) > 0 && peer_verification & GNUTLS_CERT_INVALID)
435c1d67
CY
998 message ("%s certificate could not be verified.", c_hostname);
999
1000 if (peer_verification & GNUTLS_CERT_REVOKED)
1001 GNUTLS_LOG2 (1, max_log_level, "certificate was revoked (CRL):",
1002 c_hostname);
1003
1004 if (peer_verification & GNUTLS_CERT_SIGNER_NOT_FOUND)
1005 GNUTLS_LOG2 (1, max_log_level, "certificate signer was not found:",
1006 c_hostname);
1007
1008 if (peer_verification & GNUTLS_CERT_SIGNER_NOT_CA)
1009 GNUTLS_LOG2 (1, max_log_level, "certificate signer is not a CA:",
1010 c_hostname);
1011
1012 if (peer_verification & GNUTLS_CERT_INSECURE_ALGORITHM)
1013 GNUTLS_LOG2 (1, max_log_level,
1014 "certificate was signed with an insecure algorithm:",
1015 c_hostname);
1016
1017 if (peer_verification & GNUTLS_CERT_NOT_ACTIVATED)
1018 GNUTLS_LOG2 (1, max_log_level, "certificate is not yet activated:",
1019 c_hostname);
1020
1021 if (peer_verification & GNUTLS_CERT_EXPIRED)
1022 GNUTLS_LOG2 (1, max_log_level, "certificate has expired:",
1023 c_hostname);
1024
1025 if (peer_verification != 0)
1026 {
1027 if (NILP (verify_hostname_error))
1028 GNUTLS_LOG2 (1, max_log_level, "certificate validation failed:",
1029 c_hostname);
1030 else
1031 {
1032 emacs_gnutls_deinit (proc);
1033 error ("Certificate validation failed %s, verification code %d",
1034 c_hostname, peer_verification);
1035 }
1036 }
e061a11b
TZ
1037
1038 /* Up to here the process is the same for X.509 certificates and
1039 OpenPGP keys. From now on X.509 certificates are assumed. This
1040 can be easily extended to work with openpgp keys as well. */
0898ca10 1041 if (fn_gnutls_certificate_type_get (state) == GNUTLS_CRT_X509)
e061a11b 1042 {
435c1d67
CY
1043 gnutls_x509_crt_t gnutls_verify_cert;
1044 const gnutls_datum_t *gnutls_verify_cert_list;
1045 unsigned int gnutls_verify_cert_list_size;
e061a11b 1046
435c1d67 1047 ret = fn_gnutls_x509_crt_init (&gnutls_verify_cert);
e061a11b 1048 if (ret < GNUTLS_E_SUCCESS)
b5f03016 1049 return gnutls_make_error (ret);
e061a11b 1050
671875da 1051 gnutls_verify_cert_list =
b5f03016 1052 fn_gnutls_certificate_get_peers (state, &gnutls_verify_cert_list_size);
e061a11b 1053
435c1d67 1054 if (gnutls_verify_cert_list == NULL)
b5f03016 1055 {
435c1d67
CY
1056 fn_gnutls_x509_crt_deinit (gnutls_verify_cert);
1057 emacs_gnutls_deinit (proc);
1058 error ("No x509 certificate was found\n");
b5f03016 1059 }
e061a11b
TZ
1060
1061 /* We only check the first certificate in the given chain. */
0898ca10 1062 ret = fn_gnutls_x509_crt_import (gnutls_verify_cert,
b5f03016
AS
1063 &gnutls_verify_cert_list[0],
1064 GNUTLS_X509_FMT_DER);
e061a11b
TZ
1065
1066 if (ret < GNUTLS_E_SUCCESS)
b5f03016
AS
1067 {
1068 fn_gnutls_x509_crt_deinit (gnutls_verify_cert);
1069 return gnutls_make_error (ret);
1070 }
e061a11b 1071
0898ca10 1072 if (!fn_gnutls_x509_crt_check_hostname (gnutls_verify_cert, c_hostname))
b5f03016
AS
1073 {
1074 if (NILP (verify_hostname_error))
435c1d67
CY
1075 GNUTLS_LOG2 (1, max_log_level, "x509 certificate does not match:",
1076 c_hostname);
b5f03016
AS
1077 else
1078 {
1079 fn_gnutls_x509_crt_deinit (gnutls_verify_cert);
435c1d67
CY
1080 emacs_gnutls_deinit (proc);
1081 error ("The x509 certificate does not match \"%s\"", c_hostname);
b5f03016
AS
1082 }
1083 }
0898ca10 1084 fn_gnutls_x509_crt_deinit (gnutls_verify_cert);
e061a11b
TZ
1085 }
1086
1087 return gnutls_make_error (ret);
8af55556
TZ
1088}
1089
1090DEFUN ("gnutls-bye", Fgnutls_bye,
1091 Sgnutls_bye, 2, 2, 0,
74f1829d 1092 doc: /* Terminate current GnuTLS connection for process PROC.
8af55556
TZ
1093The connection should have been initiated using `gnutls-handshake'.
1094
1095If CONT is not nil the TLS connection gets terminated and further
74f1829d 1096receives and sends will be disallowed. If the return value is zero you
8af55556
TZ
1097may continue using the connection. If CONT is nil, GnuTLS actually
1098sends an alert containing a close request and waits for the peer to
1099reply with the same message. In order to reuse the connection you
1100should wait for an EOF from the peer.
1101
1102This function may also return `gnutls-e-again', or
1103`gnutls-e-interrupted'. */)
1104 (Lisp_Object proc, Lisp_Object cont)
1105{
1106 gnutls_session_t state;
1107 int ret;
1108
1109 CHECK_PROCESS (proc);
1110
1111 state = XPROCESS (proc)->gnutls_state;
1112
0898ca10 1113 ret = fn_gnutls_bye (state,
b5f03016 1114 NILP (cont) ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR);
8af55556
TZ
1115
1116 return gnutls_make_error (ret);
1117}
1118
8af55556
TZ
1119void
1120syms_of_gnutls (void)
1121{
e061a11b
TZ
1122 gnutls_global_initialized = 0;
1123
a555cb87 1124 DEFSYM (Qgnutls_dll, "gnutls");
a555cb87
JB
1125 DEFSYM (Qgnutls_code, "gnutls-code");
1126 DEFSYM (Qgnutls_anon, "gnutls-anon");
1127 DEFSYM (Qgnutls_x509pki, "gnutls-x509pki");
a3720aa2
AS
1128 DEFSYM (QCgnutls_bootprop_hostname, ":hostname");
1129 DEFSYM (QCgnutls_bootprop_priority, ":priority");
1130 DEFSYM (QCgnutls_bootprop_trustfiles, ":trustfiles");
1131 DEFSYM (QCgnutls_bootprop_keylist, ":keylist");
1132 DEFSYM (QCgnutls_bootprop_crlfiles, ":crlfiles");
1133 DEFSYM (QCgnutls_bootprop_callbacks, ":callbacks");
1134 DEFSYM (QCgnutls_bootprop_callbacks_verify, "verify");
1135 DEFSYM (QCgnutls_bootprop_min_prime_bits, ":min-prime-bits");
1136 DEFSYM (QCgnutls_bootprop_loglevel, ":loglevel");
1137 DEFSYM (QCgnutls_bootprop_verify_flags, ":verify-flags");
1138 DEFSYM (QCgnutls_bootprop_verify_hostname_error, ":verify-hostname-error");
a555cb87
JB
1139
1140 DEFSYM (Qgnutls_e_interrupted, "gnutls-e-interrupted");
8af55556 1141 Fput (Qgnutls_e_interrupted, Qgnutls_code,
b5f03016 1142 make_number (GNUTLS_E_INTERRUPTED));
8af55556 1143
a555cb87 1144 DEFSYM (Qgnutls_e_again, "gnutls-e-again");
8af55556 1145 Fput (Qgnutls_e_again, Qgnutls_code,
b5f03016 1146 make_number (GNUTLS_E_AGAIN));
8af55556 1147
a555cb87 1148 DEFSYM (Qgnutls_e_invalid_session, "gnutls-e-invalid-session");
8af55556 1149 Fput (Qgnutls_e_invalid_session, Qgnutls_code,
b5f03016 1150 make_number (GNUTLS_E_INVALID_SESSION));
8af55556 1151
a555cb87 1152 DEFSYM (Qgnutls_e_not_ready_for_handshake, "gnutls-e-not-ready-for-handshake");
8af55556 1153 Fput (Qgnutls_e_not_ready_for_handshake, Qgnutls_code,
b5f03016 1154 make_number (GNUTLS_E_APPLICATION_ERROR_MIN));
8af55556
TZ
1155
1156 defsubr (&Sgnutls_get_initstage);
1157 defsubr (&Sgnutls_errorp);
1158 defsubr (&Sgnutls_error_fatalp);
1159 defsubr (&Sgnutls_error_string);
1160 defsubr (&Sgnutls_boot);
1161 defsubr (&Sgnutls_deinit);
8af55556 1162 defsubr (&Sgnutls_bye);
0898ca10 1163 defsubr (&Sgnutls_available_p);
750c33f7 1164
925a6be7 1165 DEFVAR_INT ("gnutls-log-level", global_gnutls_log_level,
31fd3586
GM
1166 doc: /* Logging level used by the GnuTLS functions.
1167Set this larger than 0 to get debug output in the *Messages* buffer.
11681 is for important messages, 2 is for debug data, and higher numbers
1169are as per the GnuTLS logging conventions. */);
925a6be7 1170 global_gnutls_log_level = 0;
8af55556 1171}
bafcf6a5
JB
1172
1173#endif /* HAVE_GNUTLS */