blob: f5e31d97589172ccfd458a2e919c552aad94a26d [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * TLS interface functions and an internal TLS implementation
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07003 * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 *
14 * This file interface functions for hostapd/wpa_supplicant to use the
15 * integrated TLSv1 implementation.
16 */
17
18#include "includes.h"
19
20#include "common.h"
21#include "tls.h"
22#include "tls/tlsv1_client.h"
23#include "tls/tlsv1_server.h"
24
25
26static int tls_ref_count = 0;
27
28struct tls_global {
29 int server;
30 struct tlsv1_credentials *server_cred;
31 int check_crl;
32};
33
34struct tls_connection {
35 struct tlsv1_client *client;
36 struct tlsv1_server *server;
37};
38
39
40void * tls_init(const struct tls_config *conf)
41{
42 struct tls_global *global;
43
44 if (tls_ref_count == 0) {
45#ifdef CONFIG_TLS_INTERNAL_CLIENT
46 if (tlsv1_client_global_init())
47 return NULL;
48#endif /* CONFIG_TLS_INTERNAL_CLIENT */
49#ifdef CONFIG_TLS_INTERNAL_SERVER
50 if (tlsv1_server_global_init())
51 return NULL;
52#endif /* CONFIG_TLS_INTERNAL_SERVER */
53 }
54 tls_ref_count++;
55
56 global = os_zalloc(sizeof(*global));
57 if (global == NULL)
58 return NULL;
59
60 return global;
61}
62
63void tls_deinit(void *ssl_ctx)
64{
65 struct tls_global *global = ssl_ctx;
66 tls_ref_count--;
67 if (tls_ref_count == 0) {
68#ifdef CONFIG_TLS_INTERNAL_CLIENT
69 tlsv1_client_global_deinit();
70#endif /* CONFIG_TLS_INTERNAL_CLIENT */
71#ifdef CONFIG_TLS_INTERNAL_SERVER
72 tlsv1_cred_free(global->server_cred);
73 tlsv1_server_global_deinit();
74#endif /* CONFIG_TLS_INTERNAL_SERVER */
75 }
76 os_free(global);
77}
78
79
80int tls_get_errors(void *tls_ctx)
81{
82 return 0;
83}
84
85
86struct tls_connection * tls_connection_init(void *tls_ctx)
87{
88 struct tls_connection *conn;
89 struct tls_global *global = tls_ctx;
90
91 conn = os_zalloc(sizeof(*conn));
92 if (conn == NULL)
93 return NULL;
94
95#ifdef CONFIG_TLS_INTERNAL_CLIENT
96 if (!global->server) {
97 conn->client = tlsv1_client_init();
98 if (conn->client == NULL) {
99 os_free(conn);
100 return NULL;
101 }
102 }
103#endif /* CONFIG_TLS_INTERNAL_CLIENT */
104#ifdef CONFIG_TLS_INTERNAL_SERVER
105 if (global->server) {
106 conn->server = tlsv1_server_init(global->server_cred);
107 if (conn->server == NULL) {
108 os_free(conn);
109 return NULL;
110 }
111 }
112#endif /* CONFIG_TLS_INTERNAL_SERVER */
113
114 return conn;
115}
116
117
118void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
119{
120 if (conn == NULL)
121 return;
122#ifdef CONFIG_TLS_INTERNAL_CLIENT
123 if (conn->client)
124 tlsv1_client_deinit(conn->client);
125#endif /* CONFIG_TLS_INTERNAL_CLIENT */
126#ifdef CONFIG_TLS_INTERNAL_SERVER
127 if (conn->server)
128 tlsv1_server_deinit(conn->server);
129#endif /* CONFIG_TLS_INTERNAL_SERVER */
130 os_free(conn);
131}
132
133
134int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
135{
136#ifdef CONFIG_TLS_INTERNAL_CLIENT
137 if (conn->client)
138 return tlsv1_client_established(conn->client);
139#endif /* CONFIG_TLS_INTERNAL_CLIENT */
140#ifdef CONFIG_TLS_INTERNAL_SERVER
141 if (conn->server)
142 return tlsv1_server_established(conn->server);
143#endif /* CONFIG_TLS_INTERNAL_SERVER */
144 return 0;
145}
146
147
148int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
149{
150#ifdef CONFIG_TLS_INTERNAL_CLIENT
151 if (conn->client)
152 return tlsv1_client_shutdown(conn->client);
153#endif /* CONFIG_TLS_INTERNAL_CLIENT */
154#ifdef CONFIG_TLS_INTERNAL_SERVER
155 if (conn->server)
156 return tlsv1_server_shutdown(conn->server);
157#endif /* CONFIG_TLS_INTERNAL_SERVER */
158 return -1;
159}
160
161
162int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
163 const struct tls_connection_params *params)
164{
165#ifdef CONFIG_TLS_INTERNAL_CLIENT
166 struct tlsv1_credentials *cred;
167
168 if (conn->client == NULL)
169 return -1;
170
171 cred = tlsv1_cred_alloc();
172 if (cred == NULL)
173 return -1;
174
175 if (tlsv1_set_ca_cert(cred, params->ca_cert,
176 params->ca_cert_blob, params->ca_cert_blob_len,
177 params->ca_path)) {
178 wpa_printf(MSG_INFO, "TLS: Failed to configure trusted CA "
179 "certificates");
180 tlsv1_cred_free(cred);
181 return -1;
182 }
183
184 if (tlsv1_set_cert(cred, params->client_cert,
185 params->client_cert_blob,
186 params->client_cert_blob_len)) {
187 wpa_printf(MSG_INFO, "TLS: Failed to configure client "
188 "certificate");
189 tlsv1_cred_free(cred);
190 return -1;
191 }
192
193 if (tlsv1_set_private_key(cred, params->private_key,
194 params->private_key_passwd,
195 params->private_key_blob,
196 params->private_key_blob_len)) {
197 wpa_printf(MSG_INFO, "TLS: Failed to load private key");
198 tlsv1_cred_free(cred);
199 return -1;
200 }
201
202 if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob,
203 params->dh_blob_len)) {
204 wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters");
205 tlsv1_cred_free(cred);
206 return -1;
207 }
208
209 if (tlsv1_client_set_cred(conn->client, cred) < 0) {
210 tlsv1_cred_free(cred);
211 return -1;
212 }
213
Dmitry Shmidtc55524a2011-07-07 11:18:38 -0700214 tlsv1_client_set_time_checks(
215 conn->client, !(params->flags & TLS_CONN_DISABLE_TIME_CHECKS));
216
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700217 return 0;
218#else /* CONFIG_TLS_INTERNAL_CLIENT */
219 return -1;
220#endif /* CONFIG_TLS_INTERNAL_CLIENT */
221}
222
223
224int tls_global_set_params(void *tls_ctx,
225 const struct tls_connection_params *params)
226{
227#ifdef CONFIG_TLS_INTERNAL_SERVER
228 struct tls_global *global = tls_ctx;
229 struct tlsv1_credentials *cred;
230
231 /* Currently, global parameters are only set when running in server
232 * mode. */
233 global->server = 1;
234 tlsv1_cred_free(global->server_cred);
235 global->server_cred = cred = tlsv1_cred_alloc();
236 if (cred == NULL)
237 return -1;
238
239 if (tlsv1_set_ca_cert(cred, params->ca_cert, params->ca_cert_blob,
240 params->ca_cert_blob_len, params->ca_path)) {
241 wpa_printf(MSG_INFO, "TLS: Failed to configure trusted CA "
242 "certificates");
243 return -1;
244 }
245
246 if (tlsv1_set_cert(cred, params->client_cert, params->client_cert_blob,
247 params->client_cert_blob_len)) {
248 wpa_printf(MSG_INFO, "TLS: Failed to configure server "
249 "certificate");
250 return -1;
251 }
252
253 if (tlsv1_set_private_key(cred, params->private_key,
254 params->private_key_passwd,
255 params->private_key_blob,
256 params->private_key_blob_len)) {
257 wpa_printf(MSG_INFO, "TLS: Failed to load private key");
258 return -1;
259 }
260
261 if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob,
262 params->dh_blob_len)) {
263 wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters");
264 return -1;
265 }
266
267 return 0;
268#else /* CONFIG_TLS_INTERNAL_SERVER */
269 return -1;
270#endif /* CONFIG_TLS_INTERNAL_SERVER */
271}
272
273
274int tls_global_set_verify(void *tls_ctx, int check_crl)
275{
276 struct tls_global *global = tls_ctx;
277 global->check_crl = check_crl;
278 return 0;
279}
280
281
282int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
283 int verify_peer)
284{
285#ifdef CONFIG_TLS_INTERNAL_SERVER
286 if (conn->server)
287 return tlsv1_server_set_verify(conn->server, verify_peer);
288#endif /* CONFIG_TLS_INTERNAL_SERVER */
289 return -1;
290}
291
292
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700293int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
294 struct tls_keys *keys)
295{
296#ifdef CONFIG_TLS_INTERNAL_CLIENT
297 if (conn->client)
298 return tlsv1_client_get_keys(conn->client, keys);
299#endif /* CONFIG_TLS_INTERNAL_CLIENT */
300#ifdef CONFIG_TLS_INTERNAL_SERVER
301 if (conn->server)
302 return tlsv1_server_get_keys(conn->server, keys);
303#endif /* CONFIG_TLS_INTERNAL_SERVER */
304 return -1;
305}
306
307
308int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
309 const char *label, int server_random_first,
310 u8 *out, size_t out_len)
311{
312#ifdef CONFIG_TLS_INTERNAL_CLIENT
313 if (conn->client) {
314 return tlsv1_client_prf(conn->client, label,
315 server_random_first,
316 out, out_len);
317 }
318#endif /* CONFIG_TLS_INTERNAL_CLIENT */
319#ifdef CONFIG_TLS_INTERNAL_SERVER
320 if (conn->server) {
321 return tlsv1_server_prf(conn->server, label,
322 server_random_first,
323 out, out_len);
324 }
325#endif /* CONFIG_TLS_INTERNAL_SERVER */
326 return -1;
327}
328
329
330struct wpabuf * tls_connection_handshake(void *tls_ctx,
331 struct tls_connection *conn,
332 const struct wpabuf *in_data,
333 struct wpabuf **appl_data)
334{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800335 return tls_connection_handshake2(tls_ctx, conn, in_data, appl_data,
336 NULL);
337}
338
339
340struct wpabuf * tls_connection_handshake2(void *tls_ctx,
341 struct tls_connection *conn,
342 const struct wpabuf *in_data,
343 struct wpabuf **appl_data,
344 int *need_more_data)
345{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700346#ifdef CONFIG_TLS_INTERNAL_CLIENT
347 u8 *res, *ad;
348 size_t res_len, ad_len;
349 struct wpabuf *out;
350
351 if (conn->client == NULL)
352 return NULL;
353
354 ad = NULL;
355 res = tlsv1_client_handshake(conn->client,
356 in_data ? wpabuf_head(in_data) : NULL,
357 in_data ? wpabuf_len(in_data) : 0,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800358 &res_len, &ad, &ad_len, need_more_data);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700359 if (res == NULL)
360 return NULL;
361 out = wpabuf_alloc_ext_data(res, res_len);
362 if (out == NULL) {
363 os_free(res);
364 os_free(ad);
365 return NULL;
366 }
367 if (appl_data) {
368 if (ad) {
369 *appl_data = wpabuf_alloc_ext_data(ad, ad_len);
370 if (*appl_data == NULL)
371 os_free(ad);
372 } else
373 *appl_data = NULL;
374 } else
375 os_free(ad);
376
377 return out;
378#else /* CONFIG_TLS_INTERNAL_CLIENT */
379 return NULL;
380#endif /* CONFIG_TLS_INTERNAL_CLIENT */
381}
382
383
384struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
385 struct tls_connection *conn,
386 const struct wpabuf *in_data,
387 struct wpabuf **appl_data)
388{
389#ifdef CONFIG_TLS_INTERNAL_SERVER
390 u8 *res;
391 size_t res_len;
392 struct wpabuf *out;
393
394 if (conn->server == NULL)
395 return NULL;
396
397 if (appl_data)
398 *appl_data = NULL;
399
400 res = tlsv1_server_handshake(conn->server, wpabuf_head(in_data),
401 wpabuf_len(in_data), &res_len);
402 if (res == NULL && tlsv1_server_established(conn->server))
403 return wpabuf_alloc(0);
404 if (res == NULL)
405 return NULL;
406 out = wpabuf_alloc_ext_data(res, res_len);
407 if (out == NULL) {
408 os_free(res);
409 return NULL;
410 }
411
412 return out;
413#else /* CONFIG_TLS_INTERNAL_SERVER */
414 return NULL;
415#endif /* CONFIG_TLS_INTERNAL_SERVER */
416}
417
418
419struct wpabuf * tls_connection_encrypt(void *tls_ctx,
420 struct tls_connection *conn,
421 const struct wpabuf *in_data)
422{
423#ifdef CONFIG_TLS_INTERNAL_CLIENT
424 if (conn->client) {
425 struct wpabuf *buf;
426 int res;
427 buf = wpabuf_alloc(wpabuf_len(in_data) + 300);
428 if (buf == NULL)
429 return NULL;
430 res = tlsv1_client_encrypt(conn->client, wpabuf_head(in_data),
431 wpabuf_len(in_data),
432 wpabuf_mhead(buf),
433 wpabuf_size(buf));
434 if (res < 0) {
435 wpabuf_free(buf);
436 return NULL;
437 }
438 wpabuf_put(buf, res);
439 return buf;
440 }
441#endif /* CONFIG_TLS_INTERNAL_CLIENT */
442#ifdef CONFIG_TLS_INTERNAL_SERVER
443 if (conn->server) {
444 struct wpabuf *buf;
445 int res;
446 buf = wpabuf_alloc(wpabuf_len(in_data) + 300);
447 if (buf == NULL)
448 return NULL;
449 res = tlsv1_server_encrypt(conn->server, wpabuf_head(in_data),
450 wpabuf_len(in_data),
451 wpabuf_mhead(buf),
452 wpabuf_size(buf));
453 if (res < 0) {
454 wpabuf_free(buf);
455 return NULL;
456 }
457 wpabuf_put(buf, res);
458 return buf;
459 }
460#endif /* CONFIG_TLS_INTERNAL_SERVER */
461 return NULL;
462}
463
464
465struct wpabuf * tls_connection_decrypt(void *tls_ctx,
466 struct tls_connection *conn,
467 const struct wpabuf *in_data)
468{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800469 return tls_connection_decrypt2(tls_ctx, conn, in_data, NULL);
470}
471
472
473struct wpabuf * tls_connection_decrypt2(void *tls_ctx,
474 struct tls_connection *conn,
475 const struct wpabuf *in_data,
476 int *need_more_data)
477{
478 if (need_more_data)
479 *need_more_data = 0;
480
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700481#ifdef CONFIG_TLS_INTERNAL_CLIENT
482 if (conn->client) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800483 return tlsv1_client_decrypt(conn->client, wpabuf_head(in_data),
484 wpabuf_len(in_data),
485 need_more_data);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700486 }
487#endif /* CONFIG_TLS_INTERNAL_CLIENT */
488#ifdef CONFIG_TLS_INTERNAL_SERVER
489 if (conn->server) {
490 struct wpabuf *buf;
491 int res;
492 buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
493 if (buf == NULL)
494 return NULL;
495 res = tlsv1_server_decrypt(conn->server, wpabuf_head(in_data),
496 wpabuf_len(in_data),
497 wpabuf_mhead(buf),
498 wpabuf_size(buf));
499 if (res < 0) {
500 wpabuf_free(buf);
501 return NULL;
502 }
503 wpabuf_put(buf, res);
504 return buf;
505 }
506#endif /* CONFIG_TLS_INTERNAL_SERVER */
507 return NULL;
508}
509
510
511int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
512{
513#ifdef CONFIG_TLS_INTERNAL_CLIENT
514 if (conn->client)
515 return tlsv1_client_resumed(conn->client);
516#endif /* CONFIG_TLS_INTERNAL_CLIENT */
517#ifdef CONFIG_TLS_INTERNAL_SERVER
518 if (conn->server)
519 return tlsv1_server_resumed(conn->server);
520#endif /* CONFIG_TLS_INTERNAL_SERVER */
521 return -1;
522}
523
524
525int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
526 u8 *ciphers)
527{
528#ifdef CONFIG_TLS_INTERNAL_CLIENT
529 if (conn->client)
530 return tlsv1_client_set_cipher_list(conn->client, ciphers);
531#endif /* CONFIG_TLS_INTERNAL_CLIENT */
532#ifdef CONFIG_TLS_INTERNAL_SERVER
533 if (conn->server)
534 return tlsv1_server_set_cipher_list(conn->server, ciphers);
535#endif /* CONFIG_TLS_INTERNAL_SERVER */
536 return -1;
537}
538
539
540int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
541 char *buf, size_t buflen)
542{
543 if (conn == NULL)
544 return -1;
545#ifdef CONFIG_TLS_INTERNAL_CLIENT
546 if (conn->client)
547 return tlsv1_client_get_cipher(conn->client, buf, buflen);
548#endif /* CONFIG_TLS_INTERNAL_CLIENT */
549#ifdef CONFIG_TLS_INTERNAL_SERVER
550 if (conn->server)
551 return tlsv1_server_get_cipher(conn->server, buf, buflen);
552#endif /* CONFIG_TLS_INTERNAL_SERVER */
553 return -1;
554}
555
556
557int tls_connection_enable_workaround(void *tls_ctx,
558 struct tls_connection *conn)
559{
560 return -1;
561}
562
563
564int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
565 int ext_type, const u8 *data,
566 size_t data_len)
567{
568#ifdef CONFIG_TLS_INTERNAL_CLIENT
569 if (conn->client) {
570 return tlsv1_client_hello_ext(conn->client, ext_type,
571 data, data_len);
572 }
573#endif /* CONFIG_TLS_INTERNAL_CLIENT */
574 return -1;
575}
576
577
578int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
579{
580 return 0;
581}
582
583
584int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
585{
586 return 0;
587}
588
589
590int tls_connection_get_write_alerts(void *tls_ctx,
591 struct tls_connection *conn)
592{
593 return 0;
594}
595
596
597int tls_connection_get_keyblock_size(void *tls_ctx,
598 struct tls_connection *conn)
599{
600#ifdef CONFIG_TLS_INTERNAL_CLIENT
601 if (conn->client)
602 return tlsv1_client_get_keyblock_size(conn->client);
603#endif /* CONFIG_TLS_INTERNAL_CLIENT */
604#ifdef CONFIG_TLS_INTERNAL_SERVER
605 if (conn->server)
606 return tlsv1_server_get_keyblock_size(conn->server);
607#endif /* CONFIG_TLS_INTERNAL_SERVER */
608 return -1;
609}
610
611
612unsigned int tls_capabilities(void *tls_ctx)
613{
614 return 0;
615}
616
617
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700618int tls_connection_set_session_ticket_cb(void *tls_ctx,
619 struct tls_connection *conn,
620 tls_session_ticket_cb cb,
621 void *ctx)
622{
623#ifdef CONFIG_TLS_INTERNAL_CLIENT
624 if (conn->client) {
625 tlsv1_client_set_session_ticket_cb(conn->client, cb, ctx);
626 return 0;
627 }
628#endif /* CONFIG_TLS_INTERNAL_CLIENT */
629#ifdef CONFIG_TLS_INTERNAL_SERVER
630 if (conn->server) {
631 tlsv1_server_set_session_ticket_cb(conn->server, cb, ctx);
632 return 0;
633 }
634#endif /* CONFIG_TLS_INTERNAL_SERVER */
635 return -1;
636}