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