blob: f2eacb5d0b5cba3877ae379aa258104b99b583dc [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;
61 unsigned int flags;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070062};
63
64
Dmitry Shmidtff787d52015-01-12 13:01:47 -080065static int tls_connection_verify_peer(gnutls_session_t session);
66
67
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070068static void tls_log_func(int level, const char *msg)
69{
70 char *s, *pos;
71 if (level == 6 || level == 7) {
72 /* These levels seem to be mostly I/O debug and msg dumps */
73 return;
74 }
75
76 s = os_strdup(msg);
77 if (s == NULL)
78 return;
79
80 pos = s;
81 while (*pos != '\0') {
82 if (*pos == '\n') {
83 *pos = '\0';
84 break;
85 }
86 pos++;
87 }
88 wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
89 "gnutls<%d> %s", level, s);
90 os_free(s);
91}
92
93
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070094void * tls_init(const struct tls_config *conf)
95{
96 struct tls_global *global;
97
Dmitry Shmidtff787d52015-01-12 13:01:47 -080098 if (tls_gnutls_ref_count == 0) {
99 wpa_printf(MSG_DEBUG,
100 "GnuTLS: Library version %s (runtime) - %s (build)",
101 gnutls_check_version(NULL), GNUTLS_VERSION);
102 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700103
104 global = os_zalloc(sizeof(*global));
105 if (global == NULL)
106 return NULL;
107
108 if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) {
109 os_free(global);
110 return NULL;
111 }
112 tls_gnutls_ref_count++;
113
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700114 gnutls_global_set_log_function(tls_log_func);
115 if (wpa_debug_show_keys)
116 gnutls_global_set_log_level(11);
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800117
118 if (conf) {
119 global->event_cb = conf->event_cb;
120 global->cb_ctx = conf->cb_ctx;
121 global->cert_in_cb = conf->cert_in_cb;
122 }
123
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700124 return global;
125}
126
127
128void tls_deinit(void *ssl_ctx)
129{
130 struct tls_global *global = ssl_ctx;
131 if (global) {
132 if (global->params_set)
133 gnutls_certificate_free_credentials(global->xcred);
134 os_free(global->session_data);
135 os_free(global);
136 }
137
138 tls_gnutls_ref_count--;
139 if (tls_gnutls_ref_count == 0)
140 gnutls_global_deinit();
141}
142
143
144int tls_get_errors(void *ssl_ctx)
145{
146 return 0;
147}
148
149
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800150static ssize_t tls_pull_func(gnutls_transport_ptr_t ptr, void *buf,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700151 size_t len)
152{
153 struct tls_connection *conn = (struct tls_connection *) ptr;
154 const u8 *end;
155 if (conn->pull_buf == NULL) {
156 errno = EWOULDBLOCK;
157 return -1;
158 }
159
160 end = wpabuf_head_u8(conn->pull_buf) + wpabuf_len(conn->pull_buf);
161 if ((size_t) (end - conn->pull_buf_offset) < len)
162 len = end - conn->pull_buf_offset;
163 os_memcpy(buf, conn->pull_buf_offset, len);
164 conn->pull_buf_offset += len;
165 if (conn->pull_buf_offset == end) {
166 wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
167 wpabuf_free(conn->pull_buf);
168 conn->pull_buf = NULL;
169 conn->pull_buf_offset = NULL;
170 } else {
171 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
172 __func__,
173 (unsigned long) (end - conn->pull_buf_offset));
174 }
175 return len;
176}
177
178
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800179static ssize_t tls_push_func(gnutls_transport_ptr_t ptr, const void *buf,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700180 size_t len)
181{
182 struct tls_connection *conn = (struct tls_connection *) ptr;
183
184 if (wpabuf_resize(&conn->push_buf, len) < 0) {
185 errno = ENOMEM;
186 return -1;
187 }
188 wpabuf_put_data(conn->push_buf, buf, len);
189
190 return len;
191}
192
193
194static int tls_gnutls_init_session(struct tls_global *global,
195 struct tls_connection *conn)
196{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800197 const char *err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700198 int ret;
199
200 ret = gnutls_init(&conn->session,
201 global->server ? GNUTLS_SERVER : GNUTLS_CLIENT);
202 if (ret < 0) {
203 wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
204 "connection: %s", gnutls_strerror(ret));
205 return -1;
206 }
207
208 ret = gnutls_set_default_priority(conn->session);
209 if (ret < 0)
210 goto fail;
211
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800212 ret = gnutls_priority_set_direct(conn->session, "NORMAL:-VERS-SSL3.0",
213 &err);
214 if (ret < 0) {
215 wpa_printf(MSG_ERROR, "GnuTLS: Priority string failure at "
216 "'%s'", err);
217 goto fail;
218 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700219
220 gnutls_transport_set_pull_function(conn->session, tls_pull_func);
221 gnutls_transport_set_push_function(conn->session, tls_push_func);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800222 gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr_t) conn);
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800223 gnutls_session_set_ptr(conn->session, conn);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700224
225 return 0;
226
227fail:
228 wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s",
229 gnutls_strerror(ret));
230 gnutls_deinit(conn->session);
231 return -1;
232}
233
234
235struct tls_connection * tls_connection_init(void *ssl_ctx)
236{
237 struct tls_global *global = ssl_ctx;
238 struct tls_connection *conn;
239 int ret;
240
241 conn = os_zalloc(sizeof(*conn));
242 if (conn == NULL)
243 return NULL;
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800244 conn->global = global;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700245
246 if (tls_gnutls_init_session(global, conn)) {
247 os_free(conn);
248 return NULL;
249 }
250
251 if (global->params_set) {
252 ret = gnutls_credentials_set(conn->session,
253 GNUTLS_CRD_CERTIFICATE,
254 global->xcred);
255 if (ret < 0) {
256 wpa_printf(MSG_INFO, "Failed to configure "
257 "credentials: %s", gnutls_strerror(ret));
258 os_free(conn);
259 return NULL;
260 }
261 }
262
263 if (gnutls_certificate_allocate_credentials(&conn->xcred)) {
264 os_free(conn);
265 return NULL;
266 }
267
268 return conn;
269}
270
271
272void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
273{
274 if (conn == NULL)
275 return;
276
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700277 gnutls_certificate_free_credentials(conn->xcred);
278 gnutls_deinit(conn->session);
279 os_free(conn->pre_shared_secret);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700280 wpabuf_free(conn->push_buf);
281 wpabuf_free(conn->pull_buf);
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800282 os_free(conn->suffix_match);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700283 os_free(conn);
284}
285
286
287int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
288{
289 return conn ? conn->established : 0;
290}
291
292
293int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
294{
295 struct tls_global *global = ssl_ctx;
296 int ret;
297
298 if (conn == NULL)
299 return -1;
300
301 /* Shutdown previous TLS connection without notifying the peer
302 * because the connection was already terminated in practice
303 * and "close notify" shutdown alert would confuse AS. */
304 gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
305 wpabuf_free(conn->push_buf);
306 conn->push_buf = NULL;
307 conn->established = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700308
309 gnutls_deinit(conn->session);
310 if (tls_gnutls_init_session(global, conn)) {
311 wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session "
312 "for session resumption use");
313 return -1;
314 }
315
316 ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
317 conn->params_set ? conn->xcred :
318 global->xcred);
319 if (ret < 0) {
320 wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials "
321 "for session resumption: %s", gnutls_strerror(ret));
322 return -1;
323 }
324
325 if (global->session_data) {
326 ret = gnutls_session_set_data(conn->session,
327 global->session_data,
328 global->session_data_size);
329 if (ret < 0) {
330 wpa_printf(MSG_INFO, "GnuTLS: Failed to set session "
331 "data: %s", gnutls_strerror(ret));
332 return -1;
333 }
334 }
335
336 return 0;
337}
338
339
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700340int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
341 const struct tls_connection_params *params)
342{
343 int ret;
344
345 if (conn == NULL || params == NULL)
346 return -1;
347
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700348 if (params->subject_match) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800349 wpa_printf(MSG_INFO, "GnuTLS: subject_match not supported");
350 return -1;
351 }
352
353 if (params->altsubject_match) {
354 wpa_printf(MSG_INFO, "GnuTLS: altsubject_match not supported");
355 return -1;
356 }
357
358 os_free(conn->suffix_match);
359 conn->suffix_match = NULL;
360 if (params->suffix_match) {
361 conn->suffix_match = os_strdup(params->suffix_match);
362 if (conn->suffix_match == NULL)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700363 return -1;
364 }
365
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800366 conn->flags = params->flags;
367
368 if (params->openssl_ciphers) {
369 wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
370 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700371 }
372
373 /* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
374 * to force peer validation(?) */
375
376 if (params->ca_cert) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800377 wpa_printf(MSG_DEBUG, "GnuTLS: Try to parse %s in DER format",
378 params->ca_cert);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700379 ret = gnutls_certificate_set_x509_trust_file(
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800380 conn->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700381 if (ret < 0) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800382 wpa_printf(MSG_DEBUG,
383 "GnuTLS: Failed to read CA cert '%s' in DER format (%s) - try in PEM format",
384 params->ca_cert,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700385 gnutls_strerror(ret));
386 ret = gnutls_certificate_set_x509_trust_file(
387 conn->xcred, params->ca_cert,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800388 GNUTLS_X509_FMT_PEM);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700389 if (ret < 0) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800390 wpa_printf(MSG_DEBUG,
391 "Failed to read CA cert '%s' in PEM format: %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700392 params->ca_cert,
393 gnutls_strerror(ret));
394 return -1;
395 }
396 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800397 } else if (params->ca_cert_blob) {
398 gnutls_datum_t ca;
399
400 ca.data = (unsigned char *) params->ca_cert_blob;
401 ca.size = params->ca_cert_blob_len;
402
403 ret = gnutls_certificate_set_x509_trust_mem(
404 conn->xcred, &ca, GNUTLS_X509_FMT_DER);
405 if (ret < 0) {
406 wpa_printf(MSG_DEBUG,
407 "Failed to parse CA cert in DER format: %s",
408 gnutls_strerror(ret));
409 ret = gnutls_certificate_set_x509_trust_mem(
410 conn->xcred, &ca, GNUTLS_X509_FMT_PEM);
411 if (ret < 0) {
412 wpa_printf(MSG_DEBUG,
413 "Failed to parse CA cert in PEM format: %s",
414 gnutls_strerror(ret));
415 return -1;
416 }
417 }
418 } else if (params->ca_path) {
419 wpa_printf(MSG_INFO, "GnuTLS: ca_path not supported");
420 return -1;
421 }
422
423 conn->disable_time_checks = 0;
424 if (params->ca_cert || params->ca_cert_blob) {
425 conn->verify_peer = 1;
426 gnutls_certificate_set_verify_function(
427 conn->xcred, tls_connection_verify_peer);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700428
429 if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
430 gnutls_certificate_set_verify_flags(
431 conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
432 }
433
434 if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800435 conn->disable_time_checks = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700436 gnutls_certificate_set_verify_flags(
437 conn->xcred,
438 GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
439 }
440 }
441
442 if (params->client_cert && params->private_key) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800443#if GNUTLS_VERSION_NUMBER >= 0x03010b
444 ret = gnutls_certificate_set_x509_key_file2(
445 conn->xcred, params->client_cert, params->private_key,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800446 GNUTLS_X509_FMT_DER, params->private_key_passwd, 0);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800447#else
448 /* private_key_passwd not (easily) supported here */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700449 ret = gnutls_certificate_set_x509_key_file(
450 conn->xcred, params->client_cert, params->private_key,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800451 GNUTLS_X509_FMT_DER);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800452#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700453 if (ret < 0) {
454 wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800455 "in DER format: %s", gnutls_strerror(ret));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800456#if GNUTLS_VERSION_NUMBER >= 0x03010b
457 ret = gnutls_certificate_set_x509_key_file2(
458 conn->xcred, params->client_cert,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800459 params->private_key, GNUTLS_X509_FMT_PEM,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800460 params->private_key_passwd, 0);
461#else
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700462 ret = gnutls_certificate_set_x509_key_file(
463 conn->xcred, params->client_cert,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800464 params->private_key, GNUTLS_X509_FMT_PEM);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800465#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700466 if (ret < 0) {
467 wpa_printf(MSG_DEBUG, "Failed to read client "
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800468 "cert/key in PEM format: %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700469 gnutls_strerror(ret));
470 return ret;
471 }
472 }
473 } else if (params->private_key) {
474 int pkcs12_ok = 0;
475#ifdef PKCS12_FUNCS
476 /* Try to load in PKCS#12 format */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700477 ret = gnutls_certificate_set_x509_simple_pkcs12_file(
478 conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
479 params->private_key_passwd);
480 if (ret != 0) {
481 wpa_printf(MSG_DEBUG, "Failed to load private_key in "
482 "PKCS#12 format: %s", gnutls_strerror(ret));
483 return -1;
484 } else
485 pkcs12_ok = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700486#endif /* PKCS12_FUNCS */
487
488 if (!pkcs12_ok) {
489 wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
490 "included");
491 return -1;
492 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800493 } else if (params->client_cert_blob && params->private_key_blob) {
494 gnutls_datum_t cert, key;
495
496 cert.data = (unsigned char *) params->client_cert_blob;
497 cert.size = params->client_cert_blob_len;
498 key.data = (unsigned char *) params->private_key_blob;
499 key.size = params->private_key_blob_len;
500
501#if GNUTLS_VERSION_NUMBER >= 0x03010b
502 ret = gnutls_certificate_set_x509_key_mem2(
503 conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER,
504 params->private_key_passwd, 0);
505#else
506 /* private_key_passwd not (easily) supported here */
507 ret = gnutls_certificate_set_x509_key_mem(
508 conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER);
509#endif
510 if (ret < 0) {
511 wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
512 "in DER format: %s", gnutls_strerror(ret));
513#if GNUTLS_VERSION_NUMBER >= 0x03010b
514 ret = gnutls_certificate_set_x509_key_mem2(
515 conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM,
516 params->private_key_passwd, 0);
517#else
518 /* private_key_passwd not (easily) supported here */
519 ret = gnutls_certificate_set_x509_key_mem(
520 conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM);
521#endif
522 if (ret < 0) {
523 wpa_printf(MSG_DEBUG, "Failed to read client "
524 "cert/key in PEM format: %s",
525 gnutls_strerror(ret));
526 return ret;
527 }
528 }
529 } else if (params->private_key_blob) {
530#ifdef PKCS12_FUNCS
531 gnutls_datum_t key;
532
533 key.data = (unsigned char *) params->private_key_blob;
534 key.size = params->private_key_blob_len;
535
536 /* Try to load in PKCS#12 format */
537 ret = gnutls_certificate_set_x509_simple_pkcs12_mem(
538 conn->xcred, &key, GNUTLS_X509_FMT_DER,
539 params->private_key_passwd);
540 if (ret != 0) {
541 wpa_printf(MSG_DEBUG, "Failed to load private_key in "
542 "PKCS#12 format: %s", gnutls_strerror(ret));
543 return -1;
544 }
545#else /* PKCS12_FUNCS */
546 wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not included");
547 return -1;
548#endif /* PKCS12_FUNCS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700549 }
550
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800551#if GNUTLS_VERSION_NUMBER >= 0x030103
552 if (params->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)) {
553 ret = gnutls_ocsp_status_request_enable_client(conn->session,
554 NULL, 0, NULL);
555 if (ret != GNUTLS_E_SUCCESS) {
556 wpa_printf(MSG_INFO,
557 "GnuTLS: Failed to enable OCSP client");
558 return -1;
559 }
560 }
561#else /* 3.1.3 */
562 if (params->flags & TLS_CONN_REQUIRE_OCSP) {
563 wpa_printf(MSG_INFO,
564 "GnuTLS: OCSP not supported by this version of GnuTLS");
565 return -1;
566 }
567#endif /* 3.1.3 */
568
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700569 conn->params_set = 1;
570
571 ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
572 conn->xcred);
573 if (ret < 0) {
574 wpa_printf(MSG_INFO, "Failed to configure credentials: %s",
575 gnutls_strerror(ret));
576 }
577
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700578 return ret;
579}
580
581
582int tls_global_set_params(void *tls_ctx,
583 const struct tls_connection_params *params)
584{
585 struct tls_global *global = tls_ctx;
586 int ret;
587
588 /* Currently, global parameters are only set when running in server
589 * mode. */
590 global->server = 1;
591
592 if (global->params_set) {
593 gnutls_certificate_free_credentials(global->xcred);
594 global->params_set = 0;
595 }
596
597 ret = gnutls_certificate_allocate_credentials(&global->xcred);
598 if (ret) {
599 wpa_printf(MSG_DEBUG, "Failed to allocate global credentials "
600 "%s", gnutls_strerror(ret));
601 return -1;
602 }
603
604 if (params->ca_cert) {
605 ret = gnutls_certificate_set_x509_trust_file(
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800606 global->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700607 if (ret < 0) {
608 wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800609 "in DER format: %s", params->ca_cert,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700610 gnutls_strerror(ret));
611 ret = gnutls_certificate_set_x509_trust_file(
612 global->xcred, params->ca_cert,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800613 GNUTLS_X509_FMT_PEM);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700614 if (ret < 0) {
615 wpa_printf(MSG_DEBUG, "Failed to read CA cert "
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800616 "'%s' in PEM format: %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700617 params->ca_cert,
618 gnutls_strerror(ret));
619 goto fail;
620 }
621 }
622
623 if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
624 gnutls_certificate_set_verify_flags(
625 global->xcred,
626 GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
627 }
628
629 if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
630 gnutls_certificate_set_verify_flags(
631 global->xcred,
632 GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
633 }
634 }
635
636 if (params->client_cert && params->private_key) {
637 /* TODO: private_key_passwd? */
638 ret = gnutls_certificate_set_x509_key_file(
639 global->xcred, params->client_cert,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800640 params->private_key, GNUTLS_X509_FMT_DER);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700641 if (ret < 0) {
642 wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800643 "in DER format: %s", gnutls_strerror(ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700644 ret = gnutls_certificate_set_x509_key_file(
645 global->xcred, params->client_cert,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800646 params->private_key, GNUTLS_X509_FMT_PEM);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700647 if (ret < 0) {
648 wpa_printf(MSG_DEBUG, "Failed to read client "
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800649 "cert/key in PEM format: %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700650 gnutls_strerror(ret));
651 goto fail;
652 }
653 }
654 } else if (params->private_key) {
655 int pkcs12_ok = 0;
656#ifdef PKCS12_FUNCS
657 /* Try to load in PKCS#12 format */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700658 ret = gnutls_certificate_set_x509_simple_pkcs12_file(
659 global->xcred, params->private_key,
660 GNUTLS_X509_FMT_DER, params->private_key_passwd);
661 if (ret != 0) {
662 wpa_printf(MSG_DEBUG, "Failed to load private_key in "
663 "PKCS#12 format: %s", gnutls_strerror(ret));
664 goto fail;
665 } else
666 pkcs12_ok = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700667#endif /* PKCS12_FUNCS */
668
669 if (!pkcs12_ok) {
670 wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
671 "included");
672 goto fail;
673 }
674 }
675
676 global->params_set = 1;
677
678 return 0;
679
680fail:
681 gnutls_certificate_free_credentials(global->xcred);
682 return -1;
683}
684
685
686int tls_global_set_verify(void *ssl_ctx, int check_crl)
687{
688 /* TODO */
689 return 0;
690}
691
692
693int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
694 int verify_peer)
695{
696 if (conn == NULL || conn->session == NULL)
697 return -1;
698
699 conn->verify_peer = verify_peer;
700 gnutls_certificate_server_set_request(conn->session,
701 verify_peer ? GNUTLS_CERT_REQUIRE
702 : GNUTLS_CERT_REQUEST);
703
704 return 0;
705}
706
707
708int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
709 struct tls_keys *keys)
710{
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800711#if GNUTLS_VERSION_NUMBER >= 0x030012
712 gnutls_datum_t client, server;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700713
714 if (conn == NULL || conn->session == NULL || keys == NULL)
715 return -1;
716
717 os_memset(keys, 0, sizeof(*keys));
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800718 gnutls_session_get_random(conn->session, &client, &server);
719 keys->client_random = client.data;
720 keys->server_random = server.data;
721 keys->client_random_len = client.size;
722 keys->server_random_len = client.size;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700723
724 return 0;
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800725#else /* 3.0.18 */
726 return -1;
727#endif /* 3.0.18 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700728}
729
730
731int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
732 const char *label, int server_random_first,
733 u8 *out, size_t out_len)
734{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700735 if (conn == NULL || conn->session == NULL)
736 return -1;
737
738 return gnutls_prf(conn->session, os_strlen(label), label,
739 server_random_first, 0, NULL, out_len, (char *) out);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700740}
741
742
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800743static void gnutls_tls_fail_event(struct tls_connection *conn,
744 const gnutls_datum_t *cert, int depth,
745 const char *subject, const char *err_str,
746 enum tls_fail_reason reason)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700747{
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800748 union tls_event_data ev;
749 struct tls_global *global = conn->global;
750 struct wpabuf *cert_buf = NULL;
751
752 if (global->event_cb == NULL)
753 return;
754
755 os_memset(&ev, 0, sizeof(ev));
756 ev.cert_fail.depth = depth;
757 ev.cert_fail.subject = subject ? subject : "";
758 ev.cert_fail.reason = reason;
759 ev.cert_fail.reason_txt = err_str;
760 if (cert) {
761 cert_buf = wpabuf_alloc_copy(cert->data, cert->size);
762 ev.cert_fail.cert = cert_buf;
763 }
764 global->event_cb(global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
765 wpabuf_free(cert_buf);
766}
767
768
769#if GNUTLS_VERSION_NUMBER < 0x030300
770static int server_eku_purpose(gnutls_x509_crt_t cert)
771{
772 unsigned int i;
773
774 for (i = 0; ; i++) {
775 char oid[128];
776 size_t oid_size = sizeof(oid);
777 int res;
778
779 res = gnutls_x509_crt_get_key_purpose_oid(cert, i, oid,
780 &oid_size, NULL);
781 if (res == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
782 if (i == 0) {
783 /* No EKU - assume any use allowed */
784 return 1;
785 }
786 break;
787 }
788
789 if (res < 0) {
790 wpa_printf(MSG_INFO, "GnuTLS: Failed to get EKU");
791 return 0;
792 }
793
794 wpa_printf(MSG_DEBUG, "GnuTLS: Certificate purpose: %s", oid);
795 if (os_strcmp(oid, GNUTLS_KP_TLS_WWW_SERVER) == 0 ||
796 os_strcmp(oid, GNUTLS_KP_ANY) == 0)
797 return 1;
798 }
799
800 return 0;
801}
802#endif /* < 3.3.0 */
803
804
805static int check_ocsp(struct tls_connection *conn, gnutls_session_t session,
806 gnutls_alert_description_t *err)
807{
808#if GNUTLS_VERSION_NUMBER >= 0x030103
809 gnutls_datum_t response, buf;
810 gnutls_ocsp_resp_t resp;
811 unsigned int cert_status;
812 int res;
813
814 if (!(conn->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)))
815 return 0;
816
817 if (!gnutls_ocsp_status_request_is_checked(session, 0)) {
818 if (conn->flags & TLS_CONN_REQUIRE_OCSP) {
819 wpa_printf(MSG_INFO,
820 "GnuTLS: No valid OCSP response received");
821 goto ocsp_error;
822 }
823
824 wpa_printf(MSG_DEBUG,
825 "GnuTLS: Valid OCSP response was not received - continue since OCSP was not required");
826 return 0;
827 }
828
829 /*
830 * GnuTLS has already verified the OCSP response in
831 * check_ocsp_response() and rejected handshake if the certificate was
832 * found to be revoked. However, if the response indicates that the
833 * status is unknown, handshake continues and reaches here. We need to
834 * re-import the OCSP response to check for unknown certificate status,
835 * but we do not need to repeat gnutls_ocsp_resp_check_crt() and
836 * gnutls_ocsp_resp_verify_direct() calls.
837 */
838
839 res = gnutls_ocsp_status_request_get(session, &response);
840 if (res != GNUTLS_E_SUCCESS) {
841 wpa_printf(MSG_INFO,
842 "GnuTLS: OCSP response was received, but it was not valid");
843 goto ocsp_error;
844 }
845
846 if (gnutls_ocsp_resp_init(&resp) != GNUTLS_E_SUCCESS)
847 goto ocsp_error;
848
849 res = gnutls_ocsp_resp_import(resp, &response);
850 if (res != GNUTLS_E_SUCCESS) {
851 wpa_printf(MSG_INFO,
852 "GnuTLS: Could not parse received OCSP response: %s",
853 gnutls_strerror(res));
854 gnutls_ocsp_resp_deinit(resp);
855 goto ocsp_error;
856 }
857
858 res = gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &buf);
859 if (res == GNUTLS_E_SUCCESS) {
860 wpa_printf(MSG_DEBUG, "GnuTLS: %s", buf.data);
861 gnutls_free(buf.data);
862 }
863
864 res = gnutls_ocsp_resp_get_single(resp, 0, NULL, NULL, NULL,
865 NULL, &cert_status, NULL,
866 NULL, NULL, NULL);
867 gnutls_ocsp_resp_deinit(resp);
868 if (res != GNUTLS_E_SUCCESS) {
869 wpa_printf(MSG_INFO,
870 "GnuTLS: Failed to extract OCSP information: %s",
871 gnutls_strerror(res));
872 goto ocsp_error;
873 }
874
875 if (cert_status == GNUTLS_OCSP_CERT_GOOD) {
876 wpa_printf(MSG_DEBUG, "GnuTLS: OCSP cert status: good");
877 } else if (cert_status == GNUTLS_OCSP_CERT_REVOKED) {
878 wpa_printf(MSG_DEBUG,
879 "GnuTLS: OCSP cert status: revoked");
880 goto ocsp_error;
881 } else {
882 wpa_printf(MSG_DEBUG,
883 "GnuTLS: OCSP cert status: unknown");
884 if (conn->flags & TLS_CONN_REQUIRE_OCSP)
885 goto ocsp_error;
886 wpa_printf(MSG_DEBUG,
887 "GnuTLS: OCSP was not required, so allow connection to continue");
888 }
889
890 return 0;
891
892ocsp_error:
893 gnutls_tls_fail_event(conn, NULL, 0, NULL,
894 "bad certificate status response",
895 TLS_FAIL_REVOKED);
896 *err = GNUTLS_A_CERTIFICATE_REVOKED;
897 return -1;
898#else /* GnuTLS 3.1.3 or newer */
899 return 0;
900#endif /* GnuTLS 3.1.3 or newer */
901}
902
903
904static int tls_connection_verify_peer(gnutls_session_t session)
905{
906 struct tls_connection *conn;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700907 unsigned int status, num_certs, i;
908 struct os_time now;
909 const gnutls_datum_t *certs;
910 gnutls_x509_crt_t cert;
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800911 gnutls_alert_description_t err;
912 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700913
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800914 conn = gnutls_session_get_ptr(session);
915 if (!conn->verify_peer) {
916 wpa_printf(MSG_DEBUG,
917 "GnuTLS: No peer certificate verification enabled");
918 return 0;
919 }
920
921 wpa_printf(MSG_DEBUG, "GnuTSL: Verifying peer certificate");
922
923#if GNUTLS_VERSION_NUMBER >= 0x030300
924 {
925 gnutls_typed_vdata_st data[1];
926 unsigned int elements = 0;
927
928 os_memset(data, 0, sizeof(data));
929 if (!conn->global->server) {
930 data[elements].type = GNUTLS_DT_KEY_PURPOSE_OID;
931 data[elements].data = (void *) GNUTLS_KP_TLS_WWW_SERVER;
932 elements++;
933 }
934 res = gnutls_certificate_verify_peers(session, data, 1,
935 &status);
936 }
937#else /* < 3.3.0 */
938 res = gnutls_certificate_verify_peers2(session, &status);
939#endif
940 if (res < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700941 wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
942 "certificate chain");
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800943 err = GNUTLS_A_INTERNAL_ERROR;
944 goto out;
945 }
946
947#if GNUTLS_VERSION_NUMBER >= 0x030104
948 {
949 gnutls_datum_t info;
950 int ret, type;
951
952 type = gnutls_certificate_type_get(session);
953 ret = gnutls_certificate_verification_status_print(status, type,
954 &info, 0);
955 if (ret < 0) {
956 wpa_printf(MSG_DEBUG,
957 "GnuTLS: Failed to print verification status");
958 err = GNUTLS_A_INTERNAL_ERROR;
959 goto out;
960 }
961 wpa_printf(MSG_DEBUG, "GnuTLS: %s", info.data);
962 gnutls_free(info.data);
963 }
964#endif /* GnuTLS 3.1.4 or newer */
965
966 certs = gnutls_certificate_get_peers(session, &num_certs);
967 if (certs == NULL || num_certs == 0) {
968 wpa_printf(MSG_INFO, "TLS: No peer certificate chain received");
969 err = GNUTLS_A_UNKNOWN_CA;
970 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700971 }
972
973 if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
974 wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
975 if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
976 wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
977 "algorithm");
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800978 gnutls_tls_fail_event(conn, NULL, 0, NULL,
979 "certificate uses insecure algorithm",
980 TLS_FAIL_BAD_CERTIFICATE);
981 err = GNUTLS_A_INSUFFICIENT_SECURITY;
982 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700983 }
984 if (status & GNUTLS_CERT_NOT_ACTIVATED) {
985 wpa_printf(MSG_INFO, "TLS: Certificate not yet "
986 "activated");
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800987 gnutls_tls_fail_event(conn, NULL, 0, NULL,
988 "certificate not yet valid",
989 TLS_FAIL_NOT_YET_VALID);
990 err = GNUTLS_A_CERTIFICATE_EXPIRED;
991 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700992 }
993 if (status & GNUTLS_CERT_EXPIRED) {
994 wpa_printf(MSG_INFO, "TLS: Certificate expired");
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800995 gnutls_tls_fail_event(conn, NULL, 0, NULL,
996 "certificate has expired",
997 TLS_FAIL_EXPIRED);
998 err = GNUTLS_A_CERTIFICATE_EXPIRED;
999 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001000 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001001 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1002 "untrusted certificate",
1003 TLS_FAIL_UNTRUSTED);
1004 err = GNUTLS_A_INTERNAL_ERROR;
1005 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001006 }
1007
1008 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
1009 wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
1010 "known issuer");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001011 gnutls_tls_fail_event(conn, NULL, 0, NULL, "signed not found",
1012 TLS_FAIL_UNTRUSTED);
1013 err = GNUTLS_A_UNKNOWN_CA;
1014 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001015 }
1016
1017 if (status & GNUTLS_CERT_REVOKED) {
1018 wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001019 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1020 "certificate revoked",
1021 TLS_FAIL_REVOKED);
1022 err = GNUTLS_A_CERTIFICATE_REVOKED;
1023 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001024 }
1025
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001026 if (status != 0) {
1027 wpa_printf(MSG_INFO, "TLS: Unknown verification status: %d",
1028 status);
1029 err = GNUTLS_A_INTERNAL_ERROR;
1030 goto out;
1031 }
1032
1033 if (check_ocsp(conn, session, &err))
1034 goto out;
1035
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001036 os_get_time(&now);
1037
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001038 for (i = 0; i < num_certs; i++) {
1039 char *buf;
1040 size_t len;
1041 if (gnutls_x509_crt_init(&cert) < 0) {
1042 wpa_printf(MSG_INFO, "TLS: Certificate initialization "
1043 "failed");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001044 err = GNUTLS_A_BAD_CERTIFICATE;
1045 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001046 }
1047
1048 if (gnutls_x509_crt_import(cert, &certs[i],
1049 GNUTLS_X509_FMT_DER) < 0) {
1050 wpa_printf(MSG_INFO, "TLS: Could not parse peer "
1051 "certificate %d/%d", i + 1, num_certs);
1052 gnutls_x509_crt_deinit(cert);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001053 err = GNUTLS_A_BAD_CERTIFICATE;
1054 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001055 }
1056
1057 gnutls_x509_crt_get_dn(cert, NULL, &len);
1058 len++;
1059 buf = os_malloc(len + 1);
1060 if (buf) {
1061 buf[0] = buf[len] = '\0';
1062 gnutls_x509_crt_get_dn(cert, buf, &len);
1063 }
1064 wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
1065 i + 1, num_certs, buf);
1066
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001067 if (conn->global->event_cb) {
1068 struct wpabuf *cert_buf = NULL;
1069 union tls_event_data ev;
1070#ifdef CONFIG_SHA256
1071 u8 hash[32];
1072 const u8 *_addr[1];
1073 size_t _len[1];
1074#endif /* CONFIG_SHA256 */
1075
1076 os_memset(&ev, 0, sizeof(ev));
1077 if (conn->global->cert_in_cb) {
1078 cert_buf = wpabuf_alloc_copy(certs[i].data,
1079 certs[i].size);
1080 ev.peer_cert.cert = cert_buf;
1081 }
1082#ifdef CONFIG_SHA256
1083 _addr[0] = certs[i].data;
1084 _len[0] = certs[i].size;
1085 if (sha256_vector(1, _addr, _len, hash) == 0) {
1086 ev.peer_cert.hash = hash;
1087 ev.peer_cert.hash_len = sizeof(hash);
1088 }
1089#endif /* CONFIG_SHA256 */
1090 ev.peer_cert.depth = i;
1091 ev.peer_cert.subject = buf;
1092 conn->global->event_cb(conn->global->cb_ctx,
1093 TLS_PEER_CERTIFICATE, &ev);
1094 wpabuf_free(cert_buf);
1095 }
1096
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001097 if (i == 0) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001098 if (conn->suffix_match &&
1099 !gnutls_x509_crt_check_hostname(
1100 cert, conn->suffix_match)) {
1101 wpa_printf(MSG_WARNING,
1102 "TLS: Domain suffix match '%s' not found",
1103 conn->suffix_match);
1104 gnutls_tls_fail_event(
1105 conn, &certs[i], i, buf,
1106 "Domain suffix mismatch",
1107 TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
1108 err = GNUTLS_A_BAD_CERTIFICATE;
1109 gnutls_x509_crt_deinit(cert);
1110 os_free(buf);
1111 goto out;
1112 }
1113
1114 /* TODO: validate altsubject_match.
1115 * For now, any such configuration is rejected in
1116 * tls_connection_set_params() */
1117
1118#if GNUTLS_VERSION_NUMBER < 0x030300
1119 /*
1120 * gnutls_certificate_verify_peers() not available, so
1121 * need to check EKU separately.
1122 */
1123 if (!conn->global->server &&
1124 !server_eku_purpose(cert)) {
1125 wpa_printf(MSG_WARNING,
1126 "GnuTLS: No server EKU");
1127 gnutls_tls_fail_event(
1128 conn, &certs[i], i, buf,
1129 "No server EKU",
1130 TLS_FAIL_BAD_CERTIFICATE);
1131 err = GNUTLS_A_BAD_CERTIFICATE;
1132 gnutls_x509_crt_deinit(cert);
1133 os_free(buf);
1134 goto out;
1135 }
1136#endif /* < 3.3.0 */
1137 }
1138
1139 if (!conn->disable_time_checks &&
1140 (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
1141 gnutls_x509_crt_get_activation_time(cert) > now.sec)) {
1142 wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
1143 "not valid at this time",
1144 i + 1, num_certs);
1145 gnutls_tls_fail_event(
1146 conn, &certs[i], i, buf,
1147 "Certificate is not valid at this time",
1148 TLS_FAIL_EXPIRED);
1149 gnutls_x509_crt_deinit(cert);
1150 os_free(buf);
1151 err = GNUTLS_A_CERTIFICATE_EXPIRED;
1152 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001153 }
1154
1155 os_free(buf);
1156
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001157 gnutls_x509_crt_deinit(cert);
1158 }
1159
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001160 if (conn->global->event_cb != NULL)
1161 conn->global->event_cb(conn->global->cb_ctx,
1162 TLS_CERT_CHAIN_SUCCESS, NULL);
1163
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001164 return 0;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001165
1166out:
1167 conn->failed++;
1168 gnutls_alert_send(session, GNUTLS_AL_FATAL, err);
1169 return GNUTLS_E_CERTIFICATE_ERROR;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001170}
1171
1172
1173static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn)
1174{
1175 int res;
1176 struct wpabuf *ad;
1177 wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data");
1178 ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3);
1179 if (ad == NULL)
1180 return NULL;
1181
1182 res = gnutls_record_recv(conn->session, wpabuf_mhead(ad),
1183 wpabuf_size(ad));
1184 wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res);
1185 if (res < 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001186 wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001187 "(%s)", __func__, (int) res,
1188 gnutls_strerror(res));
1189 wpabuf_free(ad);
1190 return NULL;
1191 }
1192
1193 wpabuf_put(ad, res);
1194 wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data",
1195 res);
1196 return ad;
1197}
1198
1199
1200struct wpabuf * tls_connection_handshake(void *tls_ctx,
1201 struct tls_connection *conn,
1202 const struct wpabuf *in_data,
1203 struct wpabuf **appl_data)
1204{
1205 struct tls_global *global = tls_ctx;
1206 struct wpabuf *out_data;
1207 int ret;
1208
1209 if (appl_data)
1210 *appl_data = NULL;
1211
1212 if (in_data && wpabuf_len(in_data) > 0) {
1213 if (conn->pull_buf) {
1214 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
1215 "pull_buf", __func__,
1216 (unsigned long) wpabuf_len(conn->pull_buf));
1217 wpabuf_free(conn->pull_buf);
1218 }
1219 conn->pull_buf = wpabuf_dup(in_data);
1220 if (conn->pull_buf == NULL)
1221 return NULL;
1222 conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
1223 }
1224
1225 ret = gnutls_handshake(conn->session);
1226 if (ret < 0) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001227 gnutls_alert_description_t alert;
1228
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001229 switch (ret) {
1230 case GNUTLS_E_AGAIN:
1231 if (global->server && conn->established &&
1232 conn->push_buf == NULL) {
1233 /* Need to return something to trigger
1234 * completion of EAP-TLS. */
1235 conn->push_buf = wpabuf_alloc(0);
1236 }
1237 break;
1238 case GNUTLS_E_FATAL_ALERT_RECEIVED:
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001239 alert = gnutls_alert_get(conn->session);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001240 wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001241 __func__, gnutls_alert_get_name(alert));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001242 conn->read_alerts++;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001243 if (conn->global->event_cb != NULL) {
1244 union tls_event_data ev;
1245
1246 os_memset(&ev, 0, sizeof(ev));
1247 ev.alert.is_local = 0;
1248 ev.alert.type = gnutls_alert_get_name(alert);
1249 ev.alert.description = ev.alert.type;
1250 conn->global->event_cb(conn->global->cb_ctx,
1251 TLS_ALERT, &ev);
1252 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001253 /* continue */
1254 default:
1255 wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
1256 "-> %s", __func__, gnutls_strerror(ret));
1257 conn->failed++;
1258 }
1259 } else {
1260 size_t size;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001261
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001262 wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001263
1264#if GNUTLS_VERSION_NUMBER >= 0x03010a
1265 {
1266 char *desc;
1267
1268 desc = gnutls_session_get_desc(conn->session);
1269 if (desc) {
1270 wpa_printf(MSG_DEBUG, "GnuTLS: %s", desc);
1271 gnutls_free(desc);
1272 }
1273 }
1274#endif /* GnuTLS 3.1.10 or newer */
1275
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001276 conn->established = 1;
1277 if (conn->push_buf == NULL) {
1278 /* Need to return something to get final TLS ACK. */
1279 conn->push_buf = wpabuf_alloc(0);
1280 }
1281
1282 gnutls_session_get_data(conn->session, NULL, &size);
1283 if (global->session_data == NULL ||
1284 global->session_data_size < size) {
1285 os_free(global->session_data);
1286 global->session_data = os_malloc(size);
1287 }
1288 if (global->session_data) {
1289 global->session_data_size = size;
1290 gnutls_session_get_data(conn->session,
1291 global->session_data,
1292 &global->session_data_size);
1293 }
1294
1295 if (conn->pull_buf && appl_data)
1296 *appl_data = gnutls_get_appl_data(conn);
1297 }
1298
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001299 out_data = conn->push_buf;
1300 conn->push_buf = NULL;
1301 return out_data;
1302}
1303
1304
1305struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
1306 struct tls_connection *conn,
1307 const struct wpabuf *in_data,
1308 struct wpabuf **appl_data)
1309{
1310 return tls_connection_handshake(tls_ctx, conn, in_data, appl_data);
1311}
1312
1313
1314struct wpabuf * tls_connection_encrypt(void *tls_ctx,
1315 struct tls_connection *conn,
1316 const struct wpabuf *in_data)
1317{
1318 ssize_t res;
1319 struct wpabuf *buf;
1320
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001321 res = gnutls_record_send(conn->session, wpabuf_head(in_data),
1322 wpabuf_len(in_data));
1323 if (res < 0) {
1324 wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
1325 __func__, gnutls_strerror(res));
1326 return NULL;
1327 }
1328
1329 buf = conn->push_buf;
1330 conn->push_buf = NULL;
1331 return buf;
1332}
1333
1334
1335struct wpabuf * tls_connection_decrypt(void *tls_ctx,
1336 struct tls_connection *conn,
1337 const struct wpabuf *in_data)
1338{
1339 ssize_t res;
1340 struct wpabuf *out;
1341
1342 if (conn->pull_buf) {
1343 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
1344 "pull_buf", __func__,
1345 (unsigned long) wpabuf_len(conn->pull_buf));
1346 wpabuf_free(conn->pull_buf);
1347 }
1348 conn->pull_buf = wpabuf_dup(in_data);
1349 if (conn->pull_buf == NULL)
1350 return NULL;
1351 conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
1352
1353 /*
1354 * Even though we try to disable TLS compression, it is possible that
1355 * this cannot be done with all TLS libraries. Add extra buffer space
1356 * to handle the possibility of the decrypted data being longer than
1357 * input data.
1358 */
1359 out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
1360 if (out == NULL)
1361 return NULL;
1362
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001363 res = gnutls_record_recv(conn->session, wpabuf_mhead(out),
1364 wpabuf_size(out));
1365 if (res < 0) {
1366 wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
1367 "(%s)", __func__, (int) res, gnutls_strerror(res));
1368 wpabuf_free(out);
1369 return NULL;
1370 }
1371 wpabuf_put(out, res);
1372
1373 return out;
1374}
1375
1376
1377int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
1378{
1379 if (conn == NULL)
1380 return 0;
1381 return gnutls_session_is_resumed(conn->session);
1382}
1383
1384
1385int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
1386 u8 *ciphers)
1387{
1388 /* TODO */
1389 return -1;
1390}
1391
1392
1393int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
1394 char *buf, size_t buflen)
1395{
1396 /* TODO */
1397 buf[0] = '\0';
1398 return 0;
1399}
1400
1401
1402int tls_connection_enable_workaround(void *ssl_ctx,
1403 struct tls_connection *conn)
1404{
1405 gnutls_record_disable_padding(conn->session);
1406 return 0;
1407}
1408
1409
1410int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
1411 int ext_type, const u8 *data,
1412 size_t data_len)
1413{
1414 /* TODO */
1415 return -1;
1416}
1417
1418
1419int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
1420{
1421 if (conn == NULL)
1422 return -1;
1423 return conn->failed;
1424}
1425
1426
1427int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
1428{
1429 if (conn == NULL)
1430 return -1;
1431 return conn->read_alerts;
1432}
1433
1434
1435int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
1436{
1437 if (conn == NULL)
1438 return -1;
1439 return conn->write_alerts;
1440}
1441
1442
1443int tls_connection_get_keyblock_size(void *tls_ctx,
1444 struct tls_connection *conn)
1445{
1446 /* TODO */
1447 return -1;
1448}
1449
1450
1451unsigned int tls_capabilities(void *tls_ctx)
1452{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001453 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001454}
1455
1456
1457int tls_connection_set_session_ticket_cb(void *tls_ctx,
1458 struct tls_connection *conn,
1459 tls_session_ticket_cb cb, void *ctx)
1460{
1461 return -1;
1462}
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001463
1464
1465int tls_get_library_version(char *buf, size_t buf_len)
1466{
1467 return os_snprintf(buf, buf_len, "GnuTLS build=%s run=%s",
1468 GNUTLS_VERSION, gnutls_check_version(NULL));
1469}