blob: c4cd3c1a5f0f4caf24a9efe035458ebf195075d5 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * SSL/TLS interface functions for GnuTLS
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003 * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
8
9#include "includes.h"
10#include <gnutls/gnutls.h>
11#include <gnutls/x509.h>
12#ifdef PKCS12_FUNCS
13#include <gnutls/pkcs12.h>
14#endif /* PKCS12_FUNCS */
Dmitry Shmidtff787d52015-01-12 13:01:47 -080015#if GNUTLS_VERSION_NUMBER >= 0x030103
16#include <gnutls/ocsp.h>
17#endif /* 3.1.3 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070018
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070019#include "common.h"
Dmitry Shmidtff787d52015-01-12 13:01:47 -080020#include "crypto/crypto.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070021#include "tls.h"
22
23
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070024static int tls_gnutls_ref_count = 0;
25
26struct tls_global {
27 /* Data for session resumption */
28 void *session_data;
29 size_t session_data_size;
30
31 int server;
32
33 int params_set;
34 gnutls_certificate_credentials_t xcred;
Dmitry Shmidtff787d52015-01-12 13:01:47 -080035
36 void (*event_cb)(void *ctx, enum tls_event ev,
37 union tls_event_data *data);
38 void *cb_ctx;
39 int cert_in_cb;
Dmitry Shmidt014a3ff2015-12-28 13:27:49 -080040
41 char *ocsp_stapling_response;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070042};
43
44struct tls_connection {
Dmitry Shmidtff787d52015-01-12 13:01:47 -080045 struct tls_global *global;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080046 gnutls_session_t session;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070047 int read_alerts, write_alerts, failed;
48
49 u8 *pre_shared_secret;
50 size_t pre_shared_secret_len;
51 int established;
52 int verify_peer;
Dmitry Shmidtff787d52015-01-12 13:01:47 -080053 unsigned int disable_time_checks:1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070054
55 struct wpabuf *push_buf;
56 struct wpabuf *pull_buf;
57 const u8 *pull_buf_offset;
58
59 int params_set;
60 gnutls_certificate_credentials_t xcred;
Dmitry Shmidtff787d52015-01-12 13:01:47 -080061
62 char *suffix_match;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -080063 char *domain_match;
Dmitry Shmidtff787d52015-01-12 13:01:47 -080064 unsigned int flags;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070065};
66
67
Dmitry Shmidtff787d52015-01-12 13:01:47 -080068static int tls_connection_verify_peer(gnutls_session_t session);
69
70
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070071static void tls_log_func(int level, const char *msg)
72{
73 char *s, *pos;
74 if (level == 6 || level == 7) {
75 /* These levels seem to be mostly I/O debug and msg dumps */
76 return;
77 }
78
79 s = os_strdup(msg);
80 if (s == NULL)
81 return;
82
83 pos = s;
84 while (*pos != '\0') {
85 if (*pos == '\n') {
86 *pos = '\0';
87 break;
88 }
89 pos++;
90 }
91 wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
92 "gnutls<%d> %s", level, s);
93 os_free(s);
94}
95
96
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070097void * tls_init(const struct tls_config *conf)
98{
99 struct tls_global *global;
100
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800101 if (tls_gnutls_ref_count == 0) {
102 wpa_printf(MSG_DEBUG,
103 "GnuTLS: Library version %s (runtime) - %s (build)",
104 gnutls_check_version(NULL), GNUTLS_VERSION);
105 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700106
107 global = os_zalloc(sizeof(*global));
108 if (global == NULL)
109 return NULL;
110
111 if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) {
112 os_free(global);
113 return NULL;
114 }
115 tls_gnutls_ref_count++;
116
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700117 gnutls_global_set_log_function(tls_log_func);
118 if (wpa_debug_show_keys)
119 gnutls_global_set_log_level(11);
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800120
121 if (conf) {
122 global->event_cb = conf->event_cb;
123 global->cb_ctx = conf->cb_ctx;
124 global->cert_in_cb = conf->cert_in_cb;
125 }
126
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700127 return global;
128}
129
130
131void tls_deinit(void *ssl_ctx)
132{
133 struct tls_global *global = ssl_ctx;
134 if (global) {
135 if (global->params_set)
136 gnutls_certificate_free_credentials(global->xcred);
137 os_free(global->session_data);
Dmitry Shmidt014a3ff2015-12-28 13:27:49 -0800138 os_free(global->ocsp_stapling_response);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700139 os_free(global);
140 }
141
142 tls_gnutls_ref_count--;
143 if (tls_gnutls_ref_count == 0)
144 gnutls_global_deinit();
145}
146
147
148int tls_get_errors(void *ssl_ctx)
149{
150 return 0;
151}
152
153
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800154static ssize_t tls_pull_func(gnutls_transport_ptr_t ptr, void *buf,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700155 size_t len)
156{
157 struct tls_connection *conn = (struct tls_connection *) ptr;
158 const u8 *end;
159 if (conn->pull_buf == NULL) {
160 errno = EWOULDBLOCK;
161 return -1;
162 }
163
164 end = wpabuf_head_u8(conn->pull_buf) + wpabuf_len(conn->pull_buf);
165 if ((size_t) (end - conn->pull_buf_offset) < len)
166 len = end - conn->pull_buf_offset;
167 os_memcpy(buf, conn->pull_buf_offset, len);
168 conn->pull_buf_offset += len;
169 if (conn->pull_buf_offset == end) {
170 wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
171 wpabuf_free(conn->pull_buf);
172 conn->pull_buf = NULL;
173 conn->pull_buf_offset = NULL;
174 } else {
175 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
176 __func__,
177 (unsigned long) (end - conn->pull_buf_offset));
178 }
179 return len;
180}
181
182
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800183static ssize_t tls_push_func(gnutls_transport_ptr_t ptr, const void *buf,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700184 size_t len)
185{
186 struct tls_connection *conn = (struct tls_connection *) ptr;
187
188 if (wpabuf_resize(&conn->push_buf, len) < 0) {
189 errno = ENOMEM;
190 return -1;
191 }
192 wpabuf_put_data(conn->push_buf, buf, len);
193
194 return len;
195}
196
197
198static int tls_gnutls_init_session(struct tls_global *global,
199 struct tls_connection *conn)
200{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800201 const char *err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700202 int ret;
203
204 ret = gnutls_init(&conn->session,
205 global->server ? GNUTLS_SERVER : GNUTLS_CLIENT);
206 if (ret < 0) {
207 wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
208 "connection: %s", gnutls_strerror(ret));
209 return -1;
210 }
211
212 ret = gnutls_set_default_priority(conn->session);
213 if (ret < 0)
214 goto fail;
215
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800216 ret = gnutls_priority_set_direct(conn->session, "NORMAL:-VERS-SSL3.0",
217 &err);
218 if (ret < 0) {
219 wpa_printf(MSG_ERROR, "GnuTLS: Priority string failure at "
220 "'%s'", err);
221 goto fail;
222 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700223
224 gnutls_transport_set_pull_function(conn->session, tls_pull_func);
225 gnutls_transport_set_push_function(conn->session, tls_push_func);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800226 gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr_t) conn);
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800227 gnutls_session_set_ptr(conn->session, conn);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700228
229 return 0;
230
231fail:
232 wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s",
233 gnutls_strerror(ret));
234 gnutls_deinit(conn->session);
235 return -1;
236}
237
238
239struct tls_connection * tls_connection_init(void *ssl_ctx)
240{
241 struct tls_global *global = ssl_ctx;
242 struct tls_connection *conn;
243 int ret;
244
245 conn = os_zalloc(sizeof(*conn));
246 if (conn == NULL)
247 return NULL;
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800248 conn->global = global;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700249
250 if (tls_gnutls_init_session(global, conn)) {
251 os_free(conn);
252 return NULL;
253 }
254
255 if (global->params_set) {
256 ret = gnutls_credentials_set(conn->session,
257 GNUTLS_CRD_CERTIFICATE,
258 global->xcred);
259 if (ret < 0) {
260 wpa_printf(MSG_INFO, "Failed to configure "
261 "credentials: %s", gnutls_strerror(ret));
262 os_free(conn);
263 return NULL;
264 }
265 }
266
267 if (gnutls_certificate_allocate_credentials(&conn->xcred)) {
268 os_free(conn);
269 return NULL;
270 }
271
272 return conn;
273}
274
275
276void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
277{
278 if (conn == NULL)
279 return;
280
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700281 gnutls_certificate_free_credentials(conn->xcred);
282 gnutls_deinit(conn->session);
283 os_free(conn->pre_shared_secret);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700284 wpabuf_free(conn->push_buf);
285 wpabuf_free(conn->pull_buf);
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800286 os_free(conn->suffix_match);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800287 os_free(conn->domain_match);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700288 os_free(conn);
289}
290
291
292int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
293{
294 return conn ? conn->established : 0;
295}
296
297
298int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
299{
300 struct tls_global *global = ssl_ctx;
301 int ret;
302
303 if (conn == NULL)
304 return -1;
305
306 /* Shutdown previous TLS connection without notifying the peer
307 * because the connection was already terminated in practice
308 * and "close notify" shutdown alert would confuse AS. */
309 gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
310 wpabuf_free(conn->push_buf);
311 conn->push_buf = NULL;
312 conn->established = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700313
314 gnutls_deinit(conn->session);
315 if (tls_gnutls_init_session(global, conn)) {
316 wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session "
317 "for session resumption use");
318 return -1;
319 }
320
321 ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
322 conn->params_set ? conn->xcred :
323 global->xcred);
324 if (ret < 0) {
325 wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials "
326 "for session resumption: %s", gnutls_strerror(ret));
327 return -1;
328 }
329
330 if (global->session_data) {
331 ret = gnutls_session_set_data(conn->session,
332 global->session_data,
333 global->session_data_size);
334 if (ret < 0) {
335 wpa_printf(MSG_INFO, "GnuTLS: Failed to set session "
336 "data: %s", gnutls_strerror(ret));
337 return -1;
338 }
339 }
340
341 return 0;
342}
343
344
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700345int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
346 const struct tls_connection_params *params)
347{
348 int ret;
349
350 if (conn == NULL || params == NULL)
351 return -1;
352
Dmitry Shmidt014a3ff2015-12-28 13:27:49 -0800353 if (params->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
354 wpa_printf(MSG_INFO,
355 "GnuTLS: ocsp=3 not supported");
356 return -1;
357 }
358
Dmitry Shmidt55840ad2015-12-14 12:45:46 -0800359 if (params->flags & TLS_CONN_EXT_CERT_CHECK) {
360 wpa_printf(MSG_INFO,
361 "GnuTLS: tls_ext_cert_check=1 not supported");
362 return -1;
363 }
364
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700365 if (params->subject_match) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800366 wpa_printf(MSG_INFO, "GnuTLS: subject_match not supported");
367 return -1;
368 }
369
370 if (params->altsubject_match) {
371 wpa_printf(MSG_INFO, "GnuTLS: altsubject_match not supported");
372 return -1;
373 }
374
375 os_free(conn->suffix_match);
376 conn->suffix_match = NULL;
377 if (params->suffix_match) {
378 conn->suffix_match = os_strdup(params->suffix_match);
379 if (conn->suffix_match == NULL)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700380 return -1;
381 }
382
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800383#if GNUTLS_VERSION_NUMBER >= 0x030300
384 os_free(conn->domain_match);
385 conn->domain_match = NULL;
386 if (params->domain_match) {
387 conn->domain_match = os_strdup(params->domain_match);
388 if (conn->domain_match == NULL)
389 return -1;
390 }
391#else /* < 3.3.0 */
392 if (params->domain_match) {
393 wpa_printf(MSG_INFO, "GnuTLS: domain_match not supported");
394 return -1;
395 }
396#endif /* >= 3.3.0 */
397
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800398 conn->flags = params->flags;
399
400 if (params->openssl_ciphers) {
401 wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
402 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700403 }
404
405 /* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
406 * to force peer validation(?) */
407
408 if (params->ca_cert) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800409 wpa_printf(MSG_DEBUG, "GnuTLS: Try to parse %s in DER format",
410 params->ca_cert);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700411 ret = gnutls_certificate_set_x509_trust_file(
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800412 conn->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700413 if (ret < 0) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800414 wpa_printf(MSG_DEBUG,
415 "GnuTLS: Failed to read CA cert '%s' in DER format (%s) - try in PEM format",
416 params->ca_cert,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700417 gnutls_strerror(ret));
418 ret = gnutls_certificate_set_x509_trust_file(
419 conn->xcred, params->ca_cert,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800420 GNUTLS_X509_FMT_PEM);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700421 if (ret < 0) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800422 wpa_printf(MSG_DEBUG,
423 "Failed to read CA cert '%s' in PEM format: %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700424 params->ca_cert,
425 gnutls_strerror(ret));
426 return -1;
427 }
428 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800429 } else if (params->ca_cert_blob) {
430 gnutls_datum_t ca;
431
432 ca.data = (unsigned char *) params->ca_cert_blob;
433 ca.size = params->ca_cert_blob_len;
434
435 ret = gnutls_certificate_set_x509_trust_mem(
436 conn->xcred, &ca, GNUTLS_X509_FMT_DER);
437 if (ret < 0) {
438 wpa_printf(MSG_DEBUG,
439 "Failed to parse CA cert in DER format: %s",
440 gnutls_strerror(ret));
441 ret = gnutls_certificate_set_x509_trust_mem(
442 conn->xcred, &ca, GNUTLS_X509_FMT_PEM);
443 if (ret < 0) {
444 wpa_printf(MSG_DEBUG,
445 "Failed to parse CA cert in PEM format: %s",
446 gnutls_strerror(ret));
447 return -1;
448 }
449 }
450 } else if (params->ca_path) {
451 wpa_printf(MSG_INFO, "GnuTLS: ca_path not supported");
452 return -1;
453 }
454
455 conn->disable_time_checks = 0;
456 if (params->ca_cert || params->ca_cert_blob) {
457 conn->verify_peer = 1;
458 gnutls_certificate_set_verify_function(
459 conn->xcred, tls_connection_verify_peer);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700460
461 if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
462 gnutls_certificate_set_verify_flags(
463 conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
464 }
465
466 if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800467 conn->disable_time_checks = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700468 gnutls_certificate_set_verify_flags(
469 conn->xcred,
470 GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
471 }
472 }
473
474 if (params->client_cert && params->private_key) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800475#if GNUTLS_VERSION_NUMBER >= 0x03010b
476 ret = gnutls_certificate_set_x509_key_file2(
477 conn->xcred, params->client_cert, params->private_key,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800478 GNUTLS_X509_FMT_DER, params->private_key_passwd, 0);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800479#else
480 /* private_key_passwd not (easily) supported here */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700481 ret = gnutls_certificate_set_x509_key_file(
482 conn->xcred, params->client_cert, params->private_key,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800483 GNUTLS_X509_FMT_DER);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800484#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700485 if (ret < 0) {
486 wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800487 "in DER format: %s", gnutls_strerror(ret));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800488#if GNUTLS_VERSION_NUMBER >= 0x03010b
489 ret = gnutls_certificate_set_x509_key_file2(
490 conn->xcred, params->client_cert,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800491 params->private_key, GNUTLS_X509_FMT_PEM,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800492 params->private_key_passwd, 0);
493#else
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700494 ret = gnutls_certificate_set_x509_key_file(
495 conn->xcred, params->client_cert,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800496 params->private_key, GNUTLS_X509_FMT_PEM);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800497#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700498 if (ret < 0) {
499 wpa_printf(MSG_DEBUG, "Failed to read client "
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800500 "cert/key in PEM format: %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700501 gnutls_strerror(ret));
502 return ret;
503 }
504 }
505 } else if (params->private_key) {
506 int pkcs12_ok = 0;
507#ifdef PKCS12_FUNCS
508 /* Try to load in PKCS#12 format */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700509 ret = gnutls_certificate_set_x509_simple_pkcs12_file(
510 conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
511 params->private_key_passwd);
512 if (ret != 0) {
513 wpa_printf(MSG_DEBUG, "Failed to load private_key in "
514 "PKCS#12 format: %s", gnutls_strerror(ret));
515 return -1;
516 } else
517 pkcs12_ok = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700518#endif /* PKCS12_FUNCS */
519
520 if (!pkcs12_ok) {
521 wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
522 "included");
523 return -1;
524 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800525 } else if (params->client_cert_blob && params->private_key_blob) {
526 gnutls_datum_t cert, key;
527
528 cert.data = (unsigned char *) params->client_cert_blob;
529 cert.size = params->client_cert_blob_len;
530 key.data = (unsigned char *) params->private_key_blob;
531 key.size = params->private_key_blob_len;
532
533#if GNUTLS_VERSION_NUMBER >= 0x03010b
534 ret = gnutls_certificate_set_x509_key_mem2(
535 conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER,
536 params->private_key_passwd, 0);
537#else
538 /* private_key_passwd not (easily) supported here */
539 ret = gnutls_certificate_set_x509_key_mem(
540 conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER);
541#endif
542 if (ret < 0) {
543 wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
544 "in DER format: %s", gnutls_strerror(ret));
545#if GNUTLS_VERSION_NUMBER >= 0x03010b
546 ret = gnutls_certificate_set_x509_key_mem2(
547 conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM,
548 params->private_key_passwd, 0);
549#else
550 /* private_key_passwd not (easily) supported here */
551 ret = gnutls_certificate_set_x509_key_mem(
552 conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM);
553#endif
554 if (ret < 0) {
555 wpa_printf(MSG_DEBUG, "Failed to read client "
556 "cert/key in PEM format: %s",
557 gnutls_strerror(ret));
558 return ret;
559 }
560 }
561 } else if (params->private_key_blob) {
562#ifdef PKCS12_FUNCS
563 gnutls_datum_t key;
564
565 key.data = (unsigned char *) params->private_key_blob;
566 key.size = params->private_key_blob_len;
567
568 /* Try to load in PKCS#12 format */
569 ret = gnutls_certificate_set_x509_simple_pkcs12_mem(
570 conn->xcred, &key, GNUTLS_X509_FMT_DER,
571 params->private_key_passwd);
572 if (ret != 0) {
573 wpa_printf(MSG_DEBUG, "Failed to load private_key in "
574 "PKCS#12 format: %s", gnutls_strerror(ret));
575 return -1;
576 }
577#else /* PKCS12_FUNCS */
578 wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not included");
579 return -1;
580#endif /* PKCS12_FUNCS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700581 }
582
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800583#if GNUTLS_VERSION_NUMBER >= 0x030103
584 if (params->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)) {
585 ret = gnutls_ocsp_status_request_enable_client(conn->session,
586 NULL, 0, NULL);
587 if (ret != GNUTLS_E_SUCCESS) {
588 wpa_printf(MSG_INFO,
589 "GnuTLS: Failed to enable OCSP client");
590 return -1;
591 }
592 }
593#else /* 3.1.3 */
594 if (params->flags & TLS_CONN_REQUIRE_OCSP) {
595 wpa_printf(MSG_INFO,
596 "GnuTLS: OCSP not supported by this version of GnuTLS");
597 return -1;
598 }
599#endif /* 3.1.3 */
600
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700601 conn->params_set = 1;
602
603 ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
604 conn->xcred);
605 if (ret < 0) {
606 wpa_printf(MSG_INFO, "Failed to configure credentials: %s",
607 gnutls_strerror(ret));
608 }
609
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700610 return ret;
611}
612
613
Dmitry Shmidt014a3ff2015-12-28 13:27:49 -0800614#if GNUTLS_VERSION_NUMBER >= 0x030103
615static int server_ocsp_status_req(gnutls_session_t session, void *ptr,
616 gnutls_datum_t *resp)
617{
618 struct tls_global *global = ptr;
619 char *cached;
620 size_t len;
621
622 if (!global->ocsp_stapling_response) {
623 wpa_printf(MSG_DEBUG, "GnuTLS: OCSP status callback - no response configured");
624 return GNUTLS_E_NO_CERTIFICATE_STATUS;
625 }
626
627 cached = os_readfile(global->ocsp_stapling_response, &len);
628 if (!cached) {
629 wpa_printf(MSG_DEBUG,
630 "GnuTLS: OCSP status callback - could not read response file (%s)",
631 global->ocsp_stapling_response);
632 return GNUTLS_E_NO_CERTIFICATE_STATUS;
633 }
634
635 wpa_printf(MSG_DEBUG,
636 "GnuTLS: OCSP status callback - send cached response");
637 resp->data = gnutls_malloc(len);
638 if (!resp->data) {
639 os_free(resp);
640 return GNUTLS_E_MEMORY_ERROR;
641 }
642
643 os_memcpy(resp->data, cached, len);
644 resp->size = len;
645 os_free(cached);
646
647 return GNUTLS_E_SUCCESS;
648}
649#endif /* 3.1.3 */
650
651
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700652int tls_global_set_params(void *tls_ctx,
653 const struct tls_connection_params *params)
654{
655 struct tls_global *global = tls_ctx;
656 int ret;
657
658 /* Currently, global parameters are only set when running in server
659 * mode. */
660 global->server = 1;
661
662 if (global->params_set) {
663 gnutls_certificate_free_credentials(global->xcred);
664 global->params_set = 0;
665 }
666
667 ret = gnutls_certificate_allocate_credentials(&global->xcred);
668 if (ret) {
669 wpa_printf(MSG_DEBUG, "Failed to allocate global credentials "
670 "%s", gnutls_strerror(ret));
671 return -1;
672 }
673
674 if (params->ca_cert) {
675 ret = gnutls_certificate_set_x509_trust_file(
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800676 global->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700677 if (ret < 0) {
678 wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800679 "in DER format: %s", params->ca_cert,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700680 gnutls_strerror(ret));
681 ret = gnutls_certificate_set_x509_trust_file(
682 global->xcred, params->ca_cert,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800683 GNUTLS_X509_FMT_PEM);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700684 if (ret < 0) {
685 wpa_printf(MSG_DEBUG, "Failed to read CA cert "
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800686 "'%s' in PEM format: %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700687 params->ca_cert,
688 gnutls_strerror(ret));
689 goto fail;
690 }
691 }
692
693 if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
694 gnutls_certificate_set_verify_flags(
695 global->xcred,
696 GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
697 }
698
699 if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
700 gnutls_certificate_set_verify_flags(
701 global->xcred,
702 GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
703 }
704 }
705
706 if (params->client_cert && params->private_key) {
707 /* TODO: private_key_passwd? */
708 ret = gnutls_certificate_set_x509_key_file(
709 global->xcred, params->client_cert,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800710 params->private_key, GNUTLS_X509_FMT_DER);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700711 if (ret < 0) {
712 wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800713 "in DER format: %s", gnutls_strerror(ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700714 ret = gnutls_certificate_set_x509_key_file(
715 global->xcred, params->client_cert,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800716 params->private_key, GNUTLS_X509_FMT_PEM);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700717 if (ret < 0) {
718 wpa_printf(MSG_DEBUG, "Failed to read client "
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800719 "cert/key in PEM format: %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700720 gnutls_strerror(ret));
721 goto fail;
722 }
723 }
724 } else if (params->private_key) {
725 int pkcs12_ok = 0;
726#ifdef PKCS12_FUNCS
727 /* Try to load in PKCS#12 format */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700728 ret = gnutls_certificate_set_x509_simple_pkcs12_file(
729 global->xcred, params->private_key,
730 GNUTLS_X509_FMT_DER, params->private_key_passwd);
731 if (ret != 0) {
732 wpa_printf(MSG_DEBUG, "Failed to load private_key in "
733 "PKCS#12 format: %s", gnutls_strerror(ret));
734 goto fail;
735 } else
736 pkcs12_ok = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700737#endif /* PKCS12_FUNCS */
738
739 if (!pkcs12_ok) {
740 wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
741 "included");
742 goto fail;
743 }
744 }
745
Dmitry Shmidt014a3ff2015-12-28 13:27:49 -0800746#if GNUTLS_VERSION_NUMBER >= 0x030103
747 os_free(global->ocsp_stapling_response);
748 if (params->ocsp_stapling_response)
749 global->ocsp_stapling_response =
750 os_strdup(params->ocsp_stapling_response);
751 else
752 global->ocsp_stapling_response = NULL;
753 gnutls_certificate_set_ocsp_status_request_function(
754 global->xcred, server_ocsp_status_req, global);
755#endif /* 3.1.3 */
756
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700757 global->params_set = 1;
758
759 return 0;
760
761fail:
762 gnutls_certificate_free_credentials(global->xcred);
763 return -1;
764}
765
766
767int tls_global_set_verify(void *ssl_ctx, int check_crl)
768{
769 /* TODO */
770 return 0;
771}
772
773
774int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800775 int verify_peer, unsigned int flags,
776 const u8 *session_ctx, size_t session_ctx_len)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700777{
778 if (conn == NULL || conn->session == NULL)
779 return -1;
780
781 conn->verify_peer = verify_peer;
782 gnutls_certificate_server_set_request(conn->session,
783 verify_peer ? GNUTLS_CERT_REQUIRE
784 : GNUTLS_CERT_REQUEST);
785
786 return 0;
787}
788
789
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800790int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
791 struct tls_random *keys)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700792{
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800793#if GNUTLS_VERSION_NUMBER >= 0x030012
794 gnutls_datum_t client, server;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700795
796 if (conn == NULL || conn->session == NULL || keys == NULL)
797 return -1;
798
799 os_memset(keys, 0, sizeof(*keys));
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800800 gnutls_session_get_random(conn->session, &client, &server);
801 keys->client_random = client.data;
802 keys->server_random = server.data;
803 keys->client_random_len = client.size;
804 keys->server_random_len = client.size;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700805
806 return 0;
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800807#else /* 3.0.18 */
808 return -1;
809#endif /* 3.0.18 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700810}
811
812
813int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
814 const char *label, int server_random_first,
Dmitry Shmidtaf9da312015-04-03 10:03:11 -0700815 int skip_keyblock, u8 *out, size_t out_len)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700816{
Dmitry Shmidtaf9da312015-04-03 10:03:11 -0700817 if (conn == NULL || conn->session == NULL || skip_keyblock)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700818 return -1;
819
820 return gnutls_prf(conn->session, os_strlen(label), label,
821 server_random_first, 0, NULL, out_len, (char *) out);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700822}
823
824
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800825static void gnutls_tls_fail_event(struct tls_connection *conn,
826 const gnutls_datum_t *cert, int depth,
827 const char *subject, const char *err_str,
828 enum tls_fail_reason reason)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700829{
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800830 union tls_event_data ev;
831 struct tls_global *global = conn->global;
832 struct wpabuf *cert_buf = NULL;
833
834 if (global->event_cb == NULL)
835 return;
836
837 os_memset(&ev, 0, sizeof(ev));
838 ev.cert_fail.depth = depth;
839 ev.cert_fail.subject = subject ? subject : "";
840 ev.cert_fail.reason = reason;
841 ev.cert_fail.reason_txt = err_str;
842 if (cert) {
843 cert_buf = wpabuf_alloc_copy(cert->data, cert->size);
844 ev.cert_fail.cert = cert_buf;
845 }
846 global->event_cb(global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
847 wpabuf_free(cert_buf);
848}
849
850
851#if GNUTLS_VERSION_NUMBER < 0x030300
852static int server_eku_purpose(gnutls_x509_crt_t cert)
853{
854 unsigned int i;
855
856 for (i = 0; ; i++) {
857 char oid[128];
858 size_t oid_size = sizeof(oid);
859 int res;
860
861 res = gnutls_x509_crt_get_key_purpose_oid(cert, i, oid,
862 &oid_size, NULL);
863 if (res == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
864 if (i == 0) {
865 /* No EKU - assume any use allowed */
866 return 1;
867 }
868 break;
869 }
870
871 if (res < 0) {
872 wpa_printf(MSG_INFO, "GnuTLS: Failed to get EKU");
873 return 0;
874 }
875
876 wpa_printf(MSG_DEBUG, "GnuTLS: Certificate purpose: %s", oid);
877 if (os_strcmp(oid, GNUTLS_KP_TLS_WWW_SERVER) == 0 ||
878 os_strcmp(oid, GNUTLS_KP_ANY) == 0)
879 return 1;
880 }
881
882 return 0;
883}
884#endif /* < 3.3.0 */
885
886
887static int check_ocsp(struct tls_connection *conn, gnutls_session_t session,
888 gnutls_alert_description_t *err)
889{
890#if GNUTLS_VERSION_NUMBER >= 0x030103
891 gnutls_datum_t response, buf;
892 gnutls_ocsp_resp_t resp;
893 unsigned int cert_status;
894 int res;
895
896 if (!(conn->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)))
897 return 0;
898
899 if (!gnutls_ocsp_status_request_is_checked(session, 0)) {
900 if (conn->flags & TLS_CONN_REQUIRE_OCSP) {
901 wpa_printf(MSG_INFO,
902 "GnuTLS: No valid OCSP response received");
903 goto ocsp_error;
904 }
905
906 wpa_printf(MSG_DEBUG,
907 "GnuTLS: Valid OCSP response was not received - continue since OCSP was not required");
908 return 0;
909 }
910
911 /*
912 * GnuTLS has already verified the OCSP response in
913 * check_ocsp_response() and rejected handshake if the certificate was
914 * found to be revoked. However, if the response indicates that the
915 * status is unknown, handshake continues and reaches here. We need to
916 * re-import the OCSP response to check for unknown certificate status,
917 * but we do not need to repeat gnutls_ocsp_resp_check_crt() and
918 * gnutls_ocsp_resp_verify_direct() calls.
919 */
920
921 res = gnutls_ocsp_status_request_get(session, &response);
922 if (res != GNUTLS_E_SUCCESS) {
923 wpa_printf(MSG_INFO,
924 "GnuTLS: OCSP response was received, but it was not valid");
925 goto ocsp_error;
926 }
927
928 if (gnutls_ocsp_resp_init(&resp) != GNUTLS_E_SUCCESS)
929 goto ocsp_error;
930
931 res = gnutls_ocsp_resp_import(resp, &response);
932 if (res != GNUTLS_E_SUCCESS) {
933 wpa_printf(MSG_INFO,
934 "GnuTLS: Could not parse received OCSP response: %s",
935 gnutls_strerror(res));
936 gnutls_ocsp_resp_deinit(resp);
937 goto ocsp_error;
938 }
939
940 res = gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &buf);
941 if (res == GNUTLS_E_SUCCESS) {
942 wpa_printf(MSG_DEBUG, "GnuTLS: %s", buf.data);
943 gnutls_free(buf.data);
944 }
945
946 res = gnutls_ocsp_resp_get_single(resp, 0, NULL, NULL, NULL,
947 NULL, &cert_status, NULL,
948 NULL, NULL, NULL);
949 gnutls_ocsp_resp_deinit(resp);
950 if (res != GNUTLS_E_SUCCESS) {
951 wpa_printf(MSG_INFO,
952 "GnuTLS: Failed to extract OCSP information: %s",
953 gnutls_strerror(res));
954 goto ocsp_error;
955 }
956
957 if (cert_status == GNUTLS_OCSP_CERT_GOOD) {
958 wpa_printf(MSG_DEBUG, "GnuTLS: OCSP cert status: good");
959 } else if (cert_status == GNUTLS_OCSP_CERT_REVOKED) {
960 wpa_printf(MSG_DEBUG,
961 "GnuTLS: OCSP cert status: revoked");
962 goto ocsp_error;
963 } else {
964 wpa_printf(MSG_DEBUG,
965 "GnuTLS: OCSP cert status: unknown");
966 if (conn->flags & TLS_CONN_REQUIRE_OCSP)
967 goto ocsp_error;
968 wpa_printf(MSG_DEBUG,
969 "GnuTLS: OCSP was not required, so allow connection to continue");
970 }
971
972 return 0;
973
974ocsp_error:
975 gnutls_tls_fail_event(conn, NULL, 0, NULL,
976 "bad certificate status response",
977 TLS_FAIL_REVOKED);
978 *err = GNUTLS_A_CERTIFICATE_REVOKED;
979 return -1;
980#else /* GnuTLS 3.1.3 or newer */
981 return 0;
982#endif /* GnuTLS 3.1.3 or newer */
983}
984
985
986static int tls_connection_verify_peer(gnutls_session_t session)
987{
988 struct tls_connection *conn;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700989 unsigned int status, num_certs, i;
990 struct os_time now;
991 const gnutls_datum_t *certs;
992 gnutls_x509_crt_t cert;
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800993 gnutls_alert_description_t err;
994 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700995
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800996 conn = gnutls_session_get_ptr(session);
997 if (!conn->verify_peer) {
998 wpa_printf(MSG_DEBUG,
999 "GnuTLS: No peer certificate verification enabled");
1000 return 0;
1001 }
1002
1003 wpa_printf(MSG_DEBUG, "GnuTSL: Verifying peer certificate");
1004
1005#if GNUTLS_VERSION_NUMBER >= 0x030300
1006 {
1007 gnutls_typed_vdata_st data[1];
1008 unsigned int elements = 0;
1009
1010 os_memset(data, 0, sizeof(data));
1011 if (!conn->global->server) {
1012 data[elements].type = GNUTLS_DT_KEY_PURPOSE_OID;
1013 data[elements].data = (void *) GNUTLS_KP_TLS_WWW_SERVER;
1014 elements++;
1015 }
1016 res = gnutls_certificate_verify_peers(session, data, 1,
1017 &status);
1018 }
1019#else /* < 3.3.0 */
1020 res = gnutls_certificate_verify_peers2(session, &status);
1021#endif
1022 if (res < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001023 wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
1024 "certificate chain");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001025 err = GNUTLS_A_INTERNAL_ERROR;
1026 goto out;
1027 }
1028
1029#if GNUTLS_VERSION_NUMBER >= 0x030104
1030 {
1031 gnutls_datum_t info;
1032 int ret, type;
1033
1034 type = gnutls_certificate_type_get(session);
1035 ret = gnutls_certificate_verification_status_print(status, type,
1036 &info, 0);
1037 if (ret < 0) {
1038 wpa_printf(MSG_DEBUG,
1039 "GnuTLS: Failed to print verification status");
1040 err = GNUTLS_A_INTERNAL_ERROR;
1041 goto out;
1042 }
1043 wpa_printf(MSG_DEBUG, "GnuTLS: %s", info.data);
1044 gnutls_free(info.data);
1045 }
1046#endif /* GnuTLS 3.1.4 or newer */
1047
1048 certs = gnutls_certificate_get_peers(session, &num_certs);
1049 if (certs == NULL || num_certs == 0) {
1050 wpa_printf(MSG_INFO, "TLS: No peer certificate chain received");
1051 err = GNUTLS_A_UNKNOWN_CA;
1052 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001053 }
1054
1055 if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
1056 wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
1057 if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
1058 wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
1059 "algorithm");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001060 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1061 "certificate uses insecure algorithm",
1062 TLS_FAIL_BAD_CERTIFICATE);
1063 err = GNUTLS_A_INSUFFICIENT_SECURITY;
1064 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001065 }
1066 if (status & GNUTLS_CERT_NOT_ACTIVATED) {
1067 wpa_printf(MSG_INFO, "TLS: Certificate not yet "
1068 "activated");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001069 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1070 "certificate not yet valid",
1071 TLS_FAIL_NOT_YET_VALID);
1072 err = GNUTLS_A_CERTIFICATE_EXPIRED;
1073 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001074 }
1075 if (status & GNUTLS_CERT_EXPIRED) {
1076 wpa_printf(MSG_INFO, "TLS: Certificate expired");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001077 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1078 "certificate has expired",
1079 TLS_FAIL_EXPIRED);
1080 err = GNUTLS_A_CERTIFICATE_EXPIRED;
1081 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001082 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001083 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1084 "untrusted certificate",
1085 TLS_FAIL_UNTRUSTED);
1086 err = GNUTLS_A_INTERNAL_ERROR;
1087 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001088 }
1089
1090 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
1091 wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
1092 "known issuer");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001093 gnutls_tls_fail_event(conn, NULL, 0, NULL, "signed not found",
1094 TLS_FAIL_UNTRUSTED);
1095 err = GNUTLS_A_UNKNOWN_CA;
1096 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001097 }
1098
1099 if (status & GNUTLS_CERT_REVOKED) {
1100 wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001101 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1102 "certificate revoked",
1103 TLS_FAIL_REVOKED);
1104 err = GNUTLS_A_CERTIFICATE_REVOKED;
1105 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001106 }
1107
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001108 if (status != 0) {
1109 wpa_printf(MSG_INFO, "TLS: Unknown verification status: %d",
1110 status);
1111 err = GNUTLS_A_INTERNAL_ERROR;
1112 goto out;
1113 }
1114
1115 if (check_ocsp(conn, session, &err))
1116 goto out;
1117
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001118 os_get_time(&now);
1119
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001120 for (i = 0; i < num_certs; i++) {
1121 char *buf;
1122 size_t len;
1123 if (gnutls_x509_crt_init(&cert) < 0) {
1124 wpa_printf(MSG_INFO, "TLS: Certificate initialization "
1125 "failed");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001126 err = GNUTLS_A_BAD_CERTIFICATE;
1127 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001128 }
1129
1130 if (gnutls_x509_crt_import(cert, &certs[i],
1131 GNUTLS_X509_FMT_DER) < 0) {
1132 wpa_printf(MSG_INFO, "TLS: Could not parse peer "
1133 "certificate %d/%d", i + 1, num_certs);
1134 gnutls_x509_crt_deinit(cert);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001135 err = GNUTLS_A_BAD_CERTIFICATE;
1136 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001137 }
1138
1139 gnutls_x509_crt_get_dn(cert, NULL, &len);
1140 len++;
1141 buf = os_malloc(len + 1);
1142 if (buf) {
1143 buf[0] = buf[len] = '\0';
1144 gnutls_x509_crt_get_dn(cert, buf, &len);
1145 }
1146 wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
1147 i + 1, num_certs, buf);
1148
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001149 if (conn->global->event_cb) {
1150 struct wpabuf *cert_buf = NULL;
1151 union tls_event_data ev;
1152#ifdef CONFIG_SHA256
1153 u8 hash[32];
1154 const u8 *_addr[1];
1155 size_t _len[1];
1156#endif /* CONFIG_SHA256 */
1157
1158 os_memset(&ev, 0, sizeof(ev));
1159 if (conn->global->cert_in_cb) {
1160 cert_buf = wpabuf_alloc_copy(certs[i].data,
1161 certs[i].size);
1162 ev.peer_cert.cert = cert_buf;
1163 }
1164#ifdef CONFIG_SHA256
1165 _addr[0] = certs[i].data;
1166 _len[0] = certs[i].size;
1167 if (sha256_vector(1, _addr, _len, hash) == 0) {
1168 ev.peer_cert.hash = hash;
1169 ev.peer_cert.hash_len = sizeof(hash);
1170 }
1171#endif /* CONFIG_SHA256 */
1172 ev.peer_cert.depth = i;
1173 ev.peer_cert.subject = buf;
1174 conn->global->event_cb(conn->global->cb_ctx,
1175 TLS_PEER_CERTIFICATE, &ev);
1176 wpabuf_free(cert_buf);
1177 }
1178
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001179 if (i == 0) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001180 if (conn->suffix_match &&
1181 !gnutls_x509_crt_check_hostname(
1182 cert, conn->suffix_match)) {
1183 wpa_printf(MSG_WARNING,
1184 "TLS: Domain suffix match '%s' not found",
1185 conn->suffix_match);
1186 gnutls_tls_fail_event(
1187 conn, &certs[i], i, buf,
1188 "Domain suffix mismatch",
1189 TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
1190 err = GNUTLS_A_BAD_CERTIFICATE;
1191 gnutls_x509_crt_deinit(cert);
1192 os_free(buf);
1193 goto out;
1194 }
1195
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08001196#if GNUTLS_VERSION_NUMBER >= 0x030300
1197 if (conn->domain_match &&
1198 !gnutls_x509_crt_check_hostname2(
1199 cert, conn->domain_match,
1200 GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS)) {
1201 wpa_printf(MSG_WARNING,
1202 "TLS: Domain match '%s' not found",
1203 conn->domain_match);
1204 gnutls_tls_fail_event(
1205 conn, &certs[i], i, buf,
1206 "Domain mismatch",
1207 TLS_FAIL_DOMAIN_MISMATCH);
1208 err = GNUTLS_A_BAD_CERTIFICATE;
1209 gnutls_x509_crt_deinit(cert);
1210 os_free(buf);
1211 goto out;
1212 }
1213#endif /* >= 3.3.0 */
1214
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001215 /* TODO: validate altsubject_match.
1216 * For now, any such configuration is rejected in
1217 * tls_connection_set_params() */
1218
1219#if GNUTLS_VERSION_NUMBER < 0x030300
1220 /*
1221 * gnutls_certificate_verify_peers() not available, so
1222 * need to check EKU separately.
1223 */
1224 if (!conn->global->server &&
1225 !server_eku_purpose(cert)) {
1226 wpa_printf(MSG_WARNING,
1227 "GnuTLS: No server EKU");
1228 gnutls_tls_fail_event(
1229 conn, &certs[i], i, buf,
1230 "No server EKU",
1231 TLS_FAIL_BAD_CERTIFICATE);
1232 err = GNUTLS_A_BAD_CERTIFICATE;
1233 gnutls_x509_crt_deinit(cert);
1234 os_free(buf);
1235 goto out;
1236 }
1237#endif /* < 3.3.0 */
1238 }
1239
1240 if (!conn->disable_time_checks &&
1241 (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
1242 gnutls_x509_crt_get_activation_time(cert) > now.sec)) {
1243 wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
1244 "not valid at this time",
1245 i + 1, num_certs);
1246 gnutls_tls_fail_event(
1247 conn, &certs[i], i, buf,
1248 "Certificate is not valid at this time",
1249 TLS_FAIL_EXPIRED);
1250 gnutls_x509_crt_deinit(cert);
1251 os_free(buf);
1252 err = GNUTLS_A_CERTIFICATE_EXPIRED;
1253 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001254 }
1255
1256 os_free(buf);
1257
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001258 gnutls_x509_crt_deinit(cert);
1259 }
1260
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001261 if (conn->global->event_cb != NULL)
1262 conn->global->event_cb(conn->global->cb_ctx,
1263 TLS_CERT_CHAIN_SUCCESS, NULL);
1264
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001265 return 0;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001266
1267out:
1268 conn->failed++;
1269 gnutls_alert_send(session, GNUTLS_AL_FATAL, err);
1270 return GNUTLS_E_CERTIFICATE_ERROR;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001271}
1272
1273
1274static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn)
1275{
1276 int res;
1277 struct wpabuf *ad;
1278 wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data");
1279 ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3);
1280 if (ad == NULL)
1281 return NULL;
1282
1283 res = gnutls_record_recv(conn->session, wpabuf_mhead(ad),
1284 wpabuf_size(ad));
1285 wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res);
1286 if (res < 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001287 wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001288 "(%s)", __func__, (int) res,
1289 gnutls_strerror(res));
1290 wpabuf_free(ad);
1291 return NULL;
1292 }
1293
1294 wpabuf_put(ad, res);
1295 wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data",
1296 res);
1297 return ad;
1298}
1299
1300
1301struct wpabuf * tls_connection_handshake(void *tls_ctx,
1302 struct tls_connection *conn,
1303 const struct wpabuf *in_data,
1304 struct wpabuf **appl_data)
1305{
1306 struct tls_global *global = tls_ctx;
1307 struct wpabuf *out_data;
1308 int ret;
1309
1310 if (appl_data)
1311 *appl_data = NULL;
1312
1313 if (in_data && wpabuf_len(in_data) > 0) {
1314 if (conn->pull_buf) {
1315 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
1316 "pull_buf", __func__,
1317 (unsigned long) wpabuf_len(conn->pull_buf));
1318 wpabuf_free(conn->pull_buf);
1319 }
1320 conn->pull_buf = wpabuf_dup(in_data);
1321 if (conn->pull_buf == NULL)
1322 return NULL;
1323 conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
1324 }
1325
1326 ret = gnutls_handshake(conn->session);
1327 if (ret < 0) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001328 gnutls_alert_description_t alert;
1329
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001330 switch (ret) {
1331 case GNUTLS_E_AGAIN:
1332 if (global->server && conn->established &&
1333 conn->push_buf == NULL) {
1334 /* Need to return something to trigger
1335 * completion of EAP-TLS. */
1336 conn->push_buf = wpabuf_alloc(0);
1337 }
1338 break;
1339 case GNUTLS_E_FATAL_ALERT_RECEIVED:
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001340 alert = gnutls_alert_get(conn->session);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001341 wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001342 __func__, gnutls_alert_get_name(alert));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001343 conn->read_alerts++;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001344 if (conn->global->event_cb != NULL) {
1345 union tls_event_data ev;
1346
1347 os_memset(&ev, 0, sizeof(ev));
1348 ev.alert.is_local = 0;
1349 ev.alert.type = gnutls_alert_get_name(alert);
1350 ev.alert.description = ev.alert.type;
1351 conn->global->event_cb(conn->global->cb_ctx,
1352 TLS_ALERT, &ev);
1353 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001354 /* continue */
1355 default:
1356 wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
1357 "-> %s", __func__, gnutls_strerror(ret));
1358 conn->failed++;
1359 }
1360 } else {
1361 size_t size;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001362
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001363 wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001364
1365#if GNUTLS_VERSION_NUMBER >= 0x03010a
1366 {
1367 char *desc;
1368
1369 desc = gnutls_session_get_desc(conn->session);
1370 if (desc) {
1371 wpa_printf(MSG_DEBUG, "GnuTLS: %s", desc);
1372 gnutls_free(desc);
1373 }
1374 }
1375#endif /* GnuTLS 3.1.10 or newer */
1376
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001377 conn->established = 1;
1378 if (conn->push_buf == NULL) {
1379 /* Need to return something to get final TLS ACK. */
1380 conn->push_buf = wpabuf_alloc(0);
1381 }
1382
1383 gnutls_session_get_data(conn->session, NULL, &size);
1384 if (global->session_data == NULL ||
1385 global->session_data_size < size) {
1386 os_free(global->session_data);
1387 global->session_data = os_malloc(size);
1388 }
1389 if (global->session_data) {
1390 global->session_data_size = size;
1391 gnutls_session_get_data(conn->session,
1392 global->session_data,
1393 &global->session_data_size);
1394 }
1395
1396 if (conn->pull_buf && appl_data)
1397 *appl_data = gnutls_get_appl_data(conn);
1398 }
1399
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001400 out_data = conn->push_buf;
1401 conn->push_buf = NULL;
1402 return out_data;
1403}
1404
1405
1406struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
1407 struct tls_connection *conn,
1408 const struct wpabuf *in_data,
1409 struct wpabuf **appl_data)
1410{
1411 return tls_connection_handshake(tls_ctx, conn, in_data, appl_data);
1412}
1413
1414
1415struct wpabuf * tls_connection_encrypt(void *tls_ctx,
1416 struct tls_connection *conn,
1417 const struct wpabuf *in_data)
1418{
1419 ssize_t res;
1420 struct wpabuf *buf;
1421
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001422 res = gnutls_record_send(conn->session, wpabuf_head(in_data),
1423 wpabuf_len(in_data));
1424 if (res < 0) {
1425 wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
1426 __func__, gnutls_strerror(res));
1427 return NULL;
1428 }
1429
1430 buf = conn->push_buf;
1431 conn->push_buf = NULL;
1432 return buf;
1433}
1434
1435
1436struct wpabuf * tls_connection_decrypt(void *tls_ctx,
1437 struct tls_connection *conn,
1438 const struct wpabuf *in_data)
1439{
1440 ssize_t res;
1441 struct wpabuf *out;
1442
1443 if (conn->pull_buf) {
1444 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
1445 "pull_buf", __func__,
1446 (unsigned long) wpabuf_len(conn->pull_buf));
1447 wpabuf_free(conn->pull_buf);
1448 }
1449 conn->pull_buf = wpabuf_dup(in_data);
1450 if (conn->pull_buf == NULL)
1451 return NULL;
1452 conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
1453
1454 /*
1455 * Even though we try to disable TLS compression, it is possible that
1456 * this cannot be done with all TLS libraries. Add extra buffer space
1457 * to handle the possibility of the decrypted data being longer than
1458 * input data.
1459 */
1460 out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
1461 if (out == NULL)
1462 return NULL;
1463
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001464 res = gnutls_record_recv(conn->session, wpabuf_mhead(out),
1465 wpabuf_size(out));
1466 if (res < 0) {
1467 wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
1468 "(%s)", __func__, (int) res, gnutls_strerror(res));
1469 wpabuf_free(out);
1470 return NULL;
1471 }
1472 wpabuf_put(out, res);
1473
1474 return out;
1475}
1476
1477
1478int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
1479{
1480 if (conn == NULL)
1481 return 0;
1482 return gnutls_session_is_resumed(conn->session);
1483}
1484
1485
1486int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
1487 u8 *ciphers)
1488{
1489 /* TODO */
1490 return -1;
1491}
1492
1493
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001494int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
1495 char *buf, size_t buflen)
1496{
1497 /* TODO */
1498 return -1;
1499}
1500
1501
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001502int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
1503 char *buf, size_t buflen)
1504{
1505 /* TODO */
1506 buf[0] = '\0';
1507 return 0;
1508}
1509
1510
1511int tls_connection_enable_workaround(void *ssl_ctx,
1512 struct tls_connection *conn)
1513{
1514 gnutls_record_disable_padding(conn->session);
1515 return 0;
1516}
1517
1518
1519int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
1520 int ext_type, const u8 *data,
1521 size_t data_len)
1522{
1523 /* TODO */
1524 return -1;
1525}
1526
1527
1528int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
1529{
1530 if (conn == NULL)
1531 return -1;
1532 return conn->failed;
1533}
1534
1535
1536int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
1537{
1538 if (conn == NULL)
1539 return -1;
1540 return conn->read_alerts;
1541}
1542
1543
1544int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
1545{
1546 if (conn == NULL)
1547 return -1;
1548 return conn->write_alerts;
1549}
1550
1551
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001552int tls_connection_set_session_ticket_cb(void *tls_ctx,
1553 struct tls_connection *conn,
1554 tls_session_ticket_cb cb, void *ctx)
1555{
1556 return -1;
1557}
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001558
1559
1560int tls_get_library_version(char *buf, size_t buf_len)
1561{
1562 return os_snprintf(buf, buf_len, "GnuTLS build=%s run=%s",
1563 GNUTLS_VERSION, gnutls_check_version(NULL));
1564}
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001565
1566
1567void tls_connection_set_success_data(struct tls_connection *conn,
1568 struct wpabuf *data)
1569{
1570}
1571
1572
1573void tls_connection_set_success_data_resumed(struct tls_connection *conn)
1574{
1575}
1576
1577
1578const struct wpabuf *
1579tls_connection_get_success_data(struct tls_connection *conn)
1580{
1581 return NULL;
1582}
1583
1584
1585void tls_connection_remove_session(struct tls_connection *conn)
1586{
1587}