Branch data Line data Source code
1 : : /*
2 : : * EAP peer method: EAP-TNC (Trusted Network Connect)
3 : : * Copyright (c) 2007, 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 : :
9 : : #include "includes.h"
10 : :
11 : : #include "common.h"
12 : : #include "eap_i.h"
13 : : #include "tncc.h"
14 : :
15 : :
16 : : struct eap_tnc_data {
17 : : enum { WAIT_START, PROC_MSG, WAIT_FRAG_ACK, DONE, FAIL } state;
18 : : struct tncc_data *tncc;
19 : : struct wpabuf *in_buf;
20 : : struct wpabuf *out_buf;
21 : : size_t out_used;
22 : : size_t fragment_size;
23 : : };
24 : :
25 : :
26 : : /* EAP-TNC Flags */
27 : : #define EAP_TNC_FLAGS_LENGTH_INCLUDED 0x80
28 : : #define EAP_TNC_FLAGS_MORE_FRAGMENTS 0x40
29 : : #define EAP_TNC_FLAGS_START 0x20
30 : : #define EAP_TNC_VERSION_MASK 0x07
31 : :
32 : : #define EAP_TNC_VERSION 1
33 : :
34 : :
35 : 0 : static void * eap_tnc_init(struct eap_sm *sm)
36 : : {
37 : : struct eap_tnc_data *data;
38 : :
39 : 0 : data = os_zalloc(sizeof(*data));
40 [ # # ]: 0 : if (data == NULL)
41 : 0 : return NULL;
42 : 0 : data->state = WAIT_START;
43 : 0 : data->fragment_size = 1300;
44 : 0 : data->tncc = tncc_init();
45 [ # # ]: 0 : if (data->tncc == NULL) {
46 : 0 : os_free(data);
47 : 0 : return NULL;
48 : : }
49 : :
50 : 0 : return data;
51 : : }
52 : :
53 : :
54 : 0 : static void eap_tnc_deinit(struct eap_sm *sm, void *priv)
55 : : {
56 : 0 : struct eap_tnc_data *data = priv;
57 : :
58 : 0 : wpabuf_free(data->in_buf);
59 : 0 : wpabuf_free(data->out_buf);
60 : 0 : tncc_deinit(data->tncc);
61 : 0 : os_free(data);
62 : 0 : }
63 : :
64 : :
65 : 0 : static struct wpabuf * eap_tnc_build_frag_ack(u8 id, u8 code)
66 : : {
67 : : struct wpabuf *msg;
68 : :
69 : 0 : msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, code, id);
70 [ # # ]: 0 : if (msg == NULL) {
71 : 0 : wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory "
72 : : "for fragment ack");
73 : 0 : return NULL;
74 : : }
75 : 0 : wpabuf_put_u8(msg, EAP_TNC_VERSION); /* Flags */
76 : :
77 : 0 : wpa_printf(MSG_DEBUG, "EAP-TNC: Send fragment ack");
78 : :
79 : 0 : return msg;
80 : : }
81 : :
82 : :
83 : 0 : static struct wpabuf * eap_tnc_build_msg(struct eap_tnc_data *data,
84 : : struct eap_method_ret *ret, u8 id)
85 : : {
86 : : struct wpabuf *resp;
87 : : u8 flags;
88 : : size_t send_len, plen;
89 : :
90 : 0 : ret->ignore = FALSE;
91 : 0 : wpa_printf(MSG_DEBUG, "EAP-TNC: Generating Response");
92 : 0 : ret->allowNotifications = TRUE;
93 : :
94 : 0 : flags = EAP_TNC_VERSION;
95 : 0 : send_len = wpabuf_len(data->out_buf) - data->out_used;
96 [ # # ]: 0 : if (1 + send_len > data->fragment_size) {
97 : 0 : send_len = data->fragment_size - 1;
98 : 0 : flags |= EAP_TNC_FLAGS_MORE_FRAGMENTS;
99 [ # # ]: 0 : if (data->out_used == 0) {
100 : 0 : flags |= EAP_TNC_FLAGS_LENGTH_INCLUDED;
101 : 0 : send_len -= 4;
102 : : }
103 : : }
104 : :
105 : 0 : plen = 1 + send_len;
106 [ # # ]: 0 : if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
107 : 0 : plen += 4;
108 : 0 : resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, plen,
109 : : EAP_CODE_RESPONSE, id);
110 [ # # ]: 0 : if (resp == NULL)
111 : 0 : return NULL;
112 : :
113 : 0 : wpabuf_put_u8(resp, flags); /* Flags */
114 [ # # ]: 0 : if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
115 : 0 : wpabuf_put_be32(resp, wpabuf_len(data->out_buf));
116 : :
117 : 0 : wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used,
118 : : send_len);
119 : 0 : data->out_used += send_len;
120 : :
121 : 0 : ret->methodState = METHOD_MAY_CONT;
122 : 0 : ret->decision = DECISION_FAIL;
123 : :
124 [ # # ]: 0 : if (data->out_used == wpabuf_len(data->out_buf)) {
125 : 0 : wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
126 : : "(message sent completely)",
127 : : (unsigned long) send_len);
128 : 0 : wpabuf_free(data->out_buf);
129 : 0 : data->out_buf = NULL;
130 : 0 : data->out_used = 0;
131 : : } else {
132 : 0 : wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
133 : : "(%lu more to send)", (unsigned long) send_len,
134 : 0 : (unsigned long) wpabuf_len(data->out_buf) -
135 : 0 : data->out_used);
136 : 0 : data->state = WAIT_FRAG_ACK;
137 : : }
138 : :
139 : 0 : return resp;
140 : : }
141 : :
142 : :
143 : 0 : static int eap_tnc_process_cont(struct eap_tnc_data *data,
144 : : const u8 *buf, size_t len)
145 : : {
146 : : /* Process continuation of a pending message */
147 [ # # ]: 0 : if (len > wpabuf_tailroom(data->in_buf)) {
148 : 0 : wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment overflow");
149 : 0 : data->state = FAIL;
150 : 0 : return -1;
151 : : }
152 : :
153 : 0 : wpabuf_put_data(data->in_buf, buf, len);
154 : 0 : wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes, waiting for "
155 : : "%lu bytes more", (unsigned long) len,
156 : 0 : (unsigned long) wpabuf_tailroom(data->in_buf));
157 : :
158 : 0 : return 0;
159 : : }
160 : :
161 : :
162 : 0 : static struct wpabuf * eap_tnc_process_fragment(struct eap_tnc_data *data,
163 : : struct eap_method_ret *ret,
164 : : u8 id, u8 flags,
165 : : u32 message_length,
166 : : const u8 *buf, size_t len)
167 : : {
168 : : /* Process a fragment that is not the last one of the message */
169 [ # # ][ # # ]: 0 : if (data->in_buf == NULL && !(flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)) {
170 : 0 : wpa_printf(MSG_DEBUG, "EAP-TNC: No Message Length field in a "
171 : : "fragmented packet");
172 : 0 : ret->ignore = TRUE;
173 : 0 : return NULL;
174 : : }
175 : :
176 [ # # ]: 0 : if (data->in_buf == NULL) {
177 : : /* First fragment of the message */
178 : 0 : data->in_buf = wpabuf_alloc(message_length);
179 [ # # ]: 0 : if (data->in_buf == NULL) {
180 : 0 : wpa_printf(MSG_DEBUG, "EAP-TNC: No memory for "
181 : : "message");
182 : 0 : ret->ignore = TRUE;
183 : 0 : return NULL;
184 : : }
185 : 0 : wpabuf_put_data(data->in_buf, buf, len);
186 : 0 : wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes in first "
187 : : "fragment, waiting for %lu bytes more",
188 : : (unsigned long) len,
189 : 0 : (unsigned long) wpabuf_tailroom(data->in_buf));
190 : : }
191 : :
192 : 0 : return eap_tnc_build_frag_ack(id, EAP_CODE_RESPONSE);
193 : : }
194 : :
195 : :
196 : 0 : static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
197 : : struct eap_method_ret *ret,
198 : : const struct wpabuf *reqData)
199 : : {
200 : 0 : struct eap_tnc_data *data = priv;
201 : : struct wpabuf *resp;
202 : : const u8 *pos, *end;
203 : : u8 *rpos, *rpos1;
204 : : size_t len, rlen;
205 : : size_t imc_len;
206 : : char *start_buf, *end_buf;
207 : : size_t start_len, end_len;
208 : 0 : int tncs_done = 0;
209 : : u8 flags, id;
210 : 0 : u32 message_length = 0;
211 : : struct wpabuf tmpbuf;
212 : :
213 : 0 : pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, reqData, &len);
214 [ # # ]: 0 : if (pos == NULL) {
215 : 0 : wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame (pos=%p len=%lu)",
216 : : pos, (unsigned long) len);
217 : 0 : ret->ignore = TRUE;
218 : 0 : return NULL;
219 : : }
220 : :
221 : 0 : id = eap_get_id(reqData);
222 : :
223 : 0 : end = pos + len;
224 : :
225 [ # # ]: 0 : if (len == 0)
226 : 0 : flags = 0; /* fragment ack */
227 : : else
228 : 0 : flags = *pos++;
229 : :
230 [ # # ][ # # ]: 0 : if (len > 0 && (flags & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) {
231 : 0 : wpa_printf(MSG_DEBUG, "EAP-TNC: Unsupported version %d",
232 : : flags & EAP_TNC_VERSION_MASK);
233 : 0 : ret->ignore = TRUE;
234 : 0 : return NULL;
235 : : }
236 : :
237 [ # # ]: 0 : if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) {
238 [ # # ]: 0 : if (end - pos < 4) {
239 : 0 : wpa_printf(MSG_DEBUG, "EAP-TNC: Message underflow");
240 : 0 : ret->ignore = TRUE;
241 : 0 : return NULL;
242 : : }
243 : 0 : message_length = WPA_GET_BE32(pos);
244 : 0 : pos += 4;
245 : :
246 [ # # ]: 0 : if (message_length < (u32) (end - pos)) {
247 : 0 : wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message "
248 : : "Length (%d; %ld remaining in this msg)",
249 : : message_length, (long) (end - pos));
250 : 0 : ret->ignore = TRUE;
251 : 0 : return NULL;
252 : : }
253 : : }
254 : :
255 : 0 : wpa_printf(MSG_DEBUG, "EAP-TNC: Received packet: Flags 0x%x "
256 : : "Message Length %u", flags, message_length);
257 : :
258 [ # # ]: 0 : if (data->state == WAIT_FRAG_ACK) {
259 [ # # ]: 0 : if (len > 1) {
260 : 0 : wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload in "
261 : : "WAIT_FRAG_ACK state");
262 : 0 : ret->ignore = TRUE;
263 : 0 : return NULL;
264 : : }
265 : 0 : wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged");
266 : 0 : data->state = PROC_MSG;
267 : 0 : return eap_tnc_build_msg(data, ret, id);
268 : : }
269 : :
270 [ # # ][ # # ]: 0 : if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) {
271 : 0 : ret->ignore = TRUE;
272 : 0 : return NULL;
273 : : }
274 : :
275 [ # # ]: 0 : if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) {
276 : 0 : return eap_tnc_process_fragment(data, ret, id, flags,
277 : : message_length, pos,
278 : 0 : end - pos);
279 : : }
280 : :
281 [ # # ]: 0 : if (data->in_buf == NULL) {
282 : : /* Wrap unfragmented messages as wpabuf without extra copy */
283 : 0 : wpabuf_set(&tmpbuf, pos, end - pos);
284 : 0 : data->in_buf = &tmpbuf;
285 : : }
286 : :
287 [ # # ]: 0 : if (data->state == WAIT_START) {
288 [ # # ]: 0 : if (!(flags & EAP_TNC_FLAGS_START)) {
289 : 0 : wpa_printf(MSG_DEBUG, "EAP-TNC: Server did not use "
290 : : "start flag in the first message");
291 : 0 : ret->ignore = TRUE;
292 : 0 : goto fail;
293 : : }
294 : :
295 : 0 : tncc_init_connection(data->tncc);
296 : :
297 : 0 : data->state = PROC_MSG;
298 : : } else {
299 : : enum tncc_process_res res;
300 : :
301 [ # # ]: 0 : if (flags & EAP_TNC_FLAGS_START) {
302 : 0 : wpa_printf(MSG_DEBUG, "EAP-TNC: Server used start "
303 : : "flag again");
304 : 0 : ret->ignore = TRUE;
305 : 0 : goto fail;
306 : : }
307 : :
308 : 0 : res = tncc_process_if_tnccs(data->tncc,
309 : 0 : wpabuf_head(data->in_buf),
310 : 0 : wpabuf_len(data->in_buf));
311 [ # # # # : 0 : switch (res) {
# # ]
312 : : case TNCCS_PROCESS_ERROR:
313 : 0 : ret->ignore = TRUE;
314 : 0 : goto fail;
315 : : case TNCCS_PROCESS_OK_NO_RECOMMENDATION:
316 : : case TNCCS_RECOMMENDATION_ERROR:
317 : 0 : wpa_printf(MSG_DEBUG, "EAP-TNC: No "
318 : : "TNCCS-Recommendation received");
319 : 0 : break;
320 : : case TNCCS_RECOMMENDATION_ALLOW:
321 : 0 : wpa_msg(sm->msg_ctx, MSG_INFO,
322 : : "TNC: Recommendation = allow");
323 : 0 : tncs_done = 1;
324 : 0 : break;
325 : : case TNCCS_RECOMMENDATION_NONE:
326 : 0 : wpa_msg(sm->msg_ctx, MSG_INFO,
327 : : "TNC: Recommendation = none");
328 : 0 : tncs_done = 1;
329 : 0 : break;
330 : : case TNCCS_RECOMMENDATION_ISOLATE:
331 : 0 : wpa_msg(sm->msg_ctx, MSG_INFO,
332 : : "TNC: Recommendation = isolate");
333 : 0 : tncs_done = 1;
334 : 0 : break;
335 : : }
336 : : }
337 : :
338 [ # # ]: 0 : if (data->in_buf != &tmpbuf)
339 : 0 : wpabuf_free(data->in_buf);
340 : 0 : data->in_buf = NULL;
341 : :
342 : 0 : ret->ignore = FALSE;
343 : 0 : ret->methodState = METHOD_MAY_CONT;
344 : 0 : ret->decision = DECISION_UNCOND_SUCC;
345 : 0 : ret->allowNotifications = TRUE;
346 : :
347 [ # # ]: 0 : if (data->out_buf) {
348 : 0 : data->state = PROC_MSG;
349 : 0 : return eap_tnc_build_msg(data, ret, id);
350 : : }
351 : :
352 [ # # ]: 0 : if (tncs_done) {
353 : 0 : resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1,
354 : 0 : EAP_CODE_RESPONSE, eap_get_id(reqData));
355 [ # # ]: 0 : if (resp == NULL)
356 : 0 : return NULL;
357 : :
358 : 0 : wpabuf_put_u8(resp, EAP_TNC_VERSION);
359 : 0 : wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS done - reply with an "
360 : : "empty ACK message");
361 : 0 : return resp;
362 : : }
363 : :
364 : 0 : imc_len = tncc_total_send_len(data->tncc);
365 : :
366 : 0 : start_buf = tncc_if_tnccs_start(data->tncc);
367 [ # # ]: 0 : if (start_buf == NULL)
368 : 0 : return NULL;
369 : 0 : start_len = os_strlen(start_buf);
370 : 0 : end_buf = tncc_if_tnccs_end();
371 [ # # ]: 0 : if (end_buf == NULL) {
372 : 0 : os_free(start_buf);
373 : 0 : return NULL;
374 : : }
375 : 0 : end_len = os_strlen(end_buf);
376 : :
377 : 0 : rlen = start_len + imc_len + end_len;
378 : 0 : resp = wpabuf_alloc(rlen);
379 [ # # ]: 0 : if (resp == NULL) {
380 : 0 : os_free(start_buf);
381 : 0 : os_free(end_buf);
382 : 0 : return NULL;
383 : : }
384 : :
385 : 0 : wpabuf_put_data(resp, start_buf, start_len);
386 : 0 : os_free(start_buf);
387 : :
388 : 0 : rpos1 = wpabuf_put(resp, 0);
389 : 0 : rpos = tncc_copy_send_buf(data->tncc, rpos1);
390 : 0 : wpabuf_put(resp, rpos - rpos1);
391 : :
392 : 0 : wpabuf_put_data(resp, end_buf, end_len);
393 : 0 : os_free(end_buf);
394 : :
395 : 0 : wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Response",
396 : : wpabuf_head(resp), wpabuf_len(resp));
397 : :
398 : 0 : data->out_buf = resp;
399 : 0 : data->state = PROC_MSG;
400 : 0 : return eap_tnc_build_msg(data, ret, id);
401 : :
402 : : fail:
403 [ # # ]: 0 : if (data->in_buf == &tmpbuf)
404 : 0 : data->in_buf = NULL;
405 : 0 : return NULL;
406 : : }
407 : :
408 : :
409 : 4 : int eap_peer_tnc_register(void)
410 : : {
411 : : struct eap_method *eap;
412 : : int ret;
413 : :
414 : 4 : eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
415 : : EAP_VENDOR_IETF, EAP_TYPE_TNC, "TNC");
416 [ - + ]: 4 : if (eap == NULL)
417 : 0 : return -1;
418 : :
419 : 4 : eap->init = eap_tnc_init;
420 : 4 : eap->deinit = eap_tnc_deinit;
421 : 4 : eap->process = eap_tnc_process;
422 : :
423 : 4 : ret = eap_peer_method_register(eap);
424 [ - + ]: 4 : if (ret)
425 : 0 : eap_peer_method_free(eap);
426 : 4 : return ret;
427 : : }
|