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