eap_server_tls_common.c revision 1f69aa52ea2e0a73ac502565df8c666ee49cab6a
1/*
2 * EAP-TLS/PEAP/TTLS/FAST server common functions
3 * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
4 *
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
15#include "includes.h"
16
17#include "common.h"
18#include "crypto/sha1.h"
19#include "crypto/tls.h"
20#include "eap_i.h"
21#include "eap_tls_common.h"
22
23
24static void eap_server_tls_free_in_buf(struct eap_ssl_data *data);
25
26
27int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
28			    int verify_peer)
29{
30	data->eap = sm;
31	data->phase2 = sm->init_phase2;
32
33	data->conn = tls_connection_init(sm->ssl_ctx);
34	if (data->conn == NULL) {
35		wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
36			   "connection");
37		return -1;
38	}
39
40	if (tls_connection_set_verify(sm->ssl_ctx, data->conn, verify_peer)) {
41		wpa_printf(MSG_INFO, "SSL: Failed to configure verification "
42			   "of TLS peer certificate");
43		tls_connection_deinit(sm->ssl_ctx, data->conn);
44		data->conn = NULL;
45		return -1;
46	}
47
48	data->tls_out_limit = sm->fragment_size > 0 ? sm->fragment_size : 1398;
49	if (data->phase2) {
50		/* Limit the fragment size in the inner TLS authentication
51		 * since the outer authentication with EAP-PEAP does not yet
52		 * support fragmentation */
53		if (data->tls_out_limit > 100)
54			data->tls_out_limit -= 100;
55	}
56	return 0;
57}
58
59
60void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
61{
62	tls_connection_deinit(sm->ssl_ctx, data->conn);
63	eap_server_tls_free_in_buf(data);
64	wpabuf_free(data->tls_out);
65	data->tls_out = NULL;
66}
67
68
69u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
70			       char *label, size_t len)
71{
72	struct tls_keys keys;
73	u8 *rnd = NULL, *out;
74
75	out = os_malloc(len);
76	if (out == NULL)
77		return NULL;
78
79	if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) ==
80	    0)
81		return out;
82
83	if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
84		goto fail;
85
86	if (keys.client_random == NULL || keys.server_random == NULL ||
87	    keys.master_key == NULL)
88		goto fail;
89
90	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
91	if (rnd == NULL)
92		goto fail;
93	os_memcpy(rnd, keys.client_random, keys.client_random_len);
94	os_memcpy(rnd + keys.client_random_len, keys.server_random,
95		  keys.server_random_len);
96
97	if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len,
98			     label, rnd, keys.client_random_len +
99			     keys.server_random_len, out, len))
100		goto fail;
101
102	os_free(rnd);
103	return out;
104
105fail:
106	os_free(out);
107	os_free(rnd);
108	return NULL;
109}
110
111
112struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data,
113					 int eap_type, int version, u8 id)
114{
115	struct wpabuf *req;
116	u8 flags;
117	size_t send_len, plen;
118
119	wpa_printf(MSG_DEBUG, "SSL: Generating Request");
120	if (data->tls_out == NULL) {
121		wpa_printf(MSG_ERROR, "SSL: tls_out NULL in %s", __func__);
122		return NULL;
123	}
124
125	flags = version;
126	send_len = wpabuf_len(data->tls_out) - data->tls_out_pos;
127	if (1 + send_len > data->tls_out_limit) {
128		send_len = data->tls_out_limit - 1;
129		flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;
130		if (data->tls_out_pos == 0) {
131			flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED;
132			send_len -= 4;
133		}
134	}
135
136	plen = 1 + send_len;
137	if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)
138		plen += 4;
139
140	req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, plen,
141			    EAP_CODE_REQUEST, id);
142	if (req == NULL)
143		return NULL;
144
145	wpabuf_put_u8(req, flags); /* Flags */
146	if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)
147		wpabuf_put_be32(req, wpabuf_len(data->tls_out));
148
149	wpabuf_put_data(req, wpabuf_head_u8(data->tls_out) + data->tls_out_pos,
150			send_len);
151	data->tls_out_pos += send_len;
152
153	if (data->tls_out_pos == wpabuf_len(data->tls_out)) {
154		wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes "
155			   "(message sent completely)",
156			   (unsigned long) send_len);
157		wpabuf_free(data->tls_out);
158		data->tls_out = NULL;
159		data->tls_out_pos = 0;
160		data->state = MSG;
161	} else {
162		wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes "
163			   "(%lu more to send)", (unsigned long) send_len,
164			   (unsigned long) wpabuf_len(data->tls_out) -
165			   data->tls_out_pos);
166		data->state = WAIT_FRAG_ACK;
167	}
168
169	return req;
170}
171
172
173struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version)
174{
175	struct wpabuf *req;
176
177	req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, 1, EAP_CODE_REQUEST,
178			    id);
179	if (req == NULL)
180		return NULL;
181	wpa_printf(MSG_DEBUG, "SSL: Building ACK");
182	wpabuf_put_u8(req, version); /* Flags */
183	return req;
184}
185
186
187static int eap_server_tls_process_cont(struct eap_ssl_data *data,
188				       const u8 *buf, size_t len)
189{
190	/* Process continuation of a pending message */
191	if (len > wpabuf_tailroom(data->tls_in)) {
192		wpa_printf(MSG_DEBUG, "SSL: Fragment overflow");
193		return -1;
194	}
195
196	wpabuf_put_data(data->tls_in, buf, len);
197	wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes, waiting for %lu "
198		   "bytes more", (unsigned long) len,
199		   (unsigned long) wpabuf_tailroom(data->tls_in));
200
201	return 0;
202}
203
204
205static int eap_server_tls_process_fragment(struct eap_ssl_data *data,
206					   u8 flags, u32 message_length,
207					   const u8 *buf, size_t len)
208{
209	/* Process a fragment that is not the last one of the message */
210	if (data->tls_in == NULL && !(flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)) {
211		wpa_printf(MSG_DEBUG, "SSL: No Message Length field in a "
212			   "fragmented packet");
213		return -1;
214	}
215
216	if (data->tls_in == NULL) {
217		/* First fragment of the message */
218
219		/* Limit length to avoid rogue peers from causing large
220		 * memory allocations. */
221		if (message_length > 65536) {
222			wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size"
223				   " over 64 kB)");
224			return -1;
225		}
226
227		data->tls_in = wpabuf_alloc(message_length);
228		if (data->tls_in == NULL) {
229			wpa_printf(MSG_DEBUG, "SSL: No memory for message");
230			return -1;
231		}
232		wpabuf_put_data(data->tls_in, buf, len);
233		wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes in first "
234			   "fragment, waiting for %lu bytes more",
235			   (unsigned long) len,
236			   (unsigned long) wpabuf_tailroom(data->tls_in));
237	}
238
239	return 0;
240}
241
242
243int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data)
244{
245	if (data->tls_out) {
246		/* This should not happen.. */
247		wpa_printf(MSG_INFO, "SSL: pending tls_out data when "
248			   "processing new message");
249		wpabuf_free(data->tls_out);
250		WPA_ASSERT(data->tls_out == NULL);
251	}
252
253	data->tls_out = tls_connection_server_handshake(sm->ssl_ctx,
254							data->conn,
255							data->tls_in, NULL);
256	if (data->tls_out == NULL) {
257		wpa_printf(MSG_INFO, "SSL: TLS processing failed");
258		return -1;
259	}
260	if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) {
261		/* TLS processing has failed - return error */
262		wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to "
263			   "report error");
264		return -1;
265	}
266
267	return 0;
268}
269
270
271static int eap_server_tls_reassemble(struct eap_ssl_data *data, u8 flags,
272				     const u8 **pos, size_t *left)
273{
274	unsigned int tls_msg_len = 0;
275	const u8 *end = *pos + *left;
276
277	if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
278		if (*left < 4) {
279			wpa_printf(MSG_INFO, "SSL: Short frame with TLS "
280				   "length");
281			return -1;
282		}
283		tls_msg_len = WPA_GET_BE32(*pos);
284		wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d",
285			   tls_msg_len);
286		*pos += 4;
287		*left -= 4;
288	}
289
290	wpa_printf(MSG_DEBUG, "SSL: Received packet: Flags 0x%x "
291		   "Message Length %u", flags, tls_msg_len);
292
293	if (data->state == WAIT_FRAG_ACK) {
294		if (*left != 0) {
295			wpa_printf(MSG_DEBUG, "SSL: Unexpected payload in "
296				   "WAIT_FRAG_ACK state");
297			return -1;
298		}
299		wpa_printf(MSG_DEBUG, "SSL: Fragment acknowledged");
300		return 1;
301	}
302
303	if (data->tls_in &&
304	    eap_server_tls_process_cont(data, *pos, end - *pos) < 0)
305		return -1;
306
307	if (flags & EAP_TLS_FLAGS_MORE_FRAGMENTS) {
308		if (eap_server_tls_process_fragment(data, flags, tls_msg_len,
309						    *pos, end - *pos) < 0)
310			return -1;
311
312		data->state = FRAG_ACK;
313		return 1;
314	}
315
316	if (data->state == FRAG_ACK) {
317		wpa_printf(MSG_DEBUG, "SSL: All fragments received");
318		data->state = MSG;
319	}
320
321	if (data->tls_in == NULL) {
322		/* Wrap unfragmented messages as wpabuf without extra copy */
323		wpabuf_set(&data->tmpbuf, *pos, end - *pos);
324		data->tls_in = &data->tmpbuf;
325	}
326
327	return 0;
328}
329
330
331static void eap_server_tls_free_in_buf(struct eap_ssl_data *data)
332{
333	if (data->tls_in != &data->tmpbuf)
334		wpabuf_free(data->tls_in);
335	data->tls_in = NULL;
336}
337
338
339struct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm,
340				       struct eap_ssl_data *data,
341				       const struct wpabuf *plain)
342{
343	struct wpabuf *buf;
344
345	buf = tls_connection_encrypt(sm->ssl_ctx, data->conn,
346				     plain);
347	if (buf == NULL) {
348		wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 data");
349		return NULL;
350	}
351
352	return buf;
353}
354
355
356int eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data,
357			   struct wpabuf *respData, void *priv, int eap_type,
358			   int (*proc_version)(struct eap_sm *sm, void *priv,
359					       int peer_version),
360			   void (*proc_msg)(struct eap_sm *sm, void *priv,
361					    const struct wpabuf *respData))
362{
363	const u8 *pos;
364	u8 flags;
365	size_t left;
366	int ret, res = 0;
367
368	pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, respData, &left);
369	if (pos == NULL || left < 1)
370		return 0; /* Should not happen - frame already validated */
371	flags = *pos++;
372	left--;
373	wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - Flags 0x%02x",
374		   (unsigned long) wpabuf_len(respData), flags);
375
376	if (proc_version &&
377	    proc_version(sm, priv, flags & EAP_TLS_VERSION_MASK) < 0)
378		return -1;
379
380	ret = eap_server_tls_reassemble(data, flags, &pos, &left);
381	if (ret < 0) {
382		res = -1;
383		goto done;
384	} else if (ret == 1)
385		return 0;
386
387	if (proc_msg)
388		proc_msg(sm, priv, respData);
389
390	if (tls_connection_get_write_alerts(sm->ssl_ctx, data->conn) > 1) {
391		wpa_printf(MSG_INFO, "SSL: Locally detected fatal error in "
392			   "TLS processing");
393		res = -1;
394	}
395
396done:
397	eap_server_tls_free_in_buf(data);
398
399	return res;
400}
401