blob: b1bec4a5388f19ebf2d676ef7093c73fa168e61f [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 Shmidt8d520ff2011-05-09 14:06:53 -070040};
41
42struct tls_connection {
Dmitry Shmidtff787d52015-01-12 13:01:47 -080043 struct tls_global *global;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080044 gnutls_session_t session;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070045 int read_alerts, write_alerts, failed;
46
47 u8 *pre_shared_secret;
48 size_t pre_shared_secret_len;
49 int established;
50 int verify_peer;
Dmitry Shmidtff787d52015-01-12 13:01:47 -080051 unsigned int disable_time_checks:1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070052
53 struct wpabuf *push_buf;
54 struct wpabuf *pull_buf;
55 const u8 *pull_buf_offset;
56
57 int params_set;
58 gnutls_certificate_credentials_t xcred;
Dmitry Shmidtff787d52015-01-12 13:01:47 -080059
60 char *suffix_match;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -080061 char *domain_match;
Dmitry Shmidtff787d52015-01-12 13:01:47 -080062 unsigned int flags;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070063};
64
65
Dmitry Shmidtff787d52015-01-12 13:01:47 -080066static int tls_connection_verify_peer(gnutls_session_t session);
67
68
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070069static void tls_log_func(int level, const char *msg)
70{
71 char *s, *pos;
72 if (level == 6 || level == 7) {
73 /* These levels seem to be mostly I/O debug and msg dumps */
74 return;
75 }
76
77 s = os_strdup(msg);
78 if (s == NULL)
79 return;
80
81 pos = s;
82 while (*pos != '\0') {
83 if (*pos == '\n') {
84 *pos = '\0';
85 break;
86 }
87 pos++;
88 }
89 wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
90 "gnutls<%d> %s", level, s);
91 os_free(s);
92}
93
94
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070095void * tls_init(const struct tls_config *conf)
96{
97 struct tls_global *global;
98
Dmitry Shmidtff787d52015-01-12 13:01:47 -080099 if (tls_gnutls_ref_count == 0) {
100 wpa_printf(MSG_DEBUG,
101 "GnuTLS: Library version %s (runtime) - %s (build)",
102 gnutls_check_version(NULL), GNUTLS_VERSION);
103 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700104
105 global = os_zalloc(sizeof(*global));
106 if (global == NULL)
107 return NULL;
108
109 if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) {
110 os_free(global);
111 return NULL;
112 }
113 tls_gnutls_ref_count++;
114
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700115 gnutls_global_set_log_function(tls_log_func);
116 if (wpa_debug_show_keys)
117 gnutls_global_set_log_level(11);
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800118
119 if (conf) {
120 global->event_cb = conf->event_cb;
121 global->cb_ctx = conf->cb_ctx;
122 global->cert_in_cb = conf->cert_in_cb;
123 }
124
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700125 return global;
126}
127
128
129void tls_deinit(void *ssl_ctx)
130{
131 struct tls_global *global = ssl_ctx;
132 if (global) {
133 if (global->params_set)
134 gnutls_certificate_free_credentials(global->xcred);
135 os_free(global->session_data);
136 os_free(global);
137 }
138
139 tls_gnutls_ref_count--;
140 if (tls_gnutls_ref_count == 0)
141 gnutls_global_deinit();
142}
143
144
145int tls_get_errors(void *ssl_ctx)
146{
147 return 0;
148}
149
150
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800151static ssize_t tls_pull_func(gnutls_transport_ptr_t ptr, void *buf,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700152 size_t len)
153{
154 struct tls_connection *conn = (struct tls_connection *) ptr;
155 const u8 *end;
156 if (conn->pull_buf == NULL) {
157 errno = EWOULDBLOCK;
158 return -1;
159 }
160
161 end = wpabuf_head_u8(conn->pull_buf) + wpabuf_len(conn->pull_buf);
162 if ((size_t) (end - conn->pull_buf_offset) < len)
163 len = end - conn->pull_buf_offset;
164 os_memcpy(buf, conn->pull_buf_offset, len);
165 conn->pull_buf_offset += len;
166 if (conn->pull_buf_offset == end) {
167 wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
168 wpabuf_free(conn->pull_buf);
169 conn->pull_buf = NULL;
170 conn->pull_buf_offset = NULL;
171 } else {
172 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
173 __func__,
174 (unsigned long) (end - conn->pull_buf_offset));
175 }
176 return len;
177}
178
179
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800180static ssize_t tls_push_func(gnutls_transport_ptr_t ptr, const void *buf,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700181 size_t len)
182{
183 struct tls_connection *conn = (struct tls_connection *) ptr;
184
185 if (wpabuf_resize(&conn->push_buf, len) < 0) {
186 errno = ENOMEM;
187 return -1;
188 }
189 wpabuf_put_data(conn->push_buf, buf, len);
190
191 return len;
192}
193
194
195static int tls_gnutls_init_session(struct tls_global *global,
196 struct tls_connection *conn)
197{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800198 const char *err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700199 int ret;
200
201 ret = gnutls_init(&conn->session,
202 global->server ? GNUTLS_SERVER : GNUTLS_CLIENT);
203 if (ret < 0) {
204 wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
205 "connection: %s", gnutls_strerror(ret));
206 return -1;
207 }
208
209 ret = gnutls_set_default_priority(conn->session);
210 if (ret < 0)
211 goto fail;
212
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800213 ret = gnutls_priority_set_direct(conn->session, "NORMAL:-VERS-SSL3.0",
214 &err);
215 if (ret < 0) {
216 wpa_printf(MSG_ERROR, "GnuTLS: Priority string failure at "
217 "'%s'", err);
218 goto fail;
219 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700220
221 gnutls_transport_set_pull_function(conn->session, tls_pull_func);
222 gnutls_transport_set_push_function(conn->session, tls_push_func);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800223 gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr_t) conn);
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800224 gnutls_session_set_ptr(conn->session, conn);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700225
226 return 0;
227
228fail:
229 wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s",
230 gnutls_strerror(ret));
231 gnutls_deinit(conn->session);
232 return -1;
233}
234
235
236struct tls_connection * tls_connection_init(void *ssl_ctx)
237{
238 struct tls_global *global = ssl_ctx;
239 struct tls_connection *conn;
240 int ret;
241
242 conn = os_zalloc(sizeof(*conn));
243 if (conn == NULL)
244 return NULL;
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800245 conn->global = global;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700246
247 if (tls_gnutls_init_session(global, conn)) {
248 os_free(conn);
249 return NULL;
250 }
251
252 if (global->params_set) {
253 ret = gnutls_credentials_set(conn->session,
254 GNUTLS_CRD_CERTIFICATE,
255 global->xcred);
256 if (ret < 0) {
257 wpa_printf(MSG_INFO, "Failed to configure "
258 "credentials: %s", gnutls_strerror(ret));
259 os_free(conn);
260 return NULL;
261 }
262 }
263
264 if (gnutls_certificate_allocate_credentials(&conn->xcred)) {
265 os_free(conn);
266 return NULL;
267 }
268
269 return conn;
270}
271
272
273void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
274{
275 if (conn == NULL)
276 return;
277
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700278 gnutls_certificate_free_credentials(conn->xcred);
279 gnutls_deinit(conn->session);
280 os_free(conn->pre_shared_secret);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700281 wpabuf_free(conn->push_buf);
282 wpabuf_free(conn->pull_buf);
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800283 os_free(conn->suffix_match);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800284 os_free(conn->domain_match);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700285 os_free(conn);
286}
287
288
289int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
290{
291 return conn ? conn->established : 0;
292}
293
294
295int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
296{
297 struct tls_global *global = ssl_ctx;
298 int ret;
299
300 if (conn == NULL)
301 return -1;
302
303 /* Shutdown previous TLS connection without notifying the peer
304 * because the connection was already terminated in practice
305 * and "close notify" shutdown alert would confuse AS. */
306 gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
307 wpabuf_free(conn->push_buf);
308 conn->push_buf = NULL;
309 conn->established = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700310
311 gnutls_deinit(conn->session);
312 if (tls_gnutls_init_session(global, conn)) {
313 wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session "
314 "for session resumption use");
315 return -1;
316 }
317
318 ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
319 conn->params_set ? conn->xcred :
320 global->xcred);
321 if (ret < 0) {
322 wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials "
323 "for session resumption: %s", gnutls_strerror(ret));
324 return -1;
325 }
326
327 if (global->session_data) {
328 ret = gnutls_session_set_data(conn->session,
329 global->session_data,
330 global->session_data_size);
331 if (ret < 0) {
332 wpa_printf(MSG_INFO, "GnuTLS: Failed to set session "
333 "data: %s", gnutls_strerror(ret));
334 return -1;
335 }
336 }
337
338 return 0;
339}
340
341
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700342int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
343 const struct tls_connection_params *params)
344{
345 int ret;
346
347 if (conn == NULL || params == NULL)
348 return -1;
349
Dmitry Shmidt55840ad2015-12-14 12:45:46 -0800350 if (params->flags & TLS_CONN_EXT_CERT_CHECK) {
351 wpa_printf(MSG_INFO,
352 "GnuTLS: tls_ext_cert_check=1 not supported");
353 return -1;
354 }
355
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700356 if (params->subject_match) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800357 wpa_printf(MSG_INFO, "GnuTLS: subject_match not supported");
358 return -1;
359 }
360
361 if (params->altsubject_match) {
362 wpa_printf(MSG_INFO, "GnuTLS: altsubject_match not supported");
363 return -1;
364 }
365
366 os_free(conn->suffix_match);
367 conn->suffix_match = NULL;
368 if (params->suffix_match) {
369 conn->suffix_match = os_strdup(params->suffix_match);
370 if (conn->suffix_match == NULL)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700371 return -1;
372 }
373
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800374#if GNUTLS_VERSION_NUMBER >= 0x030300
375 os_free(conn->domain_match);
376 conn->domain_match = NULL;
377 if (params->domain_match) {
378 conn->domain_match = os_strdup(params->domain_match);
379 if (conn->domain_match == NULL)
380 return -1;
381 }
382#else /* < 3.3.0 */
383 if (params->domain_match) {
384 wpa_printf(MSG_INFO, "GnuTLS: domain_match not supported");
385 return -1;
386 }
387#endif /* >= 3.3.0 */
388
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800389 conn->flags = params->flags;
390
391 if (params->openssl_ciphers) {
392 wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
393 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700394 }
395
396 /* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
397 * to force peer validation(?) */
398
399 if (params->ca_cert) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800400 wpa_printf(MSG_DEBUG, "GnuTLS: Try to parse %s in DER format",
401 params->ca_cert);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700402 ret = gnutls_certificate_set_x509_trust_file(
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800403 conn->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700404 if (ret < 0) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800405 wpa_printf(MSG_DEBUG,
406 "GnuTLS: Failed to read CA cert '%s' in DER format (%s) - try in PEM format",
407 params->ca_cert,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700408 gnutls_strerror(ret));
409 ret = gnutls_certificate_set_x509_trust_file(
410 conn->xcred, params->ca_cert,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800411 GNUTLS_X509_FMT_PEM);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700412 if (ret < 0) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800413 wpa_printf(MSG_DEBUG,
414 "Failed to read CA cert '%s' in PEM format: %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700415 params->ca_cert,
416 gnutls_strerror(ret));
417 return -1;
418 }
419 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800420 } else if (params->ca_cert_blob) {
421 gnutls_datum_t ca;
422
423 ca.data = (unsigned char *) params->ca_cert_blob;
424 ca.size = params->ca_cert_blob_len;
425
426 ret = gnutls_certificate_set_x509_trust_mem(
427 conn->xcred, &ca, GNUTLS_X509_FMT_DER);
428 if (ret < 0) {
429 wpa_printf(MSG_DEBUG,
430 "Failed to parse CA cert in DER format: %s",
431 gnutls_strerror(ret));
432 ret = gnutls_certificate_set_x509_trust_mem(
433 conn->xcred, &ca, GNUTLS_X509_FMT_PEM);
434 if (ret < 0) {
435 wpa_printf(MSG_DEBUG,
436 "Failed to parse CA cert in PEM format: %s",
437 gnutls_strerror(ret));
438 return -1;
439 }
440 }
441 } else if (params->ca_path) {
442 wpa_printf(MSG_INFO, "GnuTLS: ca_path not supported");
443 return -1;
444 }
445
446 conn->disable_time_checks = 0;
447 if (params->ca_cert || params->ca_cert_blob) {
448 conn->verify_peer = 1;
449 gnutls_certificate_set_verify_function(
450 conn->xcred, tls_connection_verify_peer);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700451
452 if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
453 gnutls_certificate_set_verify_flags(
454 conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
455 }
456
457 if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800458 conn->disable_time_checks = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700459 gnutls_certificate_set_verify_flags(
460 conn->xcred,
461 GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
462 }
463 }
464
465 if (params->client_cert && params->private_key) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800466#if GNUTLS_VERSION_NUMBER >= 0x03010b
467 ret = gnutls_certificate_set_x509_key_file2(
468 conn->xcred, params->client_cert, params->private_key,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800469 GNUTLS_X509_FMT_DER, params->private_key_passwd, 0);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800470#else
471 /* private_key_passwd not (easily) supported here */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700472 ret = gnutls_certificate_set_x509_key_file(
473 conn->xcred, params->client_cert, params->private_key,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800474 GNUTLS_X509_FMT_DER);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800475#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700476 if (ret < 0) {
477 wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800478 "in DER format: %s", gnutls_strerror(ret));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800479#if GNUTLS_VERSION_NUMBER >= 0x03010b
480 ret = gnutls_certificate_set_x509_key_file2(
481 conn->xcred, params->client_cert,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800482 params->private_key, GNUTLS_X509_FMT_PEM,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800483 params->private_key_passwd, 0);
484#else
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700485 ret = gnutls_certificate_set_x509_key_file(
486 conn->xcred, params->client_cert,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800487 params->private_key, GNUTLS_X509_FMT_PEM);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800488#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700489 if (ret < 0) {
490 wpa_printf(MSG_DEBUG, "Failed to read client "
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800491 "cert/key in PEM format: %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700492 gnutls_strerror(ret));
493 return ret;
494 }
495 }
496 } else if (params->private_key) {
497 int pkcs12_ok = 0;
498#ifdef PKCS12_FUNCS
499 /* Try to load in PKCS#12 format */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700500 ret = gnutls_certificate_set_x509_simple_pkcs12_file(
501 conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
502 params->private_key_passwd);
503 if (ret != 0) {
504 wpa_printf(MSG_DEBUG, "Failed to load private_key in "
505 "PKCS#12 format: %s", gnutls_strerror(ret));
506 return -1;
507 } else
508 pkcs12_ok = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700509#endif /* PKCS12_FUNCS */
510
511 if (!pkcs12_ok) {
512 wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
513 "included");
514 return -1;
515 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800516 } else if (params->client_cert_blob && params->private_key_blob) {
517 gnutls_datum_t cert, key;
518
519 cert.data = (unsigned char *) params->client_cert_blob;
520 cert.size = params->client_cert_blob_len;
521 key.data = (unsigned char *) params->private_key_blob;
522 key.size = params->private_key_blob_len;
523
524#if GNUTLS_VERSION_NUMBER >= 0x03010b
525 ret = gnutls_certificate_set_x509_key_mem2(
526 conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER,
527 params->private_key_passwd, 0);
528#else
529 /* private_key_passwd not (easily) supported here */
530 ret = gnutls_certificate_set_x509_key_mem(
531 conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER);
532#endif
533 if (ret < 0) {
534 wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
535 "in DER format: %s", gnutls_strerror(ret));
536#if GNUTLS_VERSION_NUMBER >= 0x03010b
537 ret = gnutls_certificate_set_x509_key_mem2(
538 conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM,
539 params->private_key_passwd, 0);
540#else
541 /* private_key_passwd not (easily) supported here */
542 ret = gnutls_certificate_set_x509_key_mem(
543 conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM);
544#endif
545 if (ret < 0) {
546 wpa_printf(MSG_DEBUG, "Failed to read client "
547 "cert/key in PEM format: %s",
548 gnutls_strerror(ret));
549 return ret;
550 }
551 }
552 } else if (params->private_key_blob) {
553#ifdef PKCS12_FUNCS
554 gnutls_datum_t key;
555
556 key.data = (unsigned char *) params->private_key_blob;
557 key.size = params->private_key_blob_len;
558
559 /* Try to load in PKCS#12 format */
560 ret = gnutls_certificate_set_x509_simple_pkcs12_mem(
561 conn->xcred, &key, GNUTLS_X509_FMT_DER,
562 params->private_key_passwd);
563 if (ret != 0) {
564 wpa_printf(MSG_DEBUG, "Failed to load private_key in "
565 "PKCS#12 format: %s", gnutls_strerror(ret));
566 return -1;
567 }
568#else /* PKCS12_FUNCS */
569 wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not included");
570 return -1;
571#endif /* PKCS12_FUNCS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700572 }
573
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800574#if GNUTLS_VERSION_NUMBER >= 0x030103
575 if (params->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)) {
576 ret = gnutls_ocsp_status_request_enable_client(conn->session,
577 NULL, 0, NULL);
578 if (ret != GNUTLS_E_SUCCESS) {
579 wpa_printf(MSG_INFO,
580 "GnuTLS: Failed to enable OCSP client");
581 return -1;
582 }
583 }
584#else /* 3.1.3 */
585 if (params->flags & TLS_CONN_REQUIRE_OCSP) {
586 wpa_printf(MSG_INFO,
587 "GnuTLS: OCSP not supported by this version of GnuTLS");
588 return -1;
589 }
590#endif /* 3.1.3 */
591
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700592 conn->params_set = 1;
593
594 ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
595 conn->xcred);
596 if (ret < 0) {
597 wpa_printf(MSG_INFO, "Failed to configure credentials: %s",
598 gnutls_strerror(ret));
599 }
600
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700601 return ret;
602}
603
604
605int tls_global_set_params(void *tls_ctx,
606 const struct tls_connection_params *params)
607{
608 struct tls_global *global = tls_ctx;
609 int ret;
610
611 /* Currently, global parameters are only set when running in server
612 * mode. */
613 global->server = 1;
614
615 if (global->params_set) {
616 gnutls_certificate_free_credentials(global->xcred);
617 global->params_set = 0;
618 }
619
620 ret = gnutls_certificate_allocate_credentials(&global->xcred);
621 if (ret) {
622 wpa_printf(MSG_DEBUG, "Failed to allocate global credentials "
623 "%s", gnutls_strerror(ret));
624 return -1;
625 }
626
627 if (params->ca_cert) {
628 ret = gnutls_certificate_set_x509_trust_file(
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800629 global->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700630 if (ret < 0) {
631 wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800632 "in DER format: %s", params->ca_cert,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700633 gnutls_strerror(ret));
634 ret = gnutls_certificate_set_x509_trust_file(
635 global->xcred, params->ca_cert,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800636 GNUTLS_X509_FMT_PEM);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700637 if (ret < 0) {
638 wpa_printf(MSG_DEBUG, "Failed to read CA cert "
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800639 "'%s' in PEM format: %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700640 params->ca_cert,
641 gnutls_strerror(ret));
642 goto fail;
643 }
644 }
645
646 if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
647 gnutls_certificate_set_verify_flags(
648 global->xcred,
649 GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
650 }
651
652 if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
653 gnutls_certificate_set_verify_flags(
654 global->xcred,
655 GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
656 }
657 }
658
659 if (params->client_cert && params->private_key) {
660 /* TODO: private_key_passwd? */
661 ret = gnutls_certificate_set_x509_key_file(
662 global->xcred, params->client_cert,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800663 params->private_key, GNUTLS_X509_FMT_DER);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700664 if (ret < 0) {
665 wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800666 "in DER format: %s", gnutls_strerror(ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700667 ret = gnutls_certificate_set_x509_key_file(
668 global->xcred, params->client_cert,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800669 params->private_key, GNUTLS_X509_FMT_PEM);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700670 if (ret < 0) {
671 wpa_printf(MSG_DEBUG, "Failed to read client "
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800672 "cert/key in PEM format: %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700673 gnutls_strerror(ret));
674 goto fail;
675 }
676 }
677 } else if (params->private_key) {
678 int pkcs12_ok = 0;
679#ifdef PKCS12_FUNCS
680 /* Try to load in PKCS#12 format */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700681 ret = gnutls_certificate_set_x509_simple_pkcs12_file(
682 global->xcred, params->private_key,
683 GNUTLS_X509_FMT_DER, params->private_key_passwd);
684 if (ret != 0) {
685 wpa_printf(MSG_DEBUG, "Failed to load private_key in "
686 "PKCS#12 format: %s", gnutls_strerror(ret));
687 goto fail;
688 } else
689 pkcs12_ok = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700690#endif /* PKCS12_FUNCS */
691
692 if (!pkcs12_ok) {
693 wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
694 "included");
695 goto fail;
696 }
697 }
698
699 global->params_set = 1;
700
701 return 0;
702
703fail:
704 gnutls_certificate_free_credentials(global->xcred);
705 return -1;
706}
707
708
709int tls_global_set_verify(void *ssl_ctx, int check_crl)
710{
711 /* TODO */
712 return 0;
713}
714
715
716int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800717 int verify_peer, unsigned int flags,
718 const u8 *session_ctx, size_t session_ctx_len)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700719{
720 if (conn == NULL || conn->session == NULL)
721 return -1;
722
723 conn->verify_peer = verify_peer;
724 gnutls_certificate_server_set_request(conn->session,
725 verify_peer ? GNUTLS_CERT_REQUIRE
726 : GNUTLS_CERT_REQUEST);
727
728 return 0;
729}
730
731
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800732int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
733 struct tls_random *keys)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700734{
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800735#if GNUTLS_VERSION_NUMBER >= 0x030012
736 gnutls_datum_t client, server;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700737
738 if (conn == NULL || conn->session == NULL || keys == NULL)
739 return -1;
740
741 os_memset(keys, 0, sizeof(*keys));
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800742 gnutls_session_get_random(conn->session, &client, &server);
743 keys->client_random = client.data;
744 keys->server_random = server.data;
745 keys->client_random_len = client.size;
746 keys->server_random_len = client.size;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700747
748 return 0;
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800749#else /* 3.0.18 */
750 return -1;
751#endif /* 3.0.18 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700752}
753
754
755int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
756 const char *label, int server_random_first,
Dmitry Shmidtaf9da312015-04-03 10:03:11 -0700757 int skip_keyblock, u8 *out, size_t out_len)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700758{
Dmitry Shmidtaf9da312015-04-03 10:03:11 -0700759 if (conn == NULL || conn->session == NULL || skip_keyblock)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700760 return -1;
761
762 return gnutls_prf(conn->session, os_strlen(label), label,
763 server_random_first, 0, NULL, out_len, (char *) out);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700764}
765
766
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800767static void gnutls_tls_fail_event(struct tls_connection *conn,
768 const gnutls_datum_t *cert, int depth,
769 const char *subject, const char *err_str,
770 enum tls_fail_reason reason)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700771{
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800772 union tls_event_data ev;
773 struct tls_global *global = conn->global;
774 struct wpabuf *cert_buf = NULL;
775
776 if (global->event_cb == NULL)
777 return;
778
779 os_memset(&ev, 0, sizeof(ev));
780 ev.cert_fail.depth = depth;
781 ev.cert_fail.subject = subject ? subject : "";
782 ev.cert_fail.reason = reason;
783 ev.cert_fail.reason_txt = err_str;
784 if (cert) {
785 cert_buf = wpabuf_alloc_copy(cert->data, cert->size);
786 ev.cert_fail.cert = cert_buf;
787 }
788 global->event_cb(global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
789 wpabuf_free(cert_buf);
790}
791
792
793#if GNUTLS_VERSION_NUMBER < 0x030300
794static int server_eku_purpose(gnutls_x509_crt_t cert)
795{
796 unsigned int i;
797
798 for (i = 0; ; i++) {
799 char oid[128];
800 size_t oid_size = sizeof(oid);
801 int res;
802
803 res = gnutls_x509_crt_get_key_purpose_oid(cert, i, oid,
804 &oid_size, NULL);
805 if (res == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
806 if (i == 0) {
807 /* No EKU - assume any use allowed */
808 return 1;
809 }
810 break;
811 }
812
813 if (res < 0) {
814 wpa_printf(MSG_INFO, "GnuTLS: Failed to get EKU");
815 return 0;
816 }
817
818 wpa_printf(MSG_DEBUG, "GnuTLS: Certificate purpose: %s", oid);
819 if (os_strcmp(oid, GNUTLS_KP_TLS_WWW_SERVER) == 0 ||
820 os_strcmp(oid, GNUTLS_KP_ANY) == 0)
821 return 1;
822 }
823
824 return 0;
825}
826#endif /* < 3.3.0 */
827
828
829static int check_ocsp(struct tls_connection *conn, gnutls_session_t session,
830 gnutls_alert_description_t *err)
831{
832#if GNUTLS_VERSION_NUMBER >= 0x030103
833 gnutls_datum_t response, buf;
834 gnutls_ocsp_resp_t resp;
835 unsigned int cert_status;
836 int res;
837
838 if (!(conn->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)))
839 return 0;
840
841 if (!gnutls_ocsp_status_request_is_checked(session, 0)) {
842 if (conn->flags & TLS_CONN_REQUIRE_OCSP) {
843 wpa_printf(MSG_INFO,
844 "GnuTLS: No valid OCSP response received");
845 goto ocsp_error;
846 }
847
848 wpa_printf(MSG_DEBUG,
849 "GnuTLS: Valid OCSP response was not received - continue since OCSP was not required");
850 return 0;
851 }
852
853 /*
854 * GnuTLS has already verified the OCSP response in
855 * check_ocsp_response() and rejected handshake if the certificate was
856 * found to be revoked. However, if the response indicates that the
857 * status is unknown, handshake continues and reaches here. We need to
858 * re-import the OCSP response to check for unknown certificate status,
859 * but we do not need to repeat gnutls_ocsp_resp_check_crt() and
860 * gnutls_ocsp_resp_verify_direct() calls.
861 */
862
863 res = gnutls_ocsp_status_request_get(session, &response);
864 if (res != GNUTLS_E_SUCCESS) {
865 wpa_printf(MSG_INFO,
866 "GnuTLS: OCSP response was received, but it was not valid");
867 goto ocsp_error;
868 }
869
870 if (gnutls_ocsp_resp_init(&resp) != GNUTLS_E_SUCCESS)
871 goto ocsp_error;
872
873 res = gnutls_ocsp_resp_import(resp, &response);
874 if (res != GNUTLS_E_SUCCESS) {
875 wpa_printf(MSG_INFO,
876 "GnuTLS: Could not parse received OCSP response: %s",
877 gnutls_strerror(res));
878 gnutls_ocsp_resp_deinit(resp);
879 goto ocsp_error;
880 }
881
882 res = gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &buf);
883 if (res == GNUTLS_E_SUCCESS) {
884 wpa_printf(MSG_DEBUG, "GnuTLS: %s", buf.data);
885 gnutls_free(buf.data);
886 }
887
888 res = gnutls_ocsp_resp_get_single(resp, 0, NULL, NULL, NULL,
889 NULL, &cert_status, NULL,
890 NULL, NULL, NULL);
891 gnutls_ocsp_resp_deinit(resp);
892 if (res != GNUTLS_E_SUCCESS) {
893 wpa_printf(MSG_INFO,
894 "GnuTLS: Failed to extract OCSP information: %s",
895 gnutls_strerror(res));
896 goto ocsp_error;
897 }
898
899 if (cert_status == GNUTLS_OCSP_CERT_GOOD) {
900 wpa_printf(MSG_DEBUG, "GnuTLS: OCSP cert status: good");
901 } else if (cert_status == GNUTLS_OCSP_CERT_REVOKED) {
902 wpa_printf(MSG_DEBUG,
903 "GnuTLS: OCSP cert status: revoked");
904 goto ocsp_error;
905 } else {
906 wpa_printf(MSG_DEBUG,
907 "GnuTLS: OCSP cert status: unknown");
908 if (conn->flags & TLS_CONN_REQUIRE_OCSP)
909 goto ocsp_error;
910 wpa_printf(MSG_DEBUG,
911 "GnuTLS: OCSP was not required, so allow connection to continue");
912 }
913
914 return 0;
915
916ocsp_error:
917 gnutls_tls_fail_event(conn, NULL, 0, NULL,
918 "bad certificate status response",
919 TLS_FAIL_REVOKED);
920 *err = GNUTLS_A_CERTIFICATE_REVOKED;
921 return -1;
922#else /* GnuTLS 3.1.3 or newer */
923 return 0;
924#endif /* GnuTLS 3.1.3 or newer */
925}
926
927
928static int tls_connection_verify_peer(gnutls_session_t session)
929{
930 struct tls_connection *conn;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700931 unsigned int status, num_certs, i;
932 struct os_time now;
933 const gnutls_datum_t *certs;
934 gnutls_x509_crt_t cert;
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800935 gnutls_alert_description_t err;
936 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700937
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800938 conn = gnutls_session_get_ptr(session);
939 if (!conn->verify_peer) {
940 wpa_printf(MSG_DEBUG,
941 "GnuTLS: No peer certificate verification enabled");
942 return 0;
943 }
944
945 wpa_printf(MSG_DEBUG, "GnuTSL: Verifying peer certificate");
946
947#if GNUTLS_VERSION_NUMBER >= 0x030300
948 {
949 gnutls_typed_vdata_st data[1];
950 unsigned int elements = 0;
951
952 os_memset(data, 0, sizeof(data));
953 if (!conn->global->server) {
954 data[elements].type = GNUTLS_DT_KEY_PURPOSE_OID;
955 data[elements].data = (void *) GNUTLS_KP_TLS_WWW_SERVER;
956 elements++;
957 }
958 res = gnutls_certificate_verify_peers(session, data, 1,
959 &status);
960 }
961#else /* < 3.3.0 */
962 res = gnutls_certificate_verify_peers2(session, &status);
963#endif
964 if (res < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700965 wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
966 "certificate chain");
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800967 err = GNUTLS_A_INTERNAL_ERROR;
968 goto out;
969 }
970
971#if GNUTLS_VERSION_NUMBER >= 0x030104
972 {
973 gnutls_datum_t info;
974 int ret, type;
975
976 type = gnutls_certificate_type_get(session);
977 ret = gnutls_certificate_verification_status_print(status, type,
978 &info, 0);
979 if (ret < 0) {
980 wpa_printf(MSG_DEBUG,
981 "GnuTLS: Failed to print verification status");
982 err = GNUTLS_A_INTERNAL_ERROR;
983 goto out;
984 }
985 wpa_printf(MSG_DEBUG, "GnuTLS: %s", info.data);
986 gnutls_free(info.data);
987 }
988#endif /* GnuTLS 3.1.4 or newer */
989
990 certs = gnutls_certificate_get_peers(session, &num_certs);
991 if (certs == NULL || num_certs == 0) {
992 wpa_printf(MSG_INFO, "TLS: No peer certificate chain received");
993 err = GNUTLS_A_UNKNOWN_CA;
994 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700995 }
996
997 if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
998 wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
999 if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
1000 wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
1001 "algorithm");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001002 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1003 "certificate uses insecure algorithm",
1004 TLS_FAIL_BAD_CERTIFICATE);
1005 err = GNUTLS_A_INSUFFICIENT_SECURITY;
1006 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001007 }
1008 if (status & GNUTLS_CERT_NOT_ACTIVATED) {
1009 wpa_printf(MSG_INFO, "TLS: Certificate not yet "
1010 "activated");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001011 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1012 "certificate not yet valid",
1013 TLS_FAIL_NOT_YET_VALID);
1014 err = GNUTLS_A_CERTIFICATE_EXPIRED;
1015 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001016 }
1017 if (status & GNUTLS_CERT_EXPIRED) {
1018 wpa_printf(MSG_INFO, "TLS: Certificate expired");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001019 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1020 "certificate has expired",
1021 TLS_FAIL_EXPIRED);
1022 err = GNUTLS_A_CERTIFICATE_EXPIRED;
1023 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001024 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001025 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1026 "untrusted certificate",
1027 TLS_FAIL_UNTRUSTED);
1028 err = GNUTLS_A_INTERNAL_ERROR;
1029 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001030 }
1031
1032 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
1033 wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
1034 "known issuer");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001035 gnutls_tls_fail_event(conn, NULL, 0, NULL, "signed not found",
1036 TLS_FAIL_UNTRUSTED);
1037 err = GNUTLS_A_UNKNOWN_CA;
1038 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001039 }
1040
1041 if (status & GNUTLS_CERT_REVOKED) {
1042 wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001043 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1044 "certificate revoked",
1045 TLS_FAIL_REVOKED);
1046 err = GNUTLS_A_CERTIFICATE_REVOKED;
1047 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001048 }
1049
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001050 if (status != 0) {
1051 wpa_printf(MSG_INFO, "TLS: Unknown verification status: %d",
1052 status);
1053 err = GNUTLS_A_INTERNAL_ERROR;
1054 goto out;
1055 }
1056
1057 if (check_ocsp(conn, session, &err))
1058 goto out;
1059
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001060 os_get_time(&now);
1061
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001062 for (i = 0; i < num_certs; i++) {
1063 char *buf;
1064 size_t len;
1065 if (gnutls_x509_crt_init(&cert) < 0) {
1066 wpa_printf(MSG_INFO, "TLS: Certificate initialization "
1067 "failed");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001068 err = GNUTLS_A_BAD_CERTIFICATE;
1069 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001070 }
1071
1072 if (gnutls_x509_crt_import(cert, &certs[i],
1073 GNUTLS_X509_FMT_DER) < 0) {
1074 wpa_printf(MSG_INFO, "TLS: Could not parse peer "
1075 "certificate %d/%d", i + 1, num_certs);
1076 gnutls_x509_crt_deinit(cert);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001077 err = GNUTLS_A_BAD_CERTIFICATE;
1078 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001079 }
1080
1081 gnutls_x509_crt_get_dn(cert, NULL, &len);
1082 len++;
1083 buf = os_malloc(len + 1);
1084 if (buf) {
1085 buf[0] = buf[len] = '\0';
1086 gnutls_x509_crt_get_dn(cert, buf, &len);
1087 }
1088 wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
1089 i + 1, num_certs, buf);
1090
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001091 if (conn->global->event_cb) {
1092 struct wpabuf *cert_buf = NULL;
1093 union tls_event_data ev;
1094#ifdef CONFIG_SHA256
1095 u8 hash[32];
1096 const u8 *_addr[1];
1097 size_t _len[1];
1098#endif /* CONFIG_SHA256 */
1099
1100 os_memset(&ev, 0, sizeof(ev));
1101 if (conn->global->cert_in_cb) {
1102 cert_buf = wpabuf_alloc_copy(certs[i].data,
1103 certs[i].size);
1104 ev.peer_cert.cert = cert_buf;
1105 }
1106#ifdef CONFIG_SHA256
1107 _addr[0] = certs[i].data;
1108 _len[0] = certs[i].size;
1109 if (sha256_vector(1, _addr, _len, hash) == 0) {
1110 ev.peer_cert.hash = hash;
1111 ev.peer_cert.hash_len = sizeof(hash);
1112 }
1113#endif /* CONFIG_SHA256 */
1114 ev.peer_cert.depth = i;
1115 ev.peer_cert.subject = buf;
1116 conn->global->event_cb(conn->global->cb_ctx,
1117 TLS_PEER_CERTIFICATE, &ev);
1118 wpabuf_free(cert_buf);
1119 }
1120
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001121 if (i == 0) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001122 if (conn->suffix_match &&
1123 !gnutls_x509_crt_check_hostname(
1124 cert, conn->suffix_match)) {
1125 wpa_printf(MSG_WARNING,
1126 "TLS: Domain suffix match '%s' not found",
1127 conn->suffix_match);
1128 gnutls_tls_fail_event(
1129 conn, &certs[i], i, buf,
1130 "Domain suffix mismatch",
1131 TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
1132 err = GNUTLS_A_BAD_CERTIFICATE;
1133 gnutls_x509_crt_deinit(cert);
1134 os_free(buf);
1135 goto out;
1136 }
1137
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08001138#if GNUTLS_VERSION_NUMBER >= 0x030300
1139 if (conn->domain_match &&
1140 !gnutls_x509_crt_check_hostname2(
1141 cert, conn->domain_match,
1142 GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS)) {
1143 wpa_printf(MSG_WARNING,
1144 "TLS: Domain match '%s' not found",
1145 conn->domain_match);
1146 gnutls_tls_fail_event(
1147 conn, &certs[i], i, buf,
1148 "Domain mismatch",
1149 TLS_FAIL_DOMAIN_MISMATCH);
1150 err = GNUTLS_A_BAD_CERTIFICATE;
1151 gnutls_x509_crt_deinit(cert);
1152 os_free(buf);
1153 goto out;
1154 }
1155#endif /* >= 3.3.0 */
1156
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001157 /* TODO: validate altsubject_match.
1158 * For now, any such configuration is rejected in
1159 * tls_connection_set_params() */
1160
1161#if GNUTLS_VERSION_NUMBER < 0x030300
1162 /*
1163 * gnutls_certificate_verify_peers() not available, so
1164 * need to check EKU separately.
1165 */
1166 if (!conn->global->server &&
1167 !server_eku_purpose(cert)) {
1168 wpa_printf(MSG_WARNING,
1169 "GnuTLS: No server EKU");
1170 gnutls_tls_fail_event(
1171 conn, &certs[i], i, buf,
1172 "No server EKU",
1173 TLS_FAIL_BAD_CERTIFICATE);
1174 err = GNUTLS_A_BAD_CERTIFICATE;
1175 gnutls_x509_crt_deinit(cert);
1176 os_free(buf);
1177 goto out;
1178 }
1179#endif /* < 3.3.0 */
1180 }
1181
1182 if (!conn->disable_time_checks &&
1183 (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
1184 gnutls_x509_crt_get_activation_time(cert) > now.sec)) {
1185 wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
1186 "not valid at this time",
1187 i + 1, num_certs);
1188 gnutls_tls_fail_event(
1189 conn, &certs[i], i, buf,
1190 "Certificate is not valid at this time",
1191 TLS_FAIL_EXPIRED);
1192 gnutls_x509_crt_deinit(cert);
1193 os_free(buf);
1194 err = GNUTLS_A_CERTIFICATE_EXPIRED;
1195 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001196 }
1197
1198 os_free(buf);
1199
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001200 gnutls_x509_crt_deinit(cert);
1201 }
1202
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001203 if (conn->global->event_cb != NULL)
1204 conn->global->event_cb(conn->global->cb_ctx,
1205 TLS_CERT_CHAIN_SUCCESS, NULL);
1206
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001207 return 0;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001208
1209out:
1210 conn->failed++;
1211 gnutls_alert_send(session, GNUTLS_AL_FATAL, err);
1212 return GNUTLS_E_CERTIFICATE_ERROR;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001213}
1214
1215
1216static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn)
1217{
1218 int res;
1219 struct wpabuf *ad;
1220 wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data");
1221 ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3);
1222 if (ad == NULL)
1223 return NULL;
1224
1225 res = gnutls_record_recv(conn->session, wpabuf_mhead(ad),
1226 wpabuf_size(ad));
1227 wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res);
1228 if (res < 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001229 wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001230 "(%s)", __func__, (int) res,
1231 gnutls_strerror(res));
1232 wpabuf_free(ad);
1233 return NULL;
1234 }
1235
1236 wpabuf_put(ad, res);
1237 wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data",
1238 res);
1239 return ad;
1240}
1241
1242
1243struct wpabuf * tls_connection_handshake(void *tls_ctx,
1244 struct tls_connection *conn,
1245 const struct wpabuf *in_data,
1246 struct wpabuf **appl_data)
1247{
1248 struct tls_global *global = tls_ctx;
1249 struct wpabuf *out_data;
1250 int ret;
1251
1252 if (appl_data)
1253 *appl_data = NULL;
1254
1255 if (in_data && wpabuf_len(in_data) > 0) {
1256 if (conn->pull_buf) {
1257 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
1258 "pull_buf", __func__,
1259 (unsigned long) wpabuf_len(conn->pull_buf));
1260 wpabuf_free(conn->pull_buf);
1261 }
1262 conn->pull_buf = wpabuf_dup(in_data);
1263 if (conn->pull_buf == NULL)
1264 return NULL;
1265 conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
1266 }
1267
1268 ret = gnutls_handshake(conn->session);
1269 if (ret < 0) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001270 gnutls_alert_description_t alert;
1271
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001272 switch (ret) {
1273 case GNUTLS_E_AGAIN:
1274 if (global->server && conn->established &&
1275 conn->push_buf == NULL) {
1276 /* Need to return something to trigger
1277 * completion of EAP-TLS. */
1278 conn->push_buf = wpabuf_alloc(0);
1279 }
1280 break;
1281 case GNUTLS_E_FATAL_ALERT_RECEIVED:
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001282 alert = gnutls_alert_get(conn->session);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001283 wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001284 __func__, gnutls_alert_get_name(alert));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001285 conn->read_alerts++;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001286 if (conn->global->event_cb != NULL) {
1287 union tls_event_data ev;
1288
1289 os_memset(&ev, 0, sizeof(ev));
1290 ev.alert.is_local = 0;
1291 ev.alert.type = gnutls_alert_get_name(alert);
1292 ev.alert.description = ev.alert.type;
1293 conn->global->event_cb(conn->global->cb_ctx,
1294 TLS_ALERT, &ev);
1295 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001296 /* continue */
1297 default:
1298 wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
1299 "-> %s", __func__, gnutls_strerror(ret));
1300 conn->failed++;
1301 }
1302 } else {
1303 size_t size;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001304
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001305 wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001306
1307#if GNUTLS_VERSION_NUMBER >= 0x03010a
1308 {
1309 char *desc;
1310
1311 desc = gnutls_session_get_desc(conn->session);
1312 if (desc) {
1313 wpa_printf(MSG_DEBUG, "GnuTLS: %s", desc);
1314 gnutls_free(desc);
1315 }
1316 }
1317#endif /* GnuTLS 3.1.10 or newer */
1318
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001319 conn->established = 1;
1320 if (conn->push_buf == NULL) {
1321 /* Need to return something to get final TLS ACK. */
1322 conn->push_buf = wpabuf_alloc(0);
1323 }
1324
1325 gnutls_session_get_data(conn->session, NULL, &size);
1326 if (global->session_data == NULL ||
1327 global->session_data_size < size) {
1328 os_free(global->session_data);
1329 global->session_data = os_malloc(size);
1330 }
1331 if (global->session_data) {
1332 global->session_data_size = size;
1333 gnutls_session_get_data(conn->session,
1334 global->session_data,
1335 &global->session_data_size);
1336 }
1337
1338 if (conn->pull_buf && appl_data)
1339 *appl_data = gnutls_get_appl_data(conn);
1340 }
1341
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001342 out_data = conn->push_buf;
1343 conn->push_buf = NULL;
1344 return out_data;
1345}
1346
1347
1348struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
1349 struct tls_connection *conn,
1350 const struct wpabuf *in_data,
1351 struct wpabuf **appl_data)
1352{
1353 return tls_connection_handshake(tls_ctx, conn, in_data, appl_data);
1354}
1355
1356
1357struct wpabuf * tls_connection_encrypt(void *tls_ctx,
1358 struct tls_connection *conn,
1359 const struct wpabuf *in_data)
1360{
1361 ssize_t res;
1362 struct wpabuf *buf;
1363
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001364 res = gnutls_record_send(conn->session, wpabuf_head(in_data),
1365 wpabuf_len(in_data));
1366 if (res < 0) {
1367 wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
1368 __func__, gnutls_strerror(res));
1369 return NULL;
1370 }
1371
1372 buf = conn->push_buf;
1373 conn->push_buf = NULL;
1374 return buf;
1375}
1376
1377
1378struct wpabuf * tls_connection_decrypt(void *tls_ctx,
1379 struct tls_connection *conn,
1380 const struct wpabuf *in_data)
1381{
1382 ssize_t res;
1383 struct wpabuf *out;
1384
1385 if (conn->pull_buf) {
1386 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
1387 "pull_buf", __func__,
1388 (unsigned long) wpabuf_len(conn->pull_buf));
1389 wpabuf_free(conn->pull_buf);
1390 }
1391 conn->pull_buf = wpabuf_dup(in_data);
1392 if (conn->pull_buf == NULL)
1393 return NULL;
1394 conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
1395
1396 /*
1397 * Even though we try to disable TLS compression, it is possible that
1398 * this cannot be done with all TLS libraries. Add extra buffer space
1399 * to handle the possibility of the decrypted data being longer than
1400 * input data.
1401 */
1402 out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
1403 if (out == NULL)
1404 return NULL;
1405
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001406 res = gnutls_record_recv(conn->session, wpabuf_mhead(out),
1407 wpabuf_size(out));
1408 if (res < 0) {
1409 wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
1410 "(%s)", __func__, (int) res, gnutls_strerror(res));
1411 wpabuf_free(out);
1412 return NULL;
1413 }
1414 wpabuf_put(out, res);
1415
1416 return out;
1417}
1418
1419
1420int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
1421{
1422 if (conn == NULL)
1423 return 0;
1424 return gnutls_session_is_resumed(conn->session);
1425}
1426
1427
1428int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
1429 u8 *ciphers)
1430{
1431 /* TODO */
1432 return -1;
1433}
1434
1435
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001436int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
1437 char *buf, size_t buflen)
1438{
1439 /* TODO */
1440 return -1;
1441}
1442
1443
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001444int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
1445 char *buf, size_t buflen)
1446{
1447 /* TODO */
1448 buf[0] = '\0';
1449 return 0;
1450}
1451
1452
1453int tls_connection_enable_workaround(void *ssl_ctx,
1454 struct tls_connection *conn)
1455{
1456 gnutls_record_disable_padding(conn->session);
1457 return 0;
1458}
1459
1460
1461int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
1462 int ext_type, const u8 *data,
1463 size_t data_len)
1464{
1465 /* TODO */
1466 return -1;
1467}
1468
1469
1470int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
1471{
1472 if (conn == NULL)
1473 return -1;
1474 return conn->failed;
1475}
1476
1477
1478int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
1479{
1480 if (conn == NULL)
1481 return -1;
1482 return conn->read_alerts;
1483}
1484
1485
1486int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
1487{
1488 if (conn == NULL)
1489 return -1;
1490 return conn->write_alerts;
1491}
1492
1493
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001494int tls_connection_set_session_ticket_cb(void *tls_ctx,
1495 struct tls_connection *conn,
1496 tls_session_ticket_cb cb, void *ctx)
1497{
1498 return -1;
1499}
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001500
1501
1502int tls_get_library_version(char *buf, size_t buf_len)
1503{
1504 return os_snprintf(buf, buf_len, "GnuTLS build=%s run=%s",
1505 GNUTLS_VERSION, gnutls_check_version(NULL));
1506}
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001507
1508
1509void tls_connection_set_success_data(struct tls_connection *conn,
1510 struct wpabuf *data)
1511{
1512}
1513
1514
1515void tls_connection_set_success_data_resumed(struct tls_connection *conn)
1516{
1517}
1518
1519
1520const struct wpabuf *
1521tls_connection_get_success_data(struct tls_connection *conn)
1522{
1523 return NULL;
1524}
1525
1526
1527void tls_connection_remove_session(struct tls_connection *conn)
1528{
1529}