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