blob: f994379b16b22a07596626ee65626711b4624d02 [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 Shmidt8d520ff2011-05-09 14:06:53 -0700350 if (params->subject_match) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800351 wpa_printf(MSG_INFO, "GnuTLS: subject_match not supported");
352 return -1;
353 }
354
355 if (params->altsubject_match) {
356 wpa_printf(MSG_INFO, "GnuTLS: altsubject_match not supported");
357 return -1;
358 }
359
360 os_free(conn->suffix_match);
361 conn->suffix_match = NULL;
362 if (params->suffix_match) {
363 conn->suffix_match = os_strdup(params->suffix_match);
364 if (conn->suffix_match == NULL)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700365 return -1;
366 }
367
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800368#if GNUTLS_VERSION_NUMBER >= 0x030300
369 os_free(conn->domain_match);
370 conn->domain_match = NULL;
371 if (params->domain_match) {
372 conn->domain_match = os_strdup(params->domain_match);
373 if (conn->domain_match == NULL)
374 return -1;
375 }
376#else /* < 3.3.0 */
377 if (params->domain_match) {
378 wpa_printf(MSG_INFO, "GnuTLS: domain_match not supported");
379 return -1;
380 }
381#endif /* >= 3.3.0 */
382
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800383 conn->flags = params->flags;
384
385 if (params->openssl_ciphers) {
386 wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
387 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700388 }
389
390 /* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
391 * to force peer validation(?) */
392
393 if (params->ca_cert) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800394 wpa_printf(MSG_DEBUG, "GnuTLS: Try to parse %s in DER format",
395 params->ca_cert);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700396 ret = gnutls_certificate_set_x509_trust_file(
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800397 conn->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700398 if (ret < 0) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800399 wpa_printf(MSG_DEBUG,
400 "GnuTLS: Failed to read CA cert '%s' in DER format (%s) - try in PEM format",
401 params->ca_cert,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700402 gnutls_strerror(ret));
403 ret = gnutls_certificate_set_x509_trust_file(
404 conn->xcred, params->ca_cert,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800405 GNUTLS_X509_FMT_PEM);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700406 if (ret < 0) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800407 wpa_printf(MSG_DEBUG,
408 "Failed to read CA cert '%s' in PEM format: %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700409 params->ca_cert,
410 gnutls_strerror(ret));
411 return -1;
412 }
413 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800414 } else if (params->ca_cert_blob) {
415 gnutls_datum_t ca;
416
417 ca.data = (unsigned char *) params->ca_cert_blob;
418 ca.size = params->ca_cert_blob_len;
419
420 ret = gnutls_certificate_set_x509_trust_mem(
421 conn->xcred, &ca, GNUTLS_X509_FMT_DER);
422 if (ret < 0) {
423 wpa_printf(MSG_DEBUG,
424 "Failed to parse CA cert in DER format: %s",
425 gnutls_strerror(ret));
426 ret = gnutls_certificate_set_x509_trust_mem(
427 conn->xcred, &ca, GNUTLS_X509_FMT_PEM);
428 if (ret < 0) {
429 wpa_printf(MSG_DEBUG,
430 "Failed to parse CA cert in PEM format: %s",
431 gnutls_strerror(ret));
432 return -1;
433 }
434 }
435 } else if (params->ca_path) {
436 wpa_printf(MSG_INFO, "GnuTLS: ca_path not supported");
437 return -1;
438 }
439
440 conn->disable_time_checks = 0;
441 if (params->ca_cert || params->ca_cert_blob) {
442 conn->verify_peer = 1;
443 gnutls_certificate_set_verify_function(
444 conn->xcred, tls_connection_verify_peer);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700445
446 if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
447 gnutls_certificate_set_verify_flags(
448 conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
449 }
450
451 if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800452 conn->disable_time_checks = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700453 gnutls_certificate_set_verify_flags(
454 conn->xcred,
455 GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
456 }
457 }
458
459 if (params->client_cert && params->private_key) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800460#if GNUTLS_VERSION_NUMBER >= 0x03010b
461 ret = gnutls_certificate_set_x509_key_file2(
462 conn->xcred, params->client_cert, params->private_key,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800463 GNUTLS_X509_FMT_DER, params->private_key_passwd, 0);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800464#else
465 /* private_key_passwd not (easily) supported here */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700466 ret = gnutls_certificate_set_x509_key_file(
467 conn->xcred, params->client_cert, params->private_key,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800468 GNUTLS_X509_FMT_DER);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800469#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700470 if (ret < 0) {
471 wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800472 "in DER format: %s", gnutls_strerror(ret));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800473#if GNUTLS_VERSION_NUMBER >= 0x03010b
474 ret = gnutls_certificate_set_x509_key_file2(
475 conn->xcred, params->client_cert,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800476 params->private_key, GNUTLS_X509_FMT_PEM,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800477 params->private_key_passwd, 0);
478#else
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700479 ret = gnutls_certificate_set_x509_key_file(
480 conn->xcred, params->client_cert,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800481 params->private_key, GNUTLS_X509_FMT_PEM);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800482#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700483 if (ret < 0) {
484 wpa_printf(MSG_DEBUG, "Failed to read client "
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800485 "cert/key in PEM format: %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700486 gnutls_strerror(ret));
487 return ret;
488 }
489 }
490 } else if (params->private_key) {
491 int pkcs12_ok = 0;
492#ifdef PKCS12_FUNCS
493 /* Try to load in PKCS#12 format */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700494 ret = gnutls_certificate_set_x509_simple_pkcs12_file(
495 conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
496 params->private_key_passwd);
497 if (ret != 0) {
498 wpa_printf(MSG_DEBUG, "Failed to load private_key in "
499 "PKCS#12 format: %s", gnutls_strerror(ret));
500 return -1;
501 } else
502 pkcs12_ok = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700503#endif /* PKCS12_FUNCS */
504
505 if (!pkcs12_ok) {
506 wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
507 "included");
508 return -1;
509 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800510 } else if (params->client_cert_blob && params->private_key_blob) {
511 gnutls_datum_t cert, key;
512
513 cert.data = (unsigned char *) params->client_cert_blob;
514 cert.size = params->client_cert_blob_len;
515 key.data = (unsigned char *) params->private_key_blob;
516 key.size = params->private_key_blob_len;
517
518#if GNUTLS_VERSION_NUMBER >= 0x03010b
519 ret = gnutls_certificate_set_x509_key_mem2(
520 conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER,
521 params->private_key_passwd, 0);
522#else
523 /* private_key_passwd not (easily) supported here */
524 ret = gnutls_certificate_set_x509_key_mem(
525 conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER);
526#endif
527 if (ret < 0) {
528 wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
529 "in DER format: %s", gnutls_strerror(ret));
530#if GNUTLS_VERSION_NUMBER >= 0x03010b
531 ret = gnutls_certificate_set_x509_key_mem2(
532 conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM,
533 params->private_key_passwd, 0);
534#else
535 /* private_key_passwd not (easily) supported here */
536 ret = gnutls_certificate_set_x509_key_mem(
537 conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM);
538#endif
539 if (ret < 0) {
540 wpa_printf(MSG_DEBUG, "Failed to read client "
541 "cert/key in PEM format: %s",
542 gnutls_strerror(ret));
543 return ret;
544 }
545 }
546 } else if (params->private_key_blob) {
547#ifdef PKCS12_FUNCS
548 gnutls_datum_t key;
549
550 key.data = (unsigned char *) params->private_key_blob;
551 key.size = params->private_key_blob_len;
552
553 /* Try to load in PKCS#12 format */
554 ret = gnutls_certificate_set_x509_simple_pkcs12_mem(
555 conn->xcred, &key, GNUTLS_X509_FMT_DER,
556 params->private_key_passwd);
557 if (ret != 0) {
558 wpa_printf(MSG_DEBUG, "Failed to load private_key in "
559 "PKCS#12 format: %s", gnutls_strerror(ret));
560 return -1;
561 }
562#else /* PKCS12_FUNCS */
563 wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not included");
564 return -1;
565#endif /* PKCS12_FUNCS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700566 }
567
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800568#if GNUTLS_VERSION_NUMBER >= 0x030103
569 if (params->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)) {
570 ret = gnutls_ocsp_status_request_enable_client(conn->session,
571 NULL, 0, NULL);
572 if (ret != GNUTLS_E_SUCCESS) {
573 wpa_printf(MSG_INFO,
574 "GnuTLS: Failed to enable OCSP client");
575 return -1;
576 }
577 }
578#else /* 3.1.3 */
579 if (params->flags & TLS_CONN_REQUIRE_OCSP) {
580 wpa_printf(MSG_INFO,
581 "GnuTLS: OCSP not supported by this version of GnuTLS");
582 return -1;
583 }
584#endif /* 3.1.3 */
585
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700586 conn->params_set = 1;
587
588 ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
589 conn->xcred);
590 if (ret < 0) {
591 wpa_printf(MSG_INFO, "Failed to configure credentials: %s",
592 gnutls_strerror(ret));
593 }
594
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700595 return ret;
596}
597
598
599int tls_global_set_params(void *tls_ctx,
600 const struct tls_connection_params *params)
601{
602 struct tls_global *global = tls_ctx;
603 int ret;
604
605 /* Currently, global parameters are only set when running in server
606 * mode. */
607 global->server = 1;
608
609 if (global->params_set) {
610 gnutls_certificate_free_credentials(global->xcred);
611 global->params_set = 0;
612 }
613
614 ret = gnutls_certificate_allocate_credentials(&global->xcred);
615 if (ret) {
616 wpa_printf(MSG_DEBUG, "Failed to allocate global credentials "
617 "%s", gnutls_strerror(ret));
618 return -1;
619 }
620
621 if (params->ca_cert) {
622 ret = gnutls_certificate_set_x509_trust_file(
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800623 global->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700624 if (ret < 0) {
625 wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800626 "in DER format: %s", params->ca_cert,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700627 gnutls_strerror(ret));
628 ret = gnutls_certificate_set_x509_trust_file(
629 global->xcred, params->ca_cert,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800630 GNUTLS_X509_FMT_PEM);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700631 if (ret < 0) {
632 wpa_printf(MSG_DEBUG, "Failed to read CA cert "
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800633 "'%s' in PEM format: %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700634 params->ca_cert,
635 gnutls_strerror(ret));
636 goto fail;
637 }
638 }
639
640 if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
641 gnutls_certificate_set_verify_flags(
642 global->xcred,
643 GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
644 }
645
646 if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
647 gnutls_certificate_set_verify_flags(
648 global->xcred,
649 GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
650 }
651 }
652
653 if (params->client_cert && params->private_key) {
654 /* TODO: private_key_passwd? */
655 ret = gnutls_certificate_set_x509_key_file(
656 global->xcred, params->client_cert,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800657 params->private_key, GNUTLS_X509_FMT_DER);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700658 if (ret < 0) {
659 wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800660 "in DER format: %s", gnutls_strerror(ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700661 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_PEM);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700664 if (ret < 0) {
665 wpa_printf(MSG_DEBUG, "Failed to read client "
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800666 "cert/key in PEM format: %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700667 gnutls_strerror(ret));
668 goto fail;
669 }
670 }
671 } else if (params->private_key) {
672 int pkcs12_ok = 0;
673#ifdef PKCS12_FUNCS
674 /* Try to load in PKCS#12 format */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700675 ret = gnutls_certificate_set_x509_simple_pkcs12_file(
676 global->xcred, params->private_key,
677 GNUTLS_X509_FMT_DER, params->private_key_passwd);
678 if (ret != 0) {
679 wpa_printf(MSG_DEBUG, "Failed to load private_key in "
680 "PKCS#12 format: %s", gnutls_strerror(ret));
681 goto fail;
682 } else
683 pkcs12_ok = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700684#endif /* PKCS12_FUNCS */
685
686 if (!pkcs12_ok) {
687 wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
688 "included");
689 goto fail;
690 }
691 }
692
693 global->params_set = 1;
694
695 return 0;
696
697fail:
698 gnutls_certificate_free_credentials(global->xcred);
699 return -1;
700}
701
702
703int tls_global_set_verify(void *ssl_ctx, int check_crl)
704{
705 /* TODO */
706 return 0;
707}
708
709
710int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800711 int verify_peer, unsigned int flags,
712 const u8 *session_ctx, size_t session_ctx_len)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700713{
714 if (conn == NULL || conn->session == NULL)
715 return -1;
716
717 conn->verify_peer = verify_peer;
718 gnutls_certificate_server_set_request(conn->session,
719 verify_peer ? GNUTLS_CERT_REQUIRE
720 : GNUTLS_CERT_REQUEST);
721
722 return 0;
723}
724
725
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800726int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
727 struct tls_random *keys)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700728{
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800729#if GNUTLS_VERSION_NUMBER >= 0x030012
730 gnutls_datum_t client, server;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700731
732 if (conn == NULL || conn->session == NULL || keys == NULL)
733 return -1;
734
735 os_memset(keys, 0, sizeof(*keys));
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800736 gnutls_session_get_random(conn->session, &client, &server);
737 keys->client_random = client.data;
738 keys->server_random = server.data;
739 keys->client_random_len = client.size;
740 keys->server_random_len = client.size;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700741
742 return 0;
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800743#else /* 3.0.18 */
744 return -1;
745#endif /* 3.0.18 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700746}
747
748
749int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
750 const char *label, int server_random_first,
Dmitry Shmidtaf9da312015-04-03 10:03:11 -0700751 int skip_keyblock, u8 *out, size_t out_len)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700752{
Dmitry Shmidtaf9da312015-04-03 10:03:11 -0700753 if (conn == NULL || conn->session == NULL || skip_keyblock)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700754 return -1;
755
756 return gnutls_prf(conn->session, os_strlen(label), label,
757 server_random_first, 0, NULL, out_len, (char *) out);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700758}
759
760
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800761static void gnutls_tls_fail_event(struct tls_connection *conn,
762 const gnutls_datum_t *cert, int depth,
763 const char *subject, const char *err_str,
764 enum tls_fail_reason reason)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700765{
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800766 union tls_event_data ev;
767 struct tls_global *global = conn->global;
768 struct wpabuf *cert_buf = NULL;
769
770 if (global->event_cb == NULL)
771 return;
772
773 os_memset(&ev, 0, sizeof(ev));
774 ev.cert_fail.depth = depth;
775 ev.cert_fail.subject = subject ? subject : "";
776 ev.cert_fail.reason = reason;
777 ev.cert_fail.reason_txt = err_str;
778 if (cert) {
779 cert_buf = wpabuf_alloc_copy(cert->data, cert->size);
780 ev.cert_fail.cert = cert_buf;
781 }
782 global->event_cb(global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
783 wpabuf_free(cert_buf);
784}
785
786
787#if GNUTLS_VERSION_NUMBER < 0x030300
788static int server_eku_purpose(gnutls_x509_crt_t cert)
789{
790 unsigned int i;
791
792 for (i = 0; ; i++) {
793 char oid[128];
794 size_t oid_size = sizeof(oid);
795 int res;
796
797 res = gnutls_x509_crt_get_key_purpose_oid(cert, i, oid,
798 &oid_size, NULL);
799 if (res == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
800 if (i == 0) {
801 /* No EKU - assume any use allowed */
802 return 1;
803 }
804 break;
805 }
806
807 if (res < 0) {
808 wpa_printf(MSG_INFO, "GnuTLS: Failed to get EKU");
809 return 0;
810 }
811
812 wpa_printf(MSG_DEBUG, "GnuTLS: Certificate purpose: %s", oid);
813 if (os_strcmp(oid, GNUTLS_KP_TLS_WWW_SERVER) == 0 ||
814 os_strcmp(oid, GNUTLS_KP_ANY) == 0)
815 return 1;
816 }
817
818 return 0;
819}
820#endif /* < 3.3.0 */
821
822
823static int check_ocsp(struct tls_connection *conn, gnutls_session_t session,
824 gnutls_alert_description_t *err)
825{
826#if GNUTLS_VERSION_NUMBER >= 0x030103
827 gnutls_datum_t response, buf;
828 gnutls_ocsp_resp_t resp;
829 unsigned int cert_status;
830 int res;
831
832 if (!(conn->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)))
833 return 0;
834
835 if (!gnutls_ocsp_status_request_is_checked(session, 0)) {
836 if (conn->flags & TLS_CONN_REQUIRE_OCSP) {
837 wpa_printf(MSG_INFO,
838 "GnuTLS: No valid OCSP response received");
839 goto ocsp_error;
840 }
841
842 wpa_printf(MSG_DEBUG,
843 "GnuTLS: Valid OCSP response was not received - continue since OCSP was not required");
844 return 0;
845 }
846
847 /*
848 * GnuTLS has already verified the OCSP response in
849 * check_ocsp_response() and rejected handshake if the certificate was
850 * found to be revoked. However, if the response indicates that the
851 * status is unknown, handshake continues and reaches here. We need to
852 * re-import the OCSP response to check for unknown certificate status,
853 * but we do not need to repeat gnutls_ocsp_resp_check_crt() and
854 * gnutls_ocsp_resp_verify_direct() calls.
855 */
856
857 res = gnutls_ocsp_status_request_get(session, &response);
858 if (res != GNUTLS_E_SUCCESS) {
859 wpa_printf(MSG_INFO,
860 "GnuTLS: OCSP response was received, but it was not valid");
861 goto ocsp_error;
862 }
863
864 if (gnutls_ocsp_resp_init(&resp) != GNUTLS_E_SUCCESS)
865 goto ocsp_error;
866
867 res = gnutls_ocsp_resp_import(resp, &response);
868 if (res != GNUTLS_E_SUCCESS) {
869 wpa_printf(MSG_INFO,
870 "GnuTLS: Could not parse received OCSP response: %s",
871 gnutls_strerror(res));
872 gnutls_ocsp_resp_deinit(resp);
873 goto ocsp_error;
874 }
875
876 res = gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &buf);
877 if (res == GNUTLS_E_SUCCESS) {
878 wpa_printf(MSG_DEBUG, "GnuTLS: %s", buf.data);
879 gnutls_free(buf.data);
880 }
881
882 res = gnutls_ocsp_resp_get_single(resp, 0, NULL, NULL, NULL,
883 NULL, &cert_status, NULL,
884 NULL, NULL, NULL);
885 gnutls_ocsp_resp_deinit(resp);
886 if (res != GNUTLS_E_SUCCESS) {
887 wpa_printf(MSG_INFO,
888 "GnuTLS: Failed to extract OCSP information: %s",
889 gnutls_strerror(res));
890 goto ocsp_error;
891 }
892
893 if (cert_status == GNUTLS_OCSP_CERT_GOOD) {
894 wpa_printf(MSG_DEBUG, "GnuTLS: OCSP cert status: good");
895 } else if (cert_status == GNUTLS_OCSP_CERT_REVOKED) {
896 wpa_printf(MSG_DEBUG,
897 "GnuTLS: OCSP cert status: revoked");
898 goto ocsp_error;
899 } else {
900 wpa_printf(MSG_DEBUG,
901 "GnuTLS: OCSP cert status: unknown");
902 if (conn->flags & TLS_CONN_REQUIRE_OCSP)
903 goto ocsp_error;
904 wpa_printf(MSG_DEBUG,
905 "GnuTLS: OCSP was not required, so allow connection to continue");
906 }
907
908 return 0;
909
910ocsp_error:
911 gnutls_tls_fail_event(conn, NULL, 0, NULL,
912 "bad certificate status response",
913 TLS_FAIL_REVOKED);
914 *err = GNUTLS_A_CERTIFICATE_REVOKED;
915 return -1;
916#else /* GnuTLS 3.1.3 or newer */
917 return 0;
918#endif /* GnuTLS 3.1.3 or newer */
919}
920
921
922static int tls_connection_verify_peer(gnutls_session_t session)
923{
924 struct tls_connection *conn;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700925 unsigned int status, num_certs, i;
926 struct os_time now;
927 const gnutls_datum_t *certs;
928 gnutls_x509_crt_t cert;
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800929 gnutls_alert_description_t err;
930 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700931
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800932 conn = gnutls_session_get_ptr(session);
933 if (!conn->verify_peer) {
934 wpa_printf(MSG_DEBUG,
935 "GnuTLS: No peer certificate verification enabled");
936 return 0;
937 }
938
939 wpa_printf(MSG_DEBUG, "GnuTSL: Verifying peer certificate");
940
941#if GNUTLS_VERSION_NUMBER >= 0x030300
942 {
943 gnutls_typed_vdata_st data[1];
944 unsigned int elements = 0;
945
946 os_memset(data, 0, sizeof(data));
947 if (!conn->global->server) {
948 data[elements].type = GNUTLS_DT_KEY_PURPOSE_OID;
949 data[elements].data = (void *) GNUTLS_KP_TLS_WWW_SERVER;
950 elements++;
951 }
952 res = gnutls_certificate_verify_peers(session, data, 1,
953 &status);
954 }
955#else /* < 3.3.0 */
956 res = gnutls_certificate_verify_peers2(session, &status);
957#endif
958 if (res < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700959 wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
960 "certificate chain");
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800961 err = GNUTLS_A_INTERNAL_ERROR;
962 goto out;
963 }
964
965#if GNUTLS_VERSION_NUMBER >= 0x030104
966 {
967 gnutls_datum_t info;
968 int ret, type;
969
970 type = gnutls_certificate_type_get(session);
971 ret = gnutls_certificate_verification_status_print(status, type,
972 &info, 0);
973 if (ret < 0) {
974 wpa_printf(MSG_DEBUG,
975 "GnuTLS: Failed to print verification status");
976 err = GNUTLS_A_INTERNAL_ERROR;
977 goto out;
978 }
979 wpa_printf(MSG_DEBUG, "GnuTLS: %s", info.data);
980 gnutls_free(info.data);
981 }
982#endif /* GnuTLS 3.1.4 or newer */
983
984 certs = gnutls_certificate_get_peers(session, &num_certs);
985 if (certs == NULL || num_certs == 0) {
986 wpa_printf(MSG_INFO, "TLS: No peer certificate chain received");
987 err = GNUTLS_A_UNKNOWN_CA;
988 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700989 }
990
991 if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
992 wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
993 if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
994 wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
995 "algorithm");
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800996 gnutls_tls_fail_event(conn, NULL, 0, NULL,
997 "certificate uses insecure algorithm",
998 TLS_FAIL_BAD_CERTIFICATE);
999 err = GNUTLS_A_INSUFFICIENT_SECURITY;
1000 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001001 }
1002 if (status & GNUTLS_CERT_NOT_ACTIVATED) {
1003 wpa_printf(MSG_INFO, "TLS: Certificate not yet "
1004 "activated");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001005 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1006 "certificate not yet valid",
1007 TLS_FAIL_NOT_YET_VALID);
1008 err = GNUTLS_A_CERTIFICATE_EXPIRED;
1009 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001010 }
1011 if (status & GNUTLS_CERT_EXPIRED) {
1012 wpa_printf(MSG_INFO, "TLS: Certificate expired");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001013 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1014 "certificate has expired",
1015 TLS_FAIL_EXPIRED);
1016 err = GNUTLS_A_CERTIFICATE_EXPIRED;
1017 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001018 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001019 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1020 "untrusted certificate",
1021 TLS_FAIL_UNTRUSTED);
1022 err = GNUTLS_A_INTERNAL_ERROR;
1023 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001024 }
1025
1026 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
1027 wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
1028 "known issuer");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001029 gnutls_tls_fail_event(conn, NULL, 0, NULL, "signed not found",
1030 TLS_FAIL_UNTRUSTED);
1031 err = GNUTLS_A_UNKNOWN_CA;
1032 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001033 }
1034
1035 if (status & GNUTLS_CERT_REVOKED) {
1036 wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001037 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1038 "certificate revoked",
1039 TLS_FAIL_REVOKED);
1040 err = GNUTLS_A_CERTIFICATE_REVOKED;
1041 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001042 }
1043
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001044 if (status != 0) {
1045 wpa_printf(MSG_INFO, "TLS: Unknown verification status: %d",
1046 status);
1047 err = GNUTLS_A_INTERNAL_ERROR;
1048 goto out;
1049 }
1050
1051 if (check_ocsp(conn, session, &err))
1052 goto out;
1053
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001054 os_get_time(&now);
1055
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001056 for (i = 0; i < num_certs; i++) {
1057 char *buf;
1058 size_t len;
1059 if (gnutls_x509_crt_init(&cert) < 0) {
1060 wpa_printf(MSG_INFO, "TLS: Certificate initialization "
1061 "failed");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001062 err = GNUTLS_A_BAD_CERTIFICATE;
1063 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001064 }
1065
1066 if (gnutls_x509_crt_import(cert, &certs[i],
1067 GNUTLS_X509_FMT_DER) < 0) {
1068 wpa_printf(MSG_INFO, "TLS: Could not parse peer "
1069 "certificate %d/%d", i + 1, num_certs);
1070 gnutls_x509_crt_deinit(cert);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001071 err = GNUTLS_A_BAD_CERTIFICATE;
1072 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001073 }
1074
1075 gnutls_x509_crt_get_dn(cert, NULL, &len);
1076 len++;
1077 buf = os_malloc(len + 1);
1078 if (buf) {
1079 buf[0] = buf[len] = '\0';
1080 gnutls_x509_crt_get_dn(cert, buf, &len);
1081 }
1082 wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
1083 i + 1, num_certs, buf);
1084
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001085 if (conn->global->event_cb) {
1086 struct wpabuf *cert_buf = NULL;
1087 union tls_event_data ev;
1088#ifdef CONFIG_SHA256
1089 u8 hash[32];
1090 const u8 *_addr[1];
1091 size_t _len[1];
1092#endif /* CONFIG_SHA256 */
1093
1094 os_memset(&ev, 0, sizeof(ev));
1095 if (conn->global->cert_in_cb) {
1096 cert_buf = wpabuf_alloc_copy(certs[i].data,
1097 certs[i].size);
1098 ev.peer_cert.cert = cert_buf;
1099 }
1100#ifdef CONFIG_SHA256
1101 _addr[0] = certs[i].data;
1102 _len[0] = certs[i].size;
1103 if (sha256_vector(1, _addr, _len, hash) == 0) {
1104 ev.peer_cert.hash = hash;
1105 ev.peer_cert.hash_len = sizeof(hash);
1106 }
1107#endif /* CONFIG_SHA256 */
1108 ev.peer_cert.depth = i;
1109 ev.peer_cert.subject = buf;
1110 conn->global->event_cb(conn->global->cb_ctx,
1111 TLS_PEER_CERTIFICATE, &ev);
1112 wpabuf_free(cert_buf);
1113 }
1114
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001115 if (i == 0) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001116 if (conn->suffix_match &&
1117 !gnutls_x509_crt_check_hostname(
1118 cert, conn->suffix_match)) {
1119 wpa_printf(MSG_WARNING,
1120 "TLS: Domain suffix match '%s' not found",
1121 conn->suffix_match);
1122 gnutls_tls_fail_event(
1123 conn, &certs[i], i, buf,
1124 "Domain suffix mismatch",
1125 TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
1126 err = GNUTLS_A_BAD_CERTIFICATE;
1127 gnutls_x509_crt_deinit(cert);
1128 os_free(buf);
1129 goto out;
1130 }
1131
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08001132#if GNUTLS_VERSION_NUMBER >= 0x030300
1133 if (conn->domain_match &&
1134 !gnutls_x509_crt_check_hostname2(
1135 cert, conn->domain_match,
1136 GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS)) {
1137 wpa_printf(MSG_WARNING,
1138 "TLS: Domain match '%s' not found",
1139 conn->domain_match);
1140 gnutls_tls_fail_event(
1141 conn, &certs[i], i, buf,
1142 "Domain mismatch",
1143 TLS_FAIL_DOMAIN_MISMATCH);
1144 err = GNUTLS_A_BAD_CERTIFICATE;
1145 gnutls_x509_crt_deinit(cert);
1146 os_free(buf);
1147 goto out;
1148 }
1149#endif /* >= 3.3.0 */
1150
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001151 /* TODO: validate altsubject_match.
1152 * For now, any such configuration is rejected in
1153 * tls_connection_set_params() */
1154
1155#if GNUTLS_VERSION_NUMBER < 0x030300
1156 /*
1157 * gnutls_certificate_verify_peers() not available, so
1158 * need to check EKU separately.
1159 */
1160 if (!conn->global->server &&
1161 !server_eku_purpose(cert)) {
1162 wpa_printf(MSG_WARNING,
1163 "GnuTLS: No server EKU");
1164 gnutls_tls_fail_event(
1165 conn, &certs[i], i, buf,
1166 "No server EKU",
1167 TLS_FAIL_BAD_CERTIFICATE);
1168 err = GNUTLS_A_BAD_CERTIFICATE;
1169 gnutls_x509_crt_deinit(cert);
1170 os_free(buf);
1171 goto out;
1172 }
1173#endif /* < 3.3.0 */
1174 }
1175
1176 if (!conn->disable_time_checks &&
1177 (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
1178 gnutls_x509_crt_get_activation_time(cert) > now.sec)) {
1179 wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
1180 "not valid at this time",
1181 i + 1, num_certs);
1182 gnutls_tls_fail_event(
1183 conn, &certs[i], i, buf,
1184 "Certificate is not valid at this time",
1185 TLS_FAIL_EXPIRED);
1186 gnutls_x509_crt_deinit(cert);
1187 os_free(buf);
1188 err = GNUTLS_A_CERTIFICATE_EXPIRED;
1189 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001190 }
1191
1192 os_free(buf);
1193
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001194 gnutls_x509_crt_deinit(cert);
1195 }
1196
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001197 if (conn->global->event_cb != NULL)
1198 conn->global->event_cb(conn->global->cb_ctx,
1199 TLS_CERT_CHAIN_SUCCESS, NULL);
1200
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001201 return 0;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001202
1203out:
1204 conn->failed++;
1205 gnutls_alert_send(session, GNUTLS_AL_FATAL, err);
1206 return GNUTLS_E_CERTIFICATE_ERROR;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001207}
1208
1209
1210static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn)
1211{
1212 int res;
1213 struct wpabuf *ad;
1214 wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data");
1215 ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3);
1216 if (ad == NULL)
1217 return NULL;
1218
1219 res = gnutls_record_recv(conn->session, wpabuf_mhead(ad),
1220 wpabuf_size(ad));
1221 wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res);
1222 if (res < 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001223 wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001224 "(%s)", __func__, (int) res,
1225 gnutls_strerror(res));
1226 wpabuf_free(ad);
1227 return NULL;
1228 }
1229
1230 wpabuf_put(ad, res);
1231 wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data",
1232 res);
1233 return ad;
1234}
1235
1236
1237struct wpabuf * tls_connection_handshake(void *tls_ctx,
1238 struct tls_connection *conn,
1239 const struct wpabuf *in_data,
1240 struct wpabuf **appl_data)
1241{
1242 struct tls_global *global = tls_ctx;
1243 struct wpabuf *out_data;
1244 int ret;
1245
1246 if (appl_data)
1247 *appl_data = NULL;
1248
1249 if (in_data && wpabuf_len(in_data) > 0) {
1250 if (conn->pull_buf) {
1251 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
1252 "pull_buf", __func__,
1253 (unsigned long) wpabuf_len(conn->pull_buf));
1254 wpabuf_free(conn->pull_buf);
1255 }
1256 conn->pull_buf = wpabuf_dup(in_data);
1257 if (conn->pull_buf == NULL)
1258 return NULL;
1259 conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
1260 }
1261
1262 ret = gnutls_handshake(conn->session);
1263 if (ret < 0) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001264 gnutls_alert_description_t alert;
1265
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001266 switch (ret) {
1267 case GNUTLS_E_AGAIN:
1268 if (global->server && conn->established &&
1269 conn->push_buf == NULL) {
1270 /* Need to return something to trigger
1271 * completion of EAP-TLS. */
1272 conn->push_buf = wpabuf_alloc(0);
1273 }
1274 break;
1275 case GNUTLS_E_FATAL_ALERT_RECEIVED:
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001276 alert = gnutls_alert_get(conn->session);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001277 wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001278 __func__, gnutls_alert_get_name(alert));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001279 conn->read_alerts++;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001280 if (conn->global->event_cb != NULL) {
1281 union tls_event_data ev;
1282
1283 os_memset(&ev, 0, sizeof(ev));
1284 ev.alert.is_local = 0;
1285 ev.alert.type = gnutls_alert_get_name(alert);
1286 ev.alert.description = ev.alert.type;
1287 conn->global->event_cb(conn->global->cb_ctx,
1288 TLS_ALERT, &ev);
1289 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001290 /* continue */
1291 default:
1292 wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
1293 "-> %s", __func__, gnutls_strerror(ret));
1294 conn->failed++;
1295 }
1296 } else {
1297 size_t size;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001298
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001299 wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001300
1301#if GNUTLS_VERSION_NUMBER >= 0x03010a
1302 {
1303 char *desc;
1304
1305 desc = gnutls_session_get_desc(conn->session);
1306 if (desc) {
1307 wpa_printf(MSG_DEBUG, "GnuTLS: %s", desc);
1308 gnutls_free(desc);
1309 }
1310 }
1311#endif /* GnuTLS 3.1.10 or newer */
1312
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001313 conn->established = 1;
1314 if (conn->push_buf == NULL) {
1315 /* Need to return something to get final TLS ACK. */
1316 conn->push_buf = wpabuf_alloc(0);
1317 }
1318
1319 gnutls_session_get_data(conn->session, NULL, &size);
1320 if (global->session_data == NULL ||
1321 global->session_data_size < size) {
1322 os_free(global->session_data);
1323 global->session_data = os_malloc(size);
1324 }
1325 if (global->session_data) {
1326 global->session_data_size = size;
1327 gnutls_session_get_data(conn->session,
1328 global->session_data,
1329 &global->session_data_size);
1330 }
1331
1332 if (conn->pull_buf && appl_data)
1333 *appl_data = gnutls_get_appl_data(conn);
1334 }
1335
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001336 out_data = conn->push_buf;
1337 conn->push_buf = NULL;
1338 return out_data;
1339}
1340
1341
1342struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
1343 struct tls_connection *conn,
1344 const struct wpabuf *in_data,
1345 struct wpabuf **appl_data)
1346{
1347 return tls_connection_handshake(tls_ctx, conn, in_data, appl_data);
1348}
1349
1350
1351struct wpabuf * tls_connection_encrypt(void *tls_ctx,
1352 struct tls_connection *conn,
1353 const struct wpabuf *in_data)
1354{
1355 ssize_t res;
1356 struct wpabuf *buf;
1357
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001358 res = gnutls_record_send(conn->session, wpabuf_head(in_data),
1359 wpabuf_len(in_data));
1360 if (res < 0) {
1361 wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
1362 __func__, gnutls_strerror(res));
1363 return NULL;
1364 }
1365
1366 buf = conn->push_buf;
1367 conn->push_buf = NULL;
1368 return buf;
1369}
1370
1371
1372struct wpabuf * tls_connection_decrypt(void *tls_ctx,
1373 struct tls_connection *conn,
1374 const struct wpabuf *in_data)
1375{
1376 ssize_t res;
1377 struct wpabuf *out;
1378
1379 if (conn->pull_buf) {
1380 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
1381 "pull_buf", __func__,
1382 (unsigned long) wpabuf_len(conn->pull_buf));
1383 wpabuf_free(conn->pull_buf);
1384 }
1385 conn->pull_buf = wpabuf_dup(in_data);
1386 if (conn->pull_buf == NULL)
1387 return NULL;
1388 conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
1389
1390 /*
1391 * Even though we try to disable TLS compression, it is possible that
1392 * this cannot be done with all TLS libraries. Add extra buffer space
1393 * to handle the possibility of the decrypted data being longer than
1394 * input data.
1395 */
1396 out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
1397 if (out == NULL)
1398 return NULL;
1399
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001400 res = gnutls_record_recv(conn->session, wpabuf_mhead(out),
1401 wpabuf_size(out));
1402 if (res < 0) {
1403 wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
1404 "(%s)", __func__, (int) res, gnutls_strerror(res));
1405 wpabuf_free(out);
1406 return NULL;
1407 }
1408 wpabuf_put(out, res);
1409
1410 return out;
1411}
1412
1413
1414int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
1415{
1416 if (conn == NULL)
1417 return 0;
1418 return gnutls_session_is_resumed(conn->session);
1419}
1420
1421
1422int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
1423 u8 *ciphers)
1424{
1425 /* TODO */
1426 return -1;
1427}
1428
1429
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001430int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
1431 char *buf, size_t buflen)
1432{
1433 /* TODO */
1434 return -1;
1435}
1436
1437
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001438int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
1439 char *buf, size_t buflen)
1440{
1441 /* TODO */
1442 buf[0] = '\0';
1443 return 0;
1444}
1445
1446
1447int tls_connection_enable_workaround(void *ssl_ctx,
1448 struct tls_connection *conn)
1449{
1450 gnutls_record_disable_padding(conn->session);
1451 return 0;
1452}
1453
1454
1455int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
1456 int ext_type, const u8 *data,
1457 size_t data_len)
1458{
1459 /* TODO */
1460 return -1;
1461}
1462
1463
1464int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
1465{
1466 if (conn == NULL)
1467 return -1;
1468 return conn->failed;
1469}
1470
1471
1472int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
1473{
1474 if (conn == NULL)
1475 return -1;
1476 return conn->read_alerts;
1477}
1478
1479
1480int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
1481{
1482 if (conn == NULL)
1483 return -1;
1484 return conn->write_alerts;
1485}
1486
1487
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001488int tls_connection_set_session_ticket_cb(void *tls_ctx,
1489 struct tls_connection *conn,
1490 tls_session_ticket_cb cb, void *ctx)
1491{
1492 return -1;
1493}
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001494
1495
1496int tls_get_library_version(char *buf, size_t buf_len)
1497{
1498 return os_snprintf(buf, buf_len, "GnuTLS build=%s run=%s",
1499 GNUTLS_VERSION, gnutls_check_version(NULL));
1500}
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001501
1502
1503void tls_connection_set_success_data(struct tls_connection *conn,
1504 struct wpabuf *data)
1505{
1506}
1507
1508
1509void tls_connection_set_success_data_resumed(struct tls_connection *conn)
1510{
1511}
1512
1513
1514const struct wpabuf *
1515tls_connection_get_success_data(struct tls_connection *conn)
1516{
1517 return NULL;
1518}
1519
1520
1521void tls_connection_remove_session(struct tls_connection *conn)
1522{
1523}