1 /*
2 * EAP-TNC - TNCC (IF-IMC and IF-TNCCS)
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 #ifndef CONFIG_NATIVE_WINDOWS
11 #include <dlfcn.h>
12 #endif /* CONFIG_NATIVE_WINDOWS */
13
14 #include "common.h"
15 #include "base64.h"
16 #include "common/tnc.h"
17 #include "tncc.h"
18 #include "eap_common/eap_tlv_common.h"
19 #include "eap_common/eap_defs.h"
20
21
22 #ifdef UNICODE
23 #define TSTR "%S"
24 #else /* UNICODE */
25 #define TSTR "%s"
26 #endif /* UNICODE */
27
28
29 #ifndef TNC_CONFIG_FILE
30 #define TNC_CONFIG_FILE "/etc/tnc_config"
31 #endif /* TNC_CONFIG_FILE */
32 #define TNC_WINREG_PATH TEXT("SOFTWARE\\Trusted Computing Group\\TNC\\IMCs")
33 #define IF_TNCCS_START \
34 "<?xml version=\"1.0\"?>\n" \
35 "<TNCCS-Batch BatchId=\"%d\" Recipient=\"TNCS\" " \
36 "xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \
37 "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
38 "xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \
39 "IF_TNCCS# https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n"
40 #define IF_TNCCS_END "\n</TNCCS-Batch>"
41
42 /* TNC IF-IMC */
43
44 /* IF-TNCCS-SOH - SSoH and SSoHR Attributes */
45 enum {
46 SSOH_MS_MACHINE_INVENTORY = 1,
47 SSOH_MS_QUARANTINE_STATE = 2,
48 SSOH_MS_PACKET_INFO = 3,
49 SSOH_MS_SYSTEMGENERATED_IDS = 4,
50 SSOH_MS_MACHINENAME = 5,
51 SSOH_MS_CORRELATIONID = 6,
52 SSOH_MS_INSTALLED_SHVS = 7,
53 SSOH_MS_MACHINE_INVENTORY_EX = 8
54 };
55
56 struct tnc_if_imc {
57 struct tnc_if_imc *next;
58 char *name;
59 char *path;
60 void *dlhandle; /* from dlopen() */
61 TNC_IMCID imcID;
62 TNC_ConnectionID connectionID;
63 TNC_MessageTypeList supported_types;
64 size_t num_supported_types;
65 u8 *imc_send;
66 size_t imc_send_len;
67
68 /* Functions implemented by IMCs (with TNC_IMC_ prefix) */
69 TNC_Result (*Initialize)(
70 TNC_IMCID imcID,
71 TNC_Version minVersion,
72 TNC_Version maxVersion,
73 TNC_Version *pOutActualVersion);
74 TNC_Result (*NotifyConnectionChange)(
75 TNC_IMCID imcID,
76 TNC_ConnectionID connectionID,
77 TNC_ConnectionState newState);
78 TNC_Result (*BeginHandshake)(
79 TNC_IMCID imcID,
80 TNC_ConnectionID connectionID);
81 TNC_Result (*ReceiveMessage)(
82 TNC_IMCID imcID,
83 TNC_ConnectionID connectionID,
84 TNC_BufferReference messageBuffer,
85 TNC_UInt32 messageLength,
86 TNC_MessageType messageType);
87 TNC_Result (*BatchEnding)(
88 TNC_IMCID imcID,
89 TNC_ConnectionID connectionID);
90 TNC_Result (*Terminate)(TNC_IMCID imcID);
91 TNC_Result (*ProvideBindFunction)(
92 TNC_IMCID imcID,
93 TNC_TNCC_BindFunctionPointer bindFunction);
94 };
95
96 struct tncc_data {
97 struct tnc_if_imc *imc;
98 unsigned int last_batchid;
99 };
100
101 #define TNC_MAX_IMC_ID 10
102 static struct tnc_if_imc *tnc_imc[TNC_MAX_IMC_ID] = { NULL };
103
104
105 /* TNCC functions that IMCs can call */
106
TNC_TNCC_ReportMessageTypes(TNC_IMCID imcID,TNC_MessageTypeList supportedTypes,TNC_UInt32 typeCount)107 static TNC_Result TNC_TNCC_ReportMessageTypes(
108 TNC_IMCID imcID,
109 TNC_MessageTypeList supportedTypes,
110 TNC_UInt32 typeCount)
111 {
112 TNC_UInt32 i;
113 struct tnc_if_imc *imc;
114
115 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_ReportMessageTypes(imcID=%lu "
116 "typeCount=%lu)",
117 (unsigned long) imcID, (unsigned long) typeCount);
118
119 for (i = 0; i < typeCount; i++) {
120 wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu",
121 i, supportedTypes[i]);
122 }
123
124 if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
125 return TNC_RESULT_INVALID_PARAMETER;
126
127 imc = tnc_imc[imcID];
128 os_free(imc->supported_types);
129 imc->supported_types = os_memdup(supportedTypes,
130 typeCount * sizeof(TNC_MessageType));
131 if (imc->supported_types == NULL)
132 return TNC_RESULT_FATAL;
133 imc->num_supported_types = typeCount;
134
135 return TNC_RESULT_SUCCESS;
136 }
137
138
TNC_TNCC_SendMessage(TNC_IMCID imcID,TNC_ConnectionID connectionID,TNC_BufferReference message,TNC_UInt32 messageLength,TNC_MessageType messageType)139 static TNC_Result TNC_TNCC_SendMessage(
140 TNC_IMCID imcID,
141 TNC_ConnectionID connectionID,
142 TNC_BufferReference message,
143 TNC_UInt32 messageLength,
144 TNC_MessageType messageType)
145 {
146 struct tnc_if_imc *imc;
147 unsigned char *b64;
148 size_t b64len;
149
150 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage(imcID=%lu "
151 "connectionID=%lu messageType=%lu)",
152 imcID, connectionID, messageType);
153 wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage",
154 message, messageLength);
155
156 if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
157 return TNC_RESULT_INVALID_PARAMETER;
158
159 b64 = base64_encode(message, messageLength, &b64len);
160 if (b64 == NULL)
161 return TNC_RESULT_FATAL;
162
163 imc = tnc_imc[imcID];
164 os_free(imc->imc_send);
165 imc->imc_send_len = 0;
166 imc->imc_send = os_zalloc(b64len + 100);
167 if (imc->imc_send == NULL) {
168 os_free(b64);
169 return TNC_RESULT_OTHER;
170 }
171
172 imc->imc_send_len =
173 os_snprintf((char *) imc->imc_send, b64len + 100,
174 "<IMC-IMV-Message><Type>%08X</Type>"
175 "<Base64>%s</Base64></IMC-IMV-Message>",
176 (unsigned int) messageType, b64);
177
178 os_free(b64);
179
180 return TNC_RESULT_SUCCESS;
181 }
182
183
TNC_TNCC_RequestHandshakeRetry(TNC_IMCID imcID,TNC_ConnectionID connectionID,TNC_RetryReason reason)184 static TNC_Result TNC_TNCC_RequestHandshakeRetry(
185 TNC_IMCID imcID,
186 TNC_ConnectionID connectionID,
187 TNC_RetryReason reason)
188 {
189 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_RequestHandshakeRetry");
190
191 if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
192 return TNC_RESULT_INVALID_PARAMETER;
193
194 /*
195 * TODO: trigger a call to eapol_sm_request_reauth(). This would
196 * require that the IMC continues to be loaded in memory afer
197 * authentication..
198 */
199
200 return TNC_RESULT_SUCCESS;
201 }
202
203
TNC_9048_LogMessage(TNC_IMCID imcID,TNC_UInt32 severity,const char * message)204 static TNC_Result TNC_9048_LogMessage(TNC_IMCID imcID, TNC_UInt32 severity,
205 const char *message)
206 {
207 wpa_printf(MSG_DEBUG, "TNC: TNC_9048_LogMessage(imcID=%lu "
208 "severity==%lu message='%s')",
209 imcID, severity, message);
210 return TNC_RESULT_SUCCESS;
211 }
212
213
TNC_9048_UserMessage(TNC_IMCID imcID,TNC_ConnectionID connectionID,const char * message)214 static TNC_Result TNC_9048_UserMessage(TNC_IMCID imcID,
215 TNC_ConnectionID connectionID,
216 const char *message)
217 {
218 wpa_printf(MSG_DEBUG, "TNC: TNC_9048_UserMessage(imcID=%lu "
219 "connectionID==%lu message='%s')",
220 imcID, connectionID, message);
221 return TNC_RESULT_SUCCESS;
222 }
223
224
TNC_TNCC_BindFunction(TNC_IMCID imcID,char * functionName,void ** pOutfunctionPointer)225 static TNC_Result TNC_TNCC_BindFunction(
226 TNC_IMCID imcID,
227 char *functionName,
228 void **pOutfunctionPointer)
229 {
230 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_BindFunction(imcID=%lu, "
231 "functionName='%s')", (unsigned long) imcID, functionName);
232
233 if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
234 return TNC_RESULT_INVALID_PARAMETER;
235
236 if (pOutfunctionPointer == NULL)
237 return TNC_RESULT_INVALID_PARAMETER;
238
239 if (os_strcmp(functionName, "TNC_TNCC_ReportMessageTypes") == 0)
240 *pOutfunctionPointer = TNC_TNCC_ReportMessageTypes;
241 else if (os_strcmp(functionName, "TNC_TNCC_SendMessage") == 0)
242 *pOutfunctionPointer = TNC_TNCC_SendMessage;
243 else if (os_strcmp(functionName, "TNC_TNCC_RequestHandshakeRetry") ==
244 0)
245 *pOutfunctionPointer = TNC_TNCC_RequestHandshakeRetry;
246 else if (os_strcmp(functionName, "TNC_9048_LogMessage") == 0)
247 *pOutfunctionPointer = TNC_9048_LogMessage;
248 else if (os_strcmp(functionName, "TNC_9048_UserMessage") == 0)
249 *pOutfunctionPointer = TNC_9048_UserMessage;
250 else
251 *pOutfunctionPointer = NULL;
252
253 return TNC_RESULT_SUCCESS;
254 }
255
256
tncc_get_sym(void * handle,char * func)257 static void * tncc_get_sym(void *handle, char *func)
258 {
259 void *fptr;
260
261 #ifdef CONFIG_NATIVE_WINDOWS
262 #ifdef _WIN32_WCE
263 fptr = GetProcAddressA(handle, func);
264 #else /* _WIN32_WCE */
265 fptr = GetProcAddress(handle, func);
266 #endif /* _WIN32_WCE */
267 #else /* CONFIG_NATIVE_WINDOWS */
268 fptr = dlsym(handle, func);
269 #endif /* CONFIG_NATIVE_WINDOWS */
270
271 return fptr;
272 }
273
274
tncc_imc_resolve_funcs(struct tnc_if_imc * imc)275 static int tncc_imc_resolve_funcs(struct tnc_if_imc *imc)
276 {
277 void *handle = imc->dlhandle;
278
279 /* Mandatory IMC functions */
280 imc->Initialize = tncc_get_sym(handle, "TNC_IMC_Initialize");
281 if (imc->Initialize == NULL) {
282 wpa_printf(MSG_ERROR, "TNC: IMC does not export "
283 "TNC_IMC_Initialize");
284 return -1;
285 }
286
287 imc->BeginHandshake = tncc_get_sym(handle, "TNC_IMC_BeginHandshake");
288 if (imc->BeginHandshake == NULL) {
289 wpa_printf(MSG_ERROR, "TNC: IMC does not export "
290 "TNC_IMC_BeginHandshake");
291 return -1;
292 }
293
294 imc->ProvideBindFunction =
295 tncc_get_sym(handle, "TNC_IMC_ProvideBindFunction");
296 if (imc->ProvideBindFunction == NULL) {
297 wpa_printf(MSG_ERROR, "TNC: IMC does not export "
298 "TNC_IMC_ProvideBindFunction");
299 return -1;
300 }
301
302 /* Optional IMC functions */
303 imc->NotifyConnectionChange =
304 tncc_get_sym(handle, "TNC_IMC_NotifyConnectionChange");
305 imc->ReceiveMessage = tncc_get_sym(handle, "TNC_IMC_ReceiveMessage");
306 imc->BatchEnding = tncc_get_sym(handle, "TNC_IMC_BatchEnding");
307 imc->Terminate = tncc_get_sym(handle, "TNC_IMC_Terminate");
308
309 return 0;
310 }
311
312
tncc_imc_initialize(struct tnc_if_imc * imc)313 static int tncc_imc_initialize(struct tnc_if_imc *imc)
314 {
315 TNC_Result res;
316 TNC_Version imc_ver;
317
318 wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Initialize for IMC '%s'",
319 imc->name);
320 res = imc->Initialize(imc->imcID, TNC_IFIMC_VERSION_1,
321 TNC_IFIMC_VERSION_1, &imc_ver);
322 wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Initialize: res=%lu imc_ver=%lu",
323 (unsigned long) res, (unsigned long) imc_ver);
324
325 return res == TNC_RESULT_SUCCESS ? 0 : -1;
326 }
327
328
tncc_imc_terminate(struct tnc_if_imc * imc)329 static int tncc_imc_terminate(struct tnc_if_imc *imc)
330 {
331 TNC_Result res;
332
333 if (imc->Terminate == NULL)
334 return 0;
335
336 wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Terminate for IMC '%s'",
337 imc->name);
338 res = imc->Terminate(imc->imcID);
339 wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Terminate: %lu",
340 (unsigned long) res);
341
342 return res == TNC_RESULT_SUCCESS ? 0 : -1;
343 }
344
345
tncc_imc_provide_bind_function(struct tnc_if_imc * imc)346 static int tncc_imc_provide_bind_function(struct tnc_if_imc *imc)
347 {
348 TNC_Result res;
349
350 wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_ProvideBindFunction for "
351 "IMC '%s'", imc->name);
352 res = imc->ProvideBindFunction(imc->imcID, TNC_TNCC_BindFunction);
353 wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_ProvideBindFunction: res=%lu",
354 (unsigned long) res);
355
356 return res == TNC_RESULT_SUCCESS ? 0 : -1;
357 }
358
359
tncc_imc_notify_connection_change(struct tnc_if_imc * imc,TNC_ConnectionState state)360 static int tncc_imc_notify_connection_change(struct tnc_if_imc *imc,
361 TNC_ConnectionState state)
362 {
363 TNC_Result res;
364
365 if (imc->NotifyConnectionChange == NULL)
366 return 0;
367
368 wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_NotifyConnectionChange(%d)"
369 " for IMC '%s'", (int) state, imc->name);
370 res = imc->NotifyConnectionChange(imc->imcID, imc->connectionID,
371 state);
372 wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu",
373 (unsigned long) res);
374
375 return res == TNC_RESULT_SUCCESS ? 0 : -1;
376 }
377
378
tncc_imc_begin_handshake(struct tnc_if_imc * imc)379 static int tncc_imc_begin_handshake(struct tnc_if_imc *imc)
380 {
381 TNC_Result res;
382
383 wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_BeginHandshake for IMC "
384 "'%s'", imc->name);
385 res = imc->BeginHandshake(imc->imcID, imc->connectionID);
386 wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_BeginHandshake: %lu",
387 (unsigned long) res);
388
389 return res == TNC_RESULT_SUCCESS ? 0 : -1;
390 }
391
392
tncc_load_imc(struct tnc_if_imc * imc)393 static int tncc_load_imc(struct tnc_if_imc *imc)
394 {
395 if (imc->path == NULL) {
396 wpa_printf(MSG_DEBUG, "TNC: No IMC configured");
397 return -1;
398 }
399
400 wpa_printf(MSG_DEBUG, "TNC: Opening IMC: %s (%s)",
401 imc->name, imc->path);
402 #ifdef CONFIG_NATIVE_WINDOWS
403 #ifdef UNICODE
404 {
405 TCHAR *lib = wpa_strdup_tchar(imc->path);
406 if (lib == NULL)
407 return -1;
408 imc->dlhandle = LoadLibrary(lib);
409 os_free(lib);
410 }
411 #else /* UNICODE */
412 imc->dlhandle = LoadLibrary(imc->path);
413 #endif /* UNICODE */
414 if (imc->dlhandle == NULL) {
415 wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %d",
416 imc->name, imc->path, (int) GetLastError());
417 return -1;
418 }
419 #else /* CONFIG_NATIVE_WINDOWS */
420 imc->dlhandle = dlopen(imc->path, RTLD_LAZY);
421 if (imc->dlhandle == NULL) {
422 wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %s",
423 imc->name, imc->path, dlerror());
424 return -1;
425 }
426 #endif /* CONFIG_NATIVE_WINDOWS */
427
428 if (tncc_imc_resolve_funcs(imc) < 0) {
429 wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMC functions");
430 return -1;
431 }
432
433 if (tncc_imc_initialize(imc) < 0 ||
434 tncc_imc_provide_bind_function(imc) < 0) {
435 wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMC");
436 return -1;
437 }
438
439 return 0;
440 }
441
442
tncc_unload_imc(struct tnc_if_imc * imc)443 static void tncc_unload_imc(struct tnc_if_imc *imc)
444 {
445 tncc_imc_terminate(imc);
446 tnc_imc[imc->imcID] = NULL;
447
448 if (imc->dlhandle) {
449 #ifdef CONFIG_NATIVE_WINDOWS
450 FreeLibrary(imc->dlhandle);
451 #else /* CONFIG_NATIVE_WINDOWS */
452 dlclose(imc->dlhandle);
453 #endif /* CONFIG_NATIVE_WINDOWS */
454 }
455 os_free(imc->name);
456 os_free(imc->path);
457 os_free(imc->supported_types);
458 os_free(imc->imc_send);
459 }
460
461
tncc_supported_type(struct tnc_if_imc * imc,unsigned int type)462 static int tncc_supported_type(struct tnc_if_imc *imc, unsigned int type)
463 {
464 size_t i;
465 unsigned int vendor, subtype;
466
467 if (imc == NULL || imc->supported_types == NULL)
468 return 0;
469
470 vendor = type >> 8;
471 subtype = type & 0xff;
472
473 for (i = 0; i < imc->num_supported_types; i++) {
474 unsigned int svendor, ssubtype;
475 svendor = imc->supported_types[i] >> 8;
476 ssubtype = imc->supported_types[i] & 0xff;
477 if ((vendor == svendor || svendor == TNC_VENDORID_ANY) &&
478 (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY))
479 return 1;
480 }
481
482 return 0;
483 }
484
485
tncc_send_to_imcs(struct tncc_data * tncc,unsigned int type,const u8 * msg,size_t len)486 static void tncc_send_to_imcs(struct tncc_data *tncc, unsigned int type,
487 const u8 *msg, size_t len)
488 {
489 struct tnc_if_imc *imc;
490 TNC_Result res;
491
492 wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMC(s)", msg, len);
493
494 for (imc = tncc->imc; imc; imc = imc->next) {
495 if (imc->ReceiveMessage == NULL ||
496 !tncc_supported_type(imc, type))
497 continue;
498
499 wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMC '%s'",
500 imc->name);
501 res = imc->ReceiveMessage(imc->imcID, imc->connectionID,
502 (TNC_BufferReference) msg, len,
503 type);
504 wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu",
505 (unsigned long) res);
506 }
507 }
508
509
tncc_init_connection(struct tncc_data * tncc)510 void tncc_init_connection(struct tncc_data *tncc)
511 {
512 struct tnc_if_imc *imc;
513
514 for (imc = tncc->imc; imc; imc = imc->next) {
515 tncc_imc_notify_connection_change(
516 imc, TNC_CONNECTION_STATE_CREATE);
517 tncc_imc_notify_connection_change(
518 imc, TNC_CONNECTION_STATE_HANDSHAKE);
519
520 os_free(imc->imc_send);
521 imc->imc_send = NULL;
522 imc->imc_send_len = 0;
523
524 tncc_imc_begin_handshake(imc);
525 }
526 }
527
528
tncc_total_send_len(struct tncc_data * tncc)529 size_t tncc_total_send_len(struct tncc_data *tncc)
530 {
531 struct tnc_if_imc *imc;
532
533 size_t len = 0;
534 for (imc = tncc->imc; imc; imc = imc->next)
535 len += imc->imc_send_len;
536 return len;
537 }
538
539
tncc_copy_send_buf(struct tncc_data * tncc,u8 * pos)540 u8 * tncc_copy_send_buf(struct tncc_data *tncc, u8 *pos)
541 {
542 struct tnc_if_imc *imc;
543
544 for (imc = tncc->imc; imc; imc = imc->next) {
545 if (imc->imc_send == NULL)
546 continue;
547
548 os_memcpy(pos, imc->imc_send, imc->imc_send_len);
549 pos += imc->imc_send_len;
550 os_free(imc->imc_send);
551 imc->imc_send = NULL;
552 imc->imc_send_len = 0;
553 }
554
555 return pos;
556 }
557
558
tncc_if_tnccs_start(struct tncc_data * tncc)559 char * tncc_if_tnccs_start(struct tncc_data *tncc)
560 {
561 char *buf = os_malloc(1000);
562 if (buf == NULL)
563 return NULL;
564 tncc->last_batchid++;
565 os_snprintf(buf, 1000, IF_TNCCS_START, tncc->last_batchid);
566 return buf;
567 }
568
569
tncc_if_tnccs_end(void)570 char * tncc_if_tnccs_end(void)
571 {
572 char *buf = os_malloc(100);
573 if (buf == NULL)
574 return NULL;
575 os_snprintf(buf, 100, IF_TNCCS_END);
576 return buf;
577 }
578
579
tncc_notify_recommendation(struct tncc_data * tncc,enum tncc_process_res res)580 static void tncc_notify_recommendation(struct tncc_data *tncc,
581 enum tncc_process_res res)
582 {
583 TNC_ConnectionState state;
584 struct tnc_if_imc *imc;
585
586 switch (res) {
587 case TNCCS_RECOMMENDATION_ALLOW:
588 state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
589 break;
590 case TNCCS_RECOMMENDATION_NONE:
591 state = TNC_CONNECTION_STATE_ACCESS_NONE;
592 break;
593 case TNCCS_RECOMMENDATION_ISOLATE:
594 state = TNC_CONNECTION_STATE_ACCESS_ISOLATED;
595 break;
596 default:
597 state = TNC_CONNECTION_STATE_ACCESS_NONE;
598 break;
599 }
600
601 for (imc = tncc->imc; imc; imc = imc->next)
602 tncc_imc_notify_connection_change(imc, state);
603 }
604
605
tncc_get_type(char * start,unsigned int * type)606 static int tncc_get_type(char *start, unsigned int *type)
607 {
608 char *pos = os_strstr(start, "<Type>");
609 if (pos == NULL)
610 return -1;
611 pos += 6;
612 *type = strtoul(pos, NULL, 16);
613 return 0;
614 }
615
616
tncc_get_base64(char * start,size_t * decoded_len)617 static unsigned char * tncc_get_base64(char *start, size_t *decoded_len)
618 {
619 char *pos, *pos2;
620 unsigned char *decoded;
621
622 pos = os_strstr(start, "<Base64>");
623 if (pos == NULL)
624 return NULL;
625
626 pos += 8;
627 pos2 = os_strstr(pos, "</Base64>");
628 if (pos2 == NULL)
629 return NULL;
630 *pos2 = '\0';
631
632 decoded = base64_decode((unsigned char *) pos, os_strlen(pos),
633 decoded_len);
634 *pos2 = '<';
635 if (decoded == NULL) {
636 wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data");
637 }
638
639 return decoded;
640 }
641
642
tncc_get_recommendation(char * start)643 static enum tncc_process_res tncc_get_recommendation(char *start)
644 {
645 char *pos, *pos2, saved;
646 int recom;
647
648 pos = os_strstr(start, "<TNCCS-Recommendation ");
649 if (pos == NULL)
650 return TNCCS_RECOMMENDATION_ERROR;
651
652 pos += 21;
653 pos = os_strstr(pos, " type=");
654 if (pos == NULL)
655 return TNCCS_RECOMMENDATION_ERROR;
656 pos += 6;
657
658 if (*pos == '"')
659 pos++;
660
661 pos2 = pos;
662 while (*pos2 != '\0' && *pos2 != '"' && *pos2 != '>')
663 pos2++;
664
665 if (*pos2 == '\0')
666 return TNCCS_RECOMMENDATION_ERROR;
667
668 saved = *pos2;
669 *pos2 = '\0';
670 wpa_printf(MSG_DEBUG, "TNC: TNCCS-Recommendation: '%s'", pos);
671
672 recom = TNCCS_RECOMMENDATION_ERROR;
673 if (os_strcmp(pos, "allow") == 0)
674 recom = TNCCS_RECOMMENDATION_ALLOW;
675 else if (os_strcmp(pos, "none") == 0)
676 recom = TNCCS_RECOMMENDATION_NONE;
677 else if (os_strcmp(pos, "isolate") == 0)
678 recom = TNCCS_RECOMMENDATION_ISOLATE;
679
680 *pos2 = saved;
681
682 return recom;
683 }
684
685
tncc_process_if_tnccs(struct tncc_data * tncc,const u8 * msg,size_t len)686 enum tncc_process_res tncc_process_if_tnccs(struct tncc_data *tncc,
687 const u8 *msg, size_t len)
688 {
689 char *buf, *start, *end, *pos, *pos2, *payload;
690 unsigned int batch_id;
691 unsigned char *decoded;
692 size_t decoded_len;
693 enum tncc_process_res res = TNCCS_PROCESS_OK_NO_RECOMMENDATION;
694 int recommendation_msg = 0;
695
696 wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Received IF-TNCCS message",
697 msg, len);
698 buf = dup_binstr(msg, len);
699 if (buf == NULL)
700 return TNCCS_PROCESS_ERROR;
701
702 start = os_strstr(buf, "<TNCCS-Batch ");
703 end = os_strstr(buf, "</TNCCS-Batch>");
704 if (start == NULL || end == NULL || start > end) {
705 os_free(buf);
706 return TNCCS_PROCESS_ERROR;
707 }
708
709 start += 13;
710 while (*start == ' ')
711 start++;
712 *end = '\0';
713
714 pos = os_strstr(start, "BatchId=");
715 if (pos == NULL) {
716 os_free(buf);
717 return TNCCS_PROCESS_ERROR;
718 }
719
720 pos += 8;
721 if (*pos == '"')
722 pos++;
723 batch_id = atoi(pos);
724 wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u",
725 batch_id);
726 if (batch_id != tncc->last_batchid + 1) {
727 wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId "
728 "%u (expected %u)",
729 batch_id, tncc->last_batchid + 1);
730 os_free(buf);
731 return TNCCS_PROCESS_ERROR;
732 }
733 tncc->last_batchid = batch_id;
734
735 while (*pos != '\0' && *pos != '>')
736 pos++;
737 if (*pos == '\0') {
738 os_free(buf);
739 return TNCCS_PROCESS_ERROR;
740 }
741 pos++;
742 payload = start;
743
744 /*
745 * <IMC-IMV-Message>
746 * <Type>01234567</Type>
747 * <Base64>foo==</Base64>
748 * </IMC-IMV-Message>
749 */
750
751 while (*start) {
752 char *endpos;
753 unsigned int type;
754
755 pos = os_strstr(start, "<IMC-IMV-Message>");
756 if (pos == NULL)
757 break;
758 start = pos + 17;
759 end = os_strstr(start, "</IMC-IMV-Message>");
760 if (end == NULL)
761 break;
762 *end = '\0';
763 endpos = end;
764 end += 18;
765
766 if (tncc_get_type(start, &type) < 0) {
767 *endpos = '<';
768 start = end;
769 continue;
770 }
771 wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type);
772
773 decoded = tncc_get_base64(start, &decoded_len);
774 if (decoded == NULL) {
775 *endpos = '<';
776 start = end;
777 continue;
778 }
779
780 tncc_send_to_imcs(tncc, type, decoded, decoded_len);
781
782 os_free(decoded);
783
784 start = end;
785 }
786
787 /*
788 * <TNCC-TNCS-Message>
789 * <Type>01234567</Type>
790 * <XML><TNCCS-Foo type="foo"></TNCCS-Foo></XML>
791 * <Base64>foo==</Base64>
792 * </TNCC-TNCS-Message>
793 */
794
795 start = payload;
796 while (*start) {
797 unsigned int type;
798 char *xml, *xmlend, *endpos;
799
800 pos = os_strstr(start, "<TNCC-TNCS-Message>");
801 if (pos == NULL)
802 break;
803 start = pos + 19;
804 end = os_strstr(start, "</TNCC-TNCS-Message>");
805 if (end == NULL)
806 break;
807 *end = '\0';
808 endpos = end;
809 end += 20;
810
811 if (tncc_get_type(start, &type) < 0) {
812 *endpos = '<';
813 start = end;
814 continue;
815 }
816 wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x",
817 type);
818
819 /* Base64 OR XML */
820 decoded = NULL;
821 xml = NULL;
822 xmlend = NULL;
823 pos = os_strstr(start, "<XML>");
824 if (pos) {
825 pos += 5;
826 pos2 = os_strstr(pos, "</XML>");
827 if (pos2 == NULL) {
828 *endpos = '<';
829 start = end;
830 continue;
831 }
832 xmlend = pos2;
833 xml = pos;
834 } else {
835 decoded = tncc_get_base64(start, &decoded_len);
836 if (decoded == NULL) {
837 *endpos = '<';
838 start = end;
839 continue;
840 }
841 }
842
843 if (decoded) {
844 wpa_hexdump_ascii(MSG_MSGDUMP,
845 "TNC: TNCC-TNCS-Message Base64",
846 decoded, decoded_len);
847 os_free(decoded);
848 }
849
850 if (xml) {
851 wpa_hexdump_ascii(MSG_MSGDUMP,
852 "TNC: TNCC-TNCS-Message XML",
853 (unsigned char *) xml,
854 xmlend - xml);
855 }
856
857 if (type == TNC_TNCCS_RECOMMENDATION && xml) {
858 /*
859 * <TNCCS-Recommendation type="allow">
860 * </TNCCS-Recommendation>
861 */
862 *xmlend = '\0';
863 res = tncc_get_recommendation(xml);
864 *xmlend = '<';
865 recommendation_msg = 1;
866 }
867
868 start = end;
869 }
870
871 os_free(buf);
872
873 if (recommendation_msg)
874 tncc_notify_recommendation(tncc, res);
875
876 return res;
877 }
878
879
880 #ifdef CONFIG_NATIVE_WINDOWS
tncc_read_config_reg(struct tncc_data * tncc,HKEY hive)881 static int tncc_read_config_reg(struct tncc_data *tncc, HKEY hive)
882 {
883 HKEY hk, hk2;
884 LONG ret;
885 DWORD i;
886 struct tnc_if_imc *imc, *last;
887 int j;
888
889 last = tncc->imc;
890 while (last && last->next)
891 last = last->next;
892
893 ret = RegOpenKeyEx(hive, TNC_WINREG_PATH, 0, KEY_ENUMERATE_SUB_KEYS,
894 &hk);
895 if (ret != ERROR_SUCCESS)
896 return 0;
897
898 for (i = 0; ; i++) {
899 TCHAR name[255], *val;
900 DWORD namelen, buflen;
901
902 namelen = 255;
903 ret = RegEnumKeyEx(hk, i, name, &namelen, NULL, NULL, NULL,
904 NULL);
905
906 if (ret == ERROR_NO_MORE_ITEMS)
907 break;
908
909 if (ret != ERROR_SUCCESS) {
910 wpa_printf(MSG_DEBUG, "TNC: RegEnumKeyEx failed: 0x%x",
911 (unsigned int) ret);
912 break;
913 }
914
915 if (namelen >= 255)
916 namelen = 255 - 1;
917 name[namelen] = '\0';
918
919 wpa_printf(MSG_DEBUG, "TNC: IMC '" TSTR "'", name);
920
921 ret = RegOpenKeyEx(hk, name, 0, KEY_QUERY_VALUE, &hk2);
922 if (ret != ERROR_SUCCESS) {
923 wpa_printf(MSG_DEBUG, "Could not open IMC key '" TSTR
924 "'", name);
925 continue;
926 }
927
928 ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL, NULL,
929 &buflen);
930 if (ret != ERROR_SUCCESS) {
931 wpa_printf(MSG_DEBUG, "TNC: Could not read Path from "
932 "IMC key '" TSTR "'", name);
933 RegCloseKey(hk2);
934 continue;
935 }
936
937 val = os_malloc(buflen);
938 if (val == NULL) {
939 RegCloseKey(hk2);
940 continue;
941 }
942
943 ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL,
944 (LPBYTE) val, &buflen);
945 if (ret != ERROR_SUCCESS) {
946 os_free(val);
947 RegCloseKey(hk2);
948 continue;
949 }
950
951 RegCloseKey(hk2);
952
953 wpa_unicode2ascii_inplace(val);
954 wpa_printf(MSG_DEBUG, "TNC: IMC Path '%s'", (char *) val);
955
956 for (j = 0; j < TNC_MAX_IMC_ID; j++) {
957 if (tnc_imc[j] == NULL)
958 break;
959 }
960 if (j >= TNC_MAX_IMC_ID) {
961 wpa_printf(MSG_DEBUG, "TNC: Too many IMCs");
962 os_free(val);
963 continue;
964 }
965
966 imc = os_zalloc(sizeof(*imc));
967 if (imc == NULL) {
968 os_free(val);
969 break;
970 }
971
972 imc->imcID = j;
973
974 wpa_unicode2ascii_inplace(name);
975 imc->name = os_strdup((char *) name);
976 imc->path = os_strdup((char *) val);
977
978 os_free(val);
979
980 if (last == NULL)
981 tncc->imc = imc;
982 else
983 last->next = imc;
984 last = imc;
985
986 tnc_imc[imc->imcID] = imc;
987 }
988
989 RegCloseKey(hk);
990
991 return 0;
992 }
993
994
tncc_read_config(struct tncc_data * tncc)995 static int tncc_read_config(struct tncc_data *tncc)
996 {
997 if (tncc_read_config_reg(tncc, HKEY_LOCAL_MACHINE) < 0 ||
998 tncc_read_config_reg(tncc, HKEY_CURRENT_USER) < 0)
999 return -1;
1000 return 0;
1001 }
1002
1003 #else /* CONFIG_NATIVE_WINDOWS */
1004
tncc_parse_imc(char * start,char * end,int * error)1005 static struct tnc_if_imc * tncc_parse_imc(char *start, char *end, int *error)
1006 {
1007 struct tnc_if_imc *imc;
1008 char *pos, *pos2;
1009 int i;
1010
1011 for (i = 0; i < TNC_MAX_IMC_ID; i++) {
1012 if (tnc_imc[i] == NULL)
1013 break;
1014 }
1015 if (i >= TNC_MAX_IMC_ID) {
1016 wpa_printf(MSG_DEBUG, "TNC: Too many IMCs");
1017 return NULL;
1018 }
1019
1020 imc = os_zalloc(sizeof(*imc));
1021 if (imc == NULL) {
1022 *error = 1;
1023 return NULL;
1024 }
1025
1026 imc->imcID = i;
1027
1028 pos = start;
1029 wpa_printf(MSG_DEBUG, "TNC: Configured IMC: %s", pos);
1030 if (pos + 1 >= end || *pos != '"') {
1031 wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
1032 "(no starting quotation mark)", start);
1033 os_free(imc);
1034 return NULL;
1035 }
1036
1037 pos++;
1038 pos2 = pos;
1039 while (pos2 < end && *pos2 != '"')
1040 pos2++;
1041 if (pos2 >= end) {
1042 wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
1043 "(no ending quotation mark)", start);
1044 os_free(imc);
1045 return NULL;
1046 }
1047 *pos2 = '\0';
1048 wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos);
1049 imc->name = os_strdup(pos);
1050
1051 pos = pos2 + 1;
1052 if (pos >= end || *pos != ' ') {
1053 wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
1054 "(no space after name)", start);
1055 os_free(imc->name);
1056 os_free(imc);
1057 return NULL;
1058 }
1059
1060 pos++;
1061 wpa_printf(MSG_DEBUG, "TNC: IMC file: '%s'", pos);
1062 imc->path = os_strdup(pos);
1063 tnc_imc[imc->imcID] = imc;
1064
1065 return imc;
1066 }
1067
1068
tncc_read_config(struct tncc_data * tncc)1069 static int tncc_read_config(struct tncc_data *tncc)
1070 {
1071 char *config, *end, *pos, *line_end;
1072 size_t config_len;
1073 struct tnc_if_imc *imc, *last;
1074
1075 last = NULL;
1076
1077 config = os_readfile(TNC_CONFIG_FILE, &config_len);
1078 if (config == NULL) {
1079 wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration "
1080 "file '%s'", TNC_CONFIG_FILE);
1081 return -1;
1082 }
1083
1084 end = config + config_len;
1085 for (pos = config; pos < end; pos = line_end + 1) {
1086 line_end = pos;
1087 while (*line_end != '\n' && *line_end != '\r' &&
1088 line_end < end)
1089 line_end++;
1090 *line_end = '\0';
1091
1092 if (os_strncmp(pos, "IMC ", 4) == 0) {
1093 int error = 0;
1094
1095 imc = tncc_parse_imc(pos + 4, line_end, &error);
1096 if (error) {
1097 os_free(config);
1098 return -1;
1099 }
1100 if (imc) {
1101 if (last == NULL)
1102 tncc->imc = imc;
1103 else
1104 last->next = imc;
1105 last = imc;
1106 }
1107 }
1108 }
1109
1110 os_free(config);
1111
1112 return 0;
1113 }
1114
1115 #endif /* CONFIG_NATIVE_WINDOWS */
1116
1117
tncc_init(void)1118 struct tncc_data * tncc_init(void)
1119 {
1120 struct tncc_data *tncc;
1121 struct tnc_if_imc *imc;
1122
1123 tncc = os_zalloc(sizeof(*tncc));
1124 if (tncc == NULL)
1125 return NULL;
1126
1127 /* TODO:
1128 * move loading and Initialize() to a location that is not
1129 * re-initialized for every EAP-TNC session (?)
1130 */
1131
1132 if (tncc_read_config(tncc) < 0) {
1133 wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration");
1134 goto failed;
1135 }
1136
1137 for (imc = tncc->imc; imc; imc = imc->next) {
1138 if (tncc_load_imc(imc)) {
1139 wpa_printf(MSG_ERROR, "TNC: Failed to load IMC '%s'",
1140 imc->name);
1141 goto failed;
1142 }
1143 }
1144
1145 return tncc;
1146
1147 failed:
1148 tncc_deinit(tncc);
1149 return NULL;
1150 }
1151
1152
tncc_deinit(struct tncc_data * tncc)1153 void tncc_deinit(struct tncc_data *tncc)
1154 {
1155 struct tnc_if_imc *imc, *prev;
1156
1157 imc = tncc->imc;
1158 while (imc) {
1159 tncc_unload_imc(imc);
1160
1161 prev = imc;
1162 imc = imc->next;
1163 os_free(prev);
1164 }
1165
1166 os_free(tncc);
1167 }
1168
1169
tncc_build_soh(int ver)1170 static struct wpabuf * tncc_build_soh(int ver)
1171 {
1172 struct wpabuf *buf;
1173 u8 *tlv_len, *tlv_len2, *outer_len, *inner_len, *ssoh_len, *end;
1174 u8 correlation_id[24];
1175 /* TODO: get correct name */
1176 char *machinename = "wpa_supplicant@w1.fi";
1177
1178 if (os_get_random(correlation_id, sizeof(correlation_id)))
1179 return NULL;
1180 wpa_hexdump(MSG_DEBUG, "TNC: SoH Correlation ID",
1181 correlation_id, sizeof(correlation_id));
1182
1183 buf = wpabuf_alloc(200);
1184 if (buf == NULL)
1185 return NULL;
1186
1187 /* Vendor-Specific TLV (Microsoft) - SoH */
1188 wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */
1189 tlv_len = wpabuf_put(buf, 2); /* Length */
1190 wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */
1191 wpabuf_put_be16(buf, 0x01); /* TLV Type - SoH TLV */
1192 tlv_len2 = wpabuf_put(buf, 2); /* Length */
1193
1194 /* SoH Header */
1195 wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* Outer Type */
1196 outer_len = wpabuf_put(buf, 2);
1197 wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
1198 wpabuf_put_be16(buf, ver); /* Inner Type */
1199 inner_len = wpabuf_put(buf, 2);
1200
1201 if (ver == 2) {
1202 /* SoH Mode Sub-Header */
1203 /* Outer Type */
1204 wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV);
1205 wpabuf_put_be16(buf, 4 + 24 + 1 + 1); /* Length */
1206 wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
1207 /* Value: */
1208 wpabuf_put_data(buf, correlation_id, sizeof(correlation_id));
1209 wpabuf_put_u8(buf, 0x01); /* Intent Flag - Request */
1210 wpabuf_put_u8(buf, 0x00); /* Content-Type Flag */
1211 }
1212
1213 /* SSoH TLV */
1214 /* System-Health-Id */
1215 wpabuf_put_be16(buf, 0x0002); /* Type */
1216 wpabuf_put_be16(buf, 4); /* Length */
1217 wpabuf_put_be32(buf, 79616);
1218 /* Vendor-Specific Attribute */
1219 wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV);
1220 ssoh_len = wpabuf_put(buf, 2);
1221 wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
1222
1223 /* MS-Packet-Info */
1224 wpabuf_put_u8(buf, SSOH_MS_PACKET_INFO);
1225 /* Note: IF-TNCCS-SOH v1.0 r8 claims this field to be:
1226 * Reserved(4 bits) r(1 bit) Vers(3 bits), but Windows XP
1227 * SP3 seems to be sending 0x11 for SSoH, i.e., r(request/response) bit
1228 * would not be in the specified location.
1229 * [MS-SOH] 4.0.2: Reserved(3 bits) r(1 bit) Vers(4 bits)
1230 */
1231 wpabuf_put_u8(buf, 0x11); /* r=request, vers=1 */
1232
1233 /* MS-Machine-Inventory */
1234 /* TODO: get correct values; 0 = not applicable for OS */
1235 wpabuf_put_u8(buf, SSOH_MS_MACHINE_INVENTORY);
1236 wpabuf_put_be32(buf, 0); /* osVersionMajor */
1237 wpabuf_put_be32(buf, 0); /* osVersionMinor */
1238 wpabuf_put_be32(buf, 0); /* osVersionBuild */
1239 wpabuf_put_be16(buf, 0); /* spVersionMajor */
1240 wpabuf_put_be16(buf, 0); /* spVersionMinor */
1241 wpabuf_put_be16(buf, 0); /* procArch */
1242
1243 /* MS-MachineName */
1244 wpabuf_put_u8(buf, SSOH_MS_MACHINENAME);
1245 wpabuf_put_be16(buf, os_strlen(machinename) + 1);
1246 wpabuf_put_data(buf, machinename, os_strlen(machinename) + 1);
1247
1248 /* MS-CorrelationId */
1249 wpabuf_put_u8(buf, SSOH_MS_CORRELATIONID);
1250 wpabuf_put_data(buf, correlation_id, sizeof(correlation_id));
1251
1252 /* MS-Quarantine-State */
1253 wpabuf_put_u8(buf, SSOH_MS_QUARANTINE_STATE);
1254 wpabuf_put_be16(buf, 1); /* Flags: ExtState=0, f=0, qState=1 */
1255 wpabuf_put_be32(buf, 0xffffffff); /* ProbTime (hi) */
1256 wpabuf_put_be32(buf, 0xffffffff); /* ProbTime (lo) */
1257 wpabuf_put_be16(buf, 1); /* urlLenInBytes */
1258 wpabuf_put_u8(buf, 0); /* null termination for the url */
1259
1260 /* MS-Machine-Inventory-Ex */
1261 wpabuf_put_u8(buf, SSOH_MS_MACHINE_INVENTORY_EX);
1262 wpabuf_put_be32(buf, 0); /* Reserved
1263 * (note: Windows XP SP3 uses 0xdecafbad) */
1264 wpabuf_put_u8(buf, 1); /* ProductType: Client */
1265
1266 /* Update SSoH Length */
1267 end = wpabuf_put(buf, 0);
1268 WPA_PUT_BE16(ssoh_len, end - ssoh_len - 2);
1269
1270 /* TODO: SoHReportEntry TLV (zero or more) */
1271
1272 /* Update length fields */
1273 end = wpabuf_put(buf, 0);
1274 WPA_PUT_BE16(tlv_len, end - tlv_len - 2);
1275 WPA_PUT_BE16(tlv_len2, end - tlv_len2 - 2);
1276 WPA_PUT_BE16(outer_len, end - outer_len - 2);
1277 WPA_PUT_BE16(inner_len, end - inner_len - 2);
1278
1279 return buf;
1280 }
1281
1282
tncc_process_soh_request(int ver,const u8 * data,size_t len)1283 struct wpabuf * tncc_process_soh_request(int ver, const u8 *data, size_t len)
1284 {
1285 const u8 *pos;
1286
1287 wpa_hexdump(MSG_DEBUG, "TNC: SoH Request", data, len);
1288
1289 if (len < 12)
1290 return NULL;
1291
1292 /* SoH Request */
1293 pos = data;
1294
1295 /* TLV Type */
1296 if (WPA_GET_BE16(pos) != EAP_TLV_VENDOR_SPECIFIC_TLV)
1297 return NULL;
1298 pos += 2;
1299
1300 /* Length */
1301 if (WPA_GET_BE16(pos) < 8)
1302 return NULL;
1303 pos += 2;
1304
1305 /* Vendor_Id */
1306 if (WPA_GET_BE32(pos) != EAP_VENDOR_MICROSOFT)
1307 return NULL;
1308 pos += 4;
1309
1310 /* TLV Type */
1311 if (WPA_GET_BE16(pos) != 0x02 /* SoH request TLV */)
1312 return NULL;
1313
1314 wpa_printf(MSG_DEBUG, "TNC: SoH Request TLV received");
1315
1316 return tncc_build_soh(2);
1317 }
1318