Annotation of embedaddon/strongswan/src/libimcv/plugins/imv_attestation/imv_attestation_agent.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2011-2012 Sansar Choinyambuu
! 3: * Copyright (C) 2011-2015 Andreas Steffen
! 4: * HSR Hochschule fuer Technik Rapperswil
! 5: *
! 6: * This program is free software; you can redistribute it and/or modify it
! 7: * under the terms of the GNU General Public License as published by the
! 8: * Free Software Foundation; either version 2 of the License, or (at your
! 9: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 10: *
! 11: * This program is distributed in the hope that it will be useful, but
! 12: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 13: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 14: * for more details.
! 15: */
! 16:
! 17: #define _GNU_SOURCE /* for stdndup() */
! 18: #include <string.h>
! 19:
! 20: #include "imv_attestation_agent.h"
! 21: #include "imv_attestation_state.h"
! 22: #include "imv_attestation_process.h"
! 23: #include "imv_attestation_build.h"
! 24:
! 25: #include <imcv.h>
! 26: #include <imv/imv_agent.h>
! 27: #include <imv/imv_msg.h>
! 28: #include <imv/imv_session.h>
! 29: #include <imv/imv_os_info.h>
! 30: #include <generic/generic_attr_string.h>
! 31: #include <ietf/ietf_attr.h>
! 32: #include <ietf/ietf_attr_attr_request.h>
! 33: #include <ietf/ietf_attr_pa_tnc_error.h>
! 34: #include <ietf/ietf_attr_product_info.h>
! 35: #include <ietf/ietf_attr_string_version.h>
! 36: #include <ita/ita_attr.h>
! 37: #include <tcg/tcg_attr.h>
! 38: #include <tcg/pts/tcg_pts_attr_meas_algo.h>
! 39: #include <tcg/pts/tcg_pts_attr_proto_caps.h>
! 40: #include <tcg/pts/tcg_pts_attr_req_file_meas.h>
! 41: #include <tcg/pts/tcg_pts_attr_req_file_meta.h>
! 42: #include "tcg/seg/tcg_seg_attr_max_size.h"
! 43: #include "tcg/seg/tcg_seg_attr_seg_env.h"
! 44: #include <pts/pts.h>
! 45: #include <pts/pts_database.h>
! 46: #include <pts/pts_creds.h>
! 47: #include <pts/components/ita/ita_comp_func_name.h>
! 48:
! 49: #include <tncif_pa_subtypes.h>
! 50:
! 51: #include <pen/pen.h>
! 52: #include <utils/debug.h>
! 53: #include <credentials/credential_manager.h>
! 54: #include <collections/linked_list.h>
! 55:
! 56: #define FILE_MEAS_MAX_ATTR_SIZE 100000000
! 57:
! 58: typedef struct private_imv_attestation_agent_t private_imv_attestation_agent_t;
! 59:
! 60: /* Subscribed PA-TNC message subtypes */
! 61: static pen_type_t msg_types[] = {
! 62: { PEN_TCG, PA_SUBTYPE_TCG_PTS },
! 63: { PEN_IETF, PA_SUBTYPE_IETF_OPERATING_SYSTEM }
! 64: };
! 65:
! 66: /**
! 67: * Private data of an imv_attestation_agent_t object.
! 68: */
! 69: struct private_imv_attestation_agent_t {
! 70:
! 71: /**
! 72: * Public members of imv_attestation_agent_t
! 73: */
! 74: imv_agent_if_t public;
! 75:
! 76: /**
! 77: * IMV agent responsible for generic functions
! 78: */
! 79: imv_agent_t *agent;
! 80:
! 81: /**
! 82: * Supported PTS measurement algorithms
! 83: */
! 84: pts_meas_algorithms_t supported_algorithms;
! 85:
! 86: /**
! 87: * Supported PTS Diffie Hellman Groups
! 88: */
! 89: pts_dh_group_t supported_dh_groups;
! 90:
! 91: /**
! 92: * PTS file measurement database
! 93: */
! 94: pts_database_t *pts_db;
! 95:
! 96: /**
! 97: * PTS credentials
! 98: */
! 99: pts_creds_t *pts_creds;
! 100:
! 101: /**
! 102: * PTS credential manager
! 103: */
! 104: credential_manager_t *pts_credmgr;
! 105:
! 106: };
! 107:
! 108: METHOD(imv_agent_if_t, bind_functions, TNC_Result,
! 109: private_imv_attestation_agent_t *this, TNC_TNCS_BindFunctionPointer bind_function)
! 110: {
! 111: return this->agent->bind_functions(this->agent, bind_function);
! 112: }
! 113:
! 114: METHOD(imv_agent_if_t, notify_connection_change, TNC_Result,
! 115: private_imv_attestation_agent_t *this, TNC_ConnectionID id,
! 116: TNC_ConnectionState new_state)
! 117: {
! 118: TNC_IMV_Action_Recommendation rec;
! 119: imv_state_t *state;
! 120: imv_session_t *session;
! 121:
! 122: switch (new_state)
! 123: {
! 124: case TNC_CONNECTION_STATE_CREATE:
! 125: state = imv_attestation_state_create(id);
! 126: return this->agent->create_state(this->agent, state);
! 127: case TNC_CONNECTION_STATE_DELETE:
! 128: return this->agent->delete_state(this->agent, id);
! 129: case TNC_CONNECTION_STATE_ACCESS_ALLOWED:
! 130: case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
! 131: case TNC_CONNECTION_STATE_ACCESS_NONE:
! 132: if (this->agent->get_state(this->agent, id, &state) && imcv_db)
! 133: {
! 134: session = state->get_session(state);
! 135:
! 136: if (session->get_policy_started(session))
! 137: {
! 138: switch (new_state)
! 139: {
! 140: case TNC_CONNECTION_STATE_ACCESS_ALLOWED:
! 141: rec = TNC_IMV_ACTION_RECOMMENDATION_ALLOW;
! 142: break;
! 143: case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
! 144: rec = TNC_IMV_ACTION_RECOMMENDATION_ISOLATE;
! 145: break;
! 146: case TNC_CONNECTION_STATE_ACCESS_NONE:
! 147: default:
! 148: rec = TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS;
! 149: }
! 150: imcv_db->add_recommendation(imcv_db, session, rec);
! 151: if (!imcv_db->policy_script(imcv_db, session, FALSE))
! 152: {
! 153: DBG1(DBG_IMV, "error in policy script stop");
! 154: }
! 155: }
! 156: }
! 157: /* fall through to default state */
! 158: default:
! 159: return this->agent->change_state(this->agent, id, new_state, NULL);
! 160: }
! 161: }
! 162:
! 163: /**
! 164: * Process a received message
! 165: */
! 166: static TNC_Result receive_msg(private_imv_attestation_agent_t *this,
! 167: imv_state_t *state, imv_msg_t *in_msg)
! 168: {
! 169: imv_msg_t *out_msg;
! 170: imv_session_t *session;
! 171: imv_os_info_t *os_info;
! 172: enumerator_t *enumerator;
! 173: pa_tnc_attr_t *attr;
! 174: pen_type_t type;
! 175: TNC_Result result;
! 176: chunk_t os_name, os_version;
! 177: bool fatal_error = FALSE;
! 178:
! 179: /* generate an outgoing PA-TNC message - we might need it */
! 180: out_msg = imv_msg_create_as_reply(in_msg);
! 181: out_msg->set_msg_type(out_msg, msg_types[0]);
! 182:
! 183: /* parse received PA-TNC message and handle local and remote errors */
! 184: result = in_msg->receive(in_msg, out_msg, &fatal_error);
! 185: if (result != TNC_RESULT_SUCCESS)
! 186: {
! 187: out_msg->destroy(out_msg);
! 188: return result;
! 189: }
! 190:
! 191: session = state->get_session(state);
! 192: os_info = session->get_os_info(session);
! 193:
! 194: /* analyze PA-TNC attributes */
! 195: enumerator = in_msg->create_attribute_enumerator(in_msg);
! 196: while (enumerator->enumerate(enumerator, &attr))
! 197: {
! 198: type = attr->get_type(attr);
! 199:
! 200: if (type.vendor_id == PEN_IETF)
! 201: {
! 202: switch (type.type)
! 203: {
! 204: case IETF_ATTR_PA_TNC_ERROR:
! 205: {
! 206: ietf_attr_pa_tnc_error_t *error_attr;
! 207: pen_type_t error_code;
! 208: chunk_t msg_info;
! 209:
! 210: error_attr = (ietf_attr_pa_tnc_error_t*)attr;
! 211: error_code = error_attr->get_error_code(error_attr);
! 212:
! 213: if (error_code.vendor_id == PEN_TCG)
! 214: {
! 215: msg_info = error_attr->get_msg_info(error_attr);
! 216:
! 217: DBG1(DBG_IMV, "received TCG-PTS error '%N'",
! 218: pts_error_code_names, error_code.type);
! 219: DBG1(DBG_IMV, "error information: %B", &msg_info);
! 220:
! 221: /* TPM 2.0 doesn't return TPM Version Information */
! 222: if (error_code.type != TCG_PTS_TPM_VERS_NOT_SUPPORTED)
! 223: {
! 224: fatal_error = TRUE;
! 225: }
! 226: }
! 227: break;
! 228: }
! 229: case IETF_ATTR_PRODUCT_INFORMATION:
! 230: {
! 231: ietf_attr_product_info_t *attr_cast;
! 232: pen_t vendor_id;
! 233:
! 234: state->set_action_flags(state,
! 235: IMV_ATTESTATION_ATTR_PRODUCT_INFO);
! 236: attr_cast = (ietf_attr_product_info_t*)attr;
! 237: os_name = attr_cast->get_info(attr_cast, &vendor_id, NULL);
! 238: os_info->set_name(os_info, os_name);
! 239:
! 240: if (vendor_id != PEN_IETF)
! 241: {
! 242: DBG1(DBG_IMV, "operating system name is '%.*s' "
! 243: "from vendor %N", os_name.len, os_name.ptr,
! 244: pen_names, vendor_id);
! 245: }
! 246: else
! 247: {
! 248: DBG1(DBG_IMV, "operating system name is '%.*s'",
! 249: os_name.len, os_name.ptr);
! 250: }
! 251: break;
! 252: }
! 253: case IETF_ATTR_STRING_VERSION:
! 254: {
! 255: ietf_attr_string_version_t *attr_cast;
! 256:
! 257: state->set_action_flags(state,
! 258: IMV_ATTESTATION_ATTR_STRING_VERSION);
! 259: attr_cast = (ietf_attr_string_version_t*)attr;
! 260: os_version = attr_cast->get_version(attr_cast, NULL, NULL);
! 261: os_info->set_version(os_info, os_version);
! 262:
! 263: if (os_version.len)
! 264: {
! 265: DBG1(DBG_IMV, "operating system version is '%.*s'",
! 266: os_version.len, os_version.ptr);
! 267: }
! 268: break;
! 269: }
! 270: default:
! 271: break;
! 272: }
! 273: }
! 274: else if (type.vendor_id == PEN_ITA)
! 275: {
! 276: switch (type.type)
! 277: {
! 278: case ITA_ATTR_DEVICE_ID:
! 279: {
! 280: chunk_t value;
! 281:
! 282: state->set_action_flags(state,
! 283: IMV_ATTESTATION_ATTR_DEVICE_ID);
! 284:
! 285: value = attr->get_value(attr);
! 286: DBG1(DBG_IMV, "device ID is %.*s", value.len, value.ptr);
! 287: session->set_device_id(session, value);
! 288: break;
! 289: }
! 290: default:
! 291: break;
! 292: }
! 293: }
! 294: else if (type.vendor_id == PEN_TCG)
! 295: {
! 296: if (!imv_attestation_process(attr, out_msg, state,
! 297: this->supported_algorithms, this->supported_dh_groups,
! 298: this->pts_db, this->pts_credmgr))
! 299: {
! 300: result = TNC_RESULT_FATAL;
! 301: break;
! 302: }
! 303: }
! 304: }
! 305: enumerator->destroy(enumerator);
! 306:
! 307: if (fatal_error || result != TNC_RESULT_SUCCESS)
! 308: {
! 309: state->set_recommendation(state,
! 310: TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
! 311: TNC_IMV_EVALUATION_RESULT_ERROR);
! 312: result = out_msg->send_assessment(out_msg);
! 313: if (result == TNC_RESULT_SUCCESS)
! 314: {
! 315: result = this->agent->provide_recommendation(this->agent, state);
! 316: }
! 317: }
! 318: else
! 319: {
! 320: /* send PA-TNC message with the EXCL flag set */
! 321: result = out_msg->send(out_msg, TRUE);
! 322: }
! 323: out_msg->destroy(out_msg);
! 324:
! 325: return result;
! 326: }
! 327:
! 328: METHOD(imv_agent_if_t, receive_message, TNC_Result,
! 329: private_imv_attestation_agent_t *this, TNC_ConnectionID id,
! 330: TNC_MessageType msg_type, chunk_t msg)
! 331: {
! 332: imv_state_t *state;
! 333: imv_msg_t *in_msg;
! 334: TNC_Result result;
! 335:
! 336: if (!this->agent->get_state(this->agent, id, &state))
! 337: {
! 338: return TNC_RESULT_FATAL;
! 339: }
! 340: in_msg = imv_msg_create_from_data(this->agent, state, id, msg_type, msg);
! 341: result = receive_msg(this, state, in_msg);
! 342: in_msg->destroy(in_msg);
! 343:
! 344: return result;
! 345: }
! 346:
! 347: METHOD(imv_agent_if_t, receive_message_long, TNC_Result,
! 348: private_imv_attestation_agent_t *this, TNC_ConnectionID id,
! 349: TNC_UInt32 src_imc_id, TNC_UInt32 dst_imv_id,
! 350: TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype, chunk_t msg)
! 351: {
! 352: imv_state_t *state;
! 353: imv_msg_t *in_msg;
! 354: TNC_Result result;
! 355:
! 356: if (!this->agent->get_state(this->agent, id, &state))
! 357: {
! 358: return TNC_RESULT_FATAL;
! 359: }
! 360: in_msg = imv_msg_create_from_long_data(this->agent, state, id,
! 361: src_imc_id, dst_imv_id, msg_vid, msg_subtype, msg);
! 362: result = receive_msg(this, state, in_msg);
! 363: in_msg->destroy(in_msg);
! 364:
! 365: return result;
! 366: }
! 367:
! 368: /**
! 369: * Build an IETF Attribute Request attribute for missing attributes
! 370: */
! 371: static pa_tnc_attr_t* build_attr_request(uint32_t received)
! 372: {
! 373: pa_tnc_attr_t *attr;
! 374: ietf_attr_attr_request_t *attr_cast;
! 375:
! 376: attr = ietf_attr_attr_request_create(PEN_RESERVED, 0);
! 377: attr_cast = (ietf_attr_attr_request_t*)attr;
! 378:
! 379: if (!(received & IMV_ATTESTATION_ATTR_PRODUCT_INFO) ||
! 380: !(received & IMV_ATTESTATION_ATTR_STRING_VERSION))
! 381: {
! 382: attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_PRODUCT_INFORMATION);
! 383: attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_STRING_VERSION);
! 384: }
! 385: if (!(received & IMV_ATTESTATION_ATTR_DEVICE_ID))
! 386: {
! 387: attr_cast->add(attr_cast, PEN_ITA, ITA_ATTR_DEVICE_ID);
! 388: }
! 389:
! 390: return attr;
! 391: }
! 392:
! 393: METHOD(imv_agent_if_t, batch_ending, TNC_Result,
! 394: private_imv_attestation_agent_t *this, TNC_ConnectionID id)
! 395: {
! 396: imv_msg_t *out_msg;
! 397: imv_state_t *state;
! 398: imv_session_t *session;
! 399: imv_attestation_state_t *attestation_state;
! 400: imv_attestation_handshake_state_t handshake_state;
! 401: imv_workitem_t *workitem;
! 402: TNC_IMV_Action_Recommendation rec;
! 403: TNC_IMV_Evaluation_Result eval;
! 404: TNC_IMVID imv_id;
! 405: TNC_Result result = TNC_RESULT_SUCCESS;
! 406: pts_t *pts;
! 407: int pid;
! 408: uint32_t actions;
! 409: enumerator_t *enumerator;
! 410:
! 411: if (!this->agent->get_state(this->agent, id, &state))
! 412: {
! 413: return TNC_RESULT_FATAL;
! 414: }
! 415: attestation_state = (imv_attestation_state_t*)state;
! 416: pts = attestation_state->get_pts(attestation_state);
! 417: handshake_state = attestation_state->get_handshake_state(attestation_state);
! 418: actions = state->get_action_flags(state);
! 419: session = state->get_session(state);
! 420: imv_id = this->agent->get_id(this->agent);
! 421:
! 422: /* exit if a recommendation has already been provided */
! 423: if (actions & IMV_ATTESTATION_REC)
! 424: {
! 425: return TNC_RESULT_SUCCESS;
! 426: }
! 427:
! 428: /* send an IETF attribute request if no platform info was received */
! 429: if (!(actions & IMV_ATTESTATION_ATTR_REQ))
! 430: {
! 431: if ((actions & IMV_ATTESTATION_ATTR_MUST) != IMV_ATTESTATION_ATTR_MUST)
! 432: {
! 433: imv_msg_t *os_msg;
! 434:
! 435: /* create attribute request for missing mandatory attributes */
! 436: os_msg = imv_msg_create(this->agent, state, id, imv_id,
! 437: TNC_IMCID_ANY, msg_types[1]);
! 438: os_msg->add_attribute(os_msg, build_attr_request(actions));
! 439: result = os_msg->send(os_msg, FALSE);
! 440: os_msg->destroy(os_msg);
! 441:
! 442: if (result != TNC_RESULT_SUCCESS)
! 443: {
! 444: return result;
! 445: }
! 446: }
! 447: state->set_action_flags(state, IMV_ATTESTATION_ATTR_REQ);
! 448: }
! 449:
! 450: if (!session->get_policy_started(session) &&
! 451: (actions & IMV_ATTESTATION_ATTR_PRODUCT_INFO) &&
! 452: (actions & IMV_ATTESTATION_ATTR_STRING_VERSION) &&
! 453: (actions & IMV_ATTESTATION_ATTR_DEVICE_ID))
! 454: {
! 455: if (imcv_db)
! 456: {
! 457: /* start the policy script */
! 458: if (!imcv_db->policy_script(imcv_db, session, TRUE))
! 459: {
! 460: DBG1(DBG_IMV, "error in policy script start");
! 461: }
! 462: }
! 463: else
! 464: {
! 465: DBG2(DBG_IMV, "no workitems available - no evaluation possible");
! 466: state->set_recommendation(state,
! 467: TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
! 468: TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
! 469: session->set_policy_started(session, TRUE);
! 470: }
! 471: }
! 472:
! 473: if (handshake_state == IMV_ATTESTATION_STATE_INIT)
! 474: {
! 475: size_t max_attr_size = FILE_MEAS_MAX_ATTR_SIZE;
! 476: size_t max_seg_size;
! 477: seg_contract_t *contract;
! 478: seg_contract_manager_t *contracts;
! 479: pa_tnc_attr_t *attr;
! 480: pts_proto_caps_flag_t flags;
! 481: char buf[BUF_LEN];
! 482:
! 483: out_msg = imv_msg_create(this->agent, state, id, imv_id, TNC_IMCID_ANY,
! 484: msg_types[0]);
! 485:
! 486: /* Determine maximum PA-TNC attribute segment size */
! 487: max_seg_size = state->get_max_msg_len(state)
! 488: - PA_TNC_HEADER_SIZE
! 489: - PA_TNC_ATTR_HEADER_SIZE
! 490: - TCG_SEG_ATTR_SEG_ENV_HEADER;
! 491:
! 492: /* Announce support of PA-TNC segmentation to IMC */
! 493: contract = seg_contract_create(msg_types[0], max_attr_size,
! 494: max_seg_size, TRUE, imv_id, FALSE);
! 495: contract->get_info_string(contract, buf, BUF_LEN, TRUE);
! 496: DBG2(DBG_IMV, "%s", buf);
! 497: contracts = state->get_contracts(state);
! 498: contracts->add_contract(contracts, contract);
! 499: attr = tcg_seg_attr_max_size_create(max_attr_size, max_seg_size, TRUE);
! 500: out_msg->add_attribute(out_msg, attr);
! 501:
! 502: /* Send Request Protocol Capabilities attribute */
! 503: flags = pts->get_proto_caps(pts);
! 504: attr = tcg_pts_attr_proto_caps_create(flags, TRUE);
! 505: attr->set_noskip_flag(attr, TRUE);
! 506: out_msg->add_attribute(out_msg, attr);
! 507:
! 508: /* Send Measurement Algorithms attribute */
! 509: attr = tcg_pts_attr_meas_algo_create(this->supported_algorithms, FALSE);
! 510: attr->set_noskip_flag(attr, TRUE);
! 511: out_msg->add_attribute(out_msg, attr);
! 512:
! 513: attestation_state->set_handshake_state(attestation_state,
! 514: IMV_ATTESTATION_STATE_DISCOVERY);
! 515:
! 516: /* send these initial PTS attributes and exit */
! 517: result = out_msg->send(out_msg, FALSE);
! 518: out_msg->destroy(out_msg);
! 519:
! 520: return result;
! 521: }
! 522:
! 523: /* exit if we are not ready yet for PTS measurements */
! 524: if (!(actions & IMV_ATTESTATION_ALGO))
! 525: {
! 526: return TNC_RESULT_SUCCESS;
! 527: }
! 528:
! 529: session->get_session_id(session, &pid, NULL);
! 530: pts->set_platform_id(pts, pid);
! 531:
! 532: /* create an empty out message - we might need it */
! 533: out_msg = imv_msg_create(this->agent, state, id, imv_id, TNC_IMCID_ANY,
! 534: msg_types[0]);
! 535:
! 536: /* establish the PTS measurements to be taken */
! 537: if (!(actions & IMV_ATTESTATION_FILE_MEAS))
! 538: {
! 539: bool is_dir, no_workitems = TRUE;
! 540: uint32_t delimiter = SOLIDUS_UTF;
! 541: uint16_t request_id;
! 542: pa_tnc_attr_t *attr;
! 543: char *pathname;
! 544:
! 545: attestation_state->set_handshake_state(attestation_state,
! 546: IMV_ATTESTATION_STATE_END);
! 547:
! 548: enumerator = session->create_workitem_enumerator(session);
! 549: if (enumerator)
! 550: {
! 551: while (enumerator->enumerate(enumerator, &workitem))
! 552: {
! 553: if (workitem->get_imv_id(workitem) != TNC_IMVID_ANY)
! 554: {
! 555: continue;
! 556: }
! 557:
! 558: switch (workitem->get_type(workitem))
! 559: {
! 560: case IMV_WORKITEM_FILE_REF_MEAS:
! 561: case IMV_WORKITEM_FILE_MEAS:
! 562: case IMV_WORKITEM_FILE_META:
! 563: is_dir = FALSE;
! 564: break;
! 565: case IMV_WORKITEM_DIR_REF_MEAS:
! 566: case IMV_WORKITEM_DIR_MEAS:
! 567: case IMV_WORKITEM_DIR_META:
! 568: is_dir = TRUE;
! 569: break;
! 570: case IMV_WORKITEM_TPM_ATTEST:
! 571: {
! 572: pts_component_t *comp;
! 573: pts_comp_func_name_t *comp_name;
! 574: bool no_d_flag, no_t_flag;
! 575: char result_str[BUF_LEN];
! 576:
! 577: workitem->set_imv_id(workitem, imv_id);
! 578: no_workitems = FALSE;
! 579: no_d_flag = !(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_D);
! 580: no_t_flag = !(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_T);
! 581: if (no_d_flag || no_t_flag)
! 582: {
! 583: snprintf(result_str, BUF_LEN, "%s%s%s",
! 584: (no_t_flag) ? "no TPM available" : "",
! 585: (no_t_flag && no_d_flag) ? ", " : "",
! 586: (no_d_flag) ? "no DH nonce negotiation" : "");
! 587: eval = TNC_IMV_EVALUATION_RESULT_ERROR;
! 588: session->remove_workitem(session, enumerator);
! 589: rec = workitem->set_result(workitem, result_str, eval);
! 590: state->update_recommendation(state, rec, eval);
! 591: imcv_db->finalize_workitem(imcv_db, workitem);
! 592: workitem->destroy(workitem);
! 593: continue;
! 594: }
! 595:
! 596: /* do TPM BIOS measurements */
! 597: if (strchr(workitem->get_arg_str(workitem), 'B'))
! 598: {
! 599: comp_name = pts_comp_func_name_create(PEN_ITA,
! 600: PTS_ITA_COMP_FUNC_NAME_IMA,
! 601: PTS_ITA_QUALIFIER_FLAG_KERNEL |
! 602: PTS_ITA_QUALIFIER_TYPE_TRUSTED);
! 603: comp = attestation_state->create_component(
! 604: attestation_state, comp_name,
! 605: 0, this->pts_db);
! 606: if (!comp)
! 607: {
! 608: comp_name->log(comp_name, "unregistered ");
! 609: }
! 610: comp_name->destroy(comp_name);
! 611: }
! 612:
! 613: /* do TPM IMA measurements */
! 614: if (strchr(workitem->get_arg_str(workitem), 'I'))
! 615: {
! 616: comp_name = pts_comp_func_name_create(PEN_ITA,
! 617: PTS_ITA_COMP_FUNC_NAME_IMA,
! 618: PTS_ITA_QUALIFIER_FLAG_KERNEL |
! 619: PTS_ITA_QUALIFIER_TYPE_OS);
! 620: comp = attestation_state->create_component(
! 621: attestation_state, comp_name,
! 622: 0, this->pts_db);
! 623: if (!comp)
! 624: {
! 625: comp_name->log(comp_name, "unregistered ");
! 626: }
! 627: comp_name->destroy(comp_name);
! 628: }
! 629:
! 630: /* do TPM TRUSTED BOOT measurements */
! 631: if (strchr(workitem->get_arg_str(workitem), 'T'))
! 632: {
! 633: comp_name = pts_comp_func_name_create(PEN_ITA,
! 634: PTS_ITA_COMP_FUNC_NAME_TBOOT,
! 635: PTS_ITA_QUALIFIER_FLAG_KERNEL |
! 636: PTS_ITA_QUALIFIER_TYPE_TRUSTED);
! 637: comp = attestation_state->create_component(
! 638: attestation_state, comp_name,
! 639: 0, this->pts_db);
! 640: if (!comp)
! 641: {
! 642: comp_name->log(comp_name, "unregistered ");
! 643: }
! 644: comp_name->destroy(comp_name);
! 645: }
! 646: attestation_state->set_handshake_state(attestation_state,
! 647: IMV_ATTESTATION_STATE_NONCE_REQ);
! 648: continue;
! 649: }
! 650: default:
! 651: continue;
! 652: }
! 653:
! 654: /* initiate file and directory measurements */
! 655: pathname = this->pts_db->get_pathname(this->pts_db, is_dir,
! 656: workitem->get_arg_int(workitem));
! 657: if (!pathname)
! 658: {
! 659: continue;
! 660: }
! 661: workitem->set_imv_id(workitem, imv_id);
! 662: no_workitems = FALSE;
! 663:
! 664: if (workitem->get_type(workitem) == IMV_WORKITEM_FILE_META)
! 665: {
! 666: TNC_IMV_Action_Recommendation rec;
! 667: TNC_IMV_Evaluation_Result eval;
! 668: char result_str[BUF_LEN];
! 669:
! 670: DBG2(DBG_IMV, "IMV %d requests metadata for %s '%s'",
! 671: imv_id, is_dir ? "directory" : "file", pathname);
! 672:
! 673: /* currently just fire and forget metadata requests */
! 674: attr = tcg_pts_attr_req_file_meta_create(is_dir,
! 675: delimiter, pathname);
! 676: snprintf(result_str, BUF_LEN, "%s metadata requested",
! 677: is_dir ? "directory" : "file");
! 678: eval = TNC_IMV_EVALUATION_RESULT_COMPLIANT;
! 679: session->remove_workitem(session, enumerator);
! 680: rec = workitem->set_result(workitem, result_str, eval);
! 681: state->update_recommendation(state, rec, eval);
! 682: imcv_db->finalize_workitem(imcv_db, workitem);
! 683: workitem->destroy(workitem);
! 684: }
! 685: else
! 686: {
! 687: /* use lower 16 bits of the workitem ID as request ID */
! 688: request_id = workitem->get_id(workitem) & 0xffff;
! 689:
! 690: DBG2(DBG_IMV, "IMV %d requests measurement %d for %s '%s'",
! 691: imv_id, request_id, is_dir ? "directory" : "file",
! 692: pathname);
! 693: attr = tcg_pts_attr_req_file_meas_create(is_dir, request_id,
! 694: delimiter, pathname);
! 695: }
! 696: free(pathname);
! 697: attr->set_noskip_flag(attr, TRUE);
! 698: out_msg->add_attribute(out_msg, attr);
! 699: }
! 700: enumerator->destroy(enumerator);
! 701:
! 702: /* sent all file and directory measurement and metadata requests */
! 703: state->set_action_flags(state, IMV_ATTESTATION_FILE_MEAS);
! 704:
! 705: if (no_workitems)
! 706: {
! 707: DBG2(DBG_IMV, "IMV %d has no workitems - "
! 708: "no evaluation requested", imv_id);
! 709: state->set_recommendation(state,
! 710: TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
! 711: TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
! 712: }
! 713: }
! 714: }
! 715:
! 716: /* check the IMV state for the next PA-TNC attributes to send */
! 717: enumerator = session->create_workitem_enumerator(session);
! 718: while (enumerator->enumerate(enumerator, &workitem))
! 719: {
! 720: if (workitem->get_type(workitem) == IMV_WORKITEM_TPM_ATTEST)
! 721: {
! 722: if (!imv_attestation_build(out_msg, state,
! 723: this->supported_dh_groups, this->pts_db))
! 724: {
! 725: imv_reason_string_t *reason_string;
! 726: chunk_t result;
! 727: char *result_str;
! 728:
! 729: reason_string = imv_reason_string_create("en", ", ");
! 730: attestation_state->add_comp_evid_reasons(attestation_state,
! 731: reason_string);
! 732: result = reason_string->get_encoding(reason_string);
! 733: result_str = strndup(result.ptr, result.len);
! 734: reason_string->destroy(reason_string);
! 735:
! 736: eval = TNC_IMV_EVALUATION_RESULT_ERROR;
! 737: session->remove_workitem(session, enumerator);
! 738: rec = workitem->set_result(workitem, result_str, eval);
! 739: state->update_recommendation(state, rec, eval);
! 740: imcv_db->finalize_workitem(imcv_db, workitem);
! 741: }
! 742: break;
! 743: }
! 744: }
! 745: enumerator->destroy(enumerator);
! 746:
! 747: /* finalized all workitems? */
! 748: if (session->get_policy_started(session) &&
! 749: session->get_workitem_count(session, imv_id) == 0 &&
! 750: attestation_state->get_handshake_state(attestation_state) ==
! 751: IMV_ATTESTATION_STATE_END)
! 752: {
! 753: result = out_msg->send_assessment(out_msg);
! 754: out_msg->destroy(out_msg);
! 755: state->set_action_flags(state, IMV_ATTESTATION_REC);
! 756:
! 757: if (result != TNC_RESULT_SUCCESS)
! 758: {
! 759: return result;
! 760: }
! 761: return this->agent->provide_recommendation(this->agent, state);
! 762: }
! 763:
! 764: /* send non-empty PA-TNC message with excl flag not set */
! 765: if (out_msg->get_attribute_count(out_msg))
! 766: {
! 767: result = out_msg->send(out_msg, FALSE);
! 768: }
! 769: out_msg->destroy(out_msg);
! 770:
! 771: return result;
! 772: }
! 773:
! 774: METHOD(imv_agent_if_t, solicit_recommendation, TNC_Result,
! 775: private_imv_attestation_agent_t *this, TNC_ConnectionID id)
! 776: {
! 777: TNC_IMVID imv_id;
! 778: imv_state_t *state;
! 779: imv_attestation_state_t *attestation_state;
! 780: imv_session_t *session;
! 781:
! 782: if (!this->agent->get_state(this->agent, id, &state))
! 783: {
! 784: return TNC_RESULT_FATAL;
! 785: }
! 786: attestation_state = (imv_attestation_state_t*)state;
! 787: session = state->get_session(state);
! 788: imv_id = this->agent->get_id(this->agent);
! 789:
! 790: if (imcv_db)
! 791: {
! 792: TNC_IMV_Evaluation_Result eval;
! 793: TNC_IMV_Action_Recommendation rec;
! 794: imv_workitem_t *workitem;
! 795: enumerator_t *enumerator;
! 796: int pending_file_meas = 0;
! 797: char *result_str;
! 798: chunk_t result_buf;
! 799: bio_writer_t *result;
! 800:
! 801: enumerator = session->create_workitem_enumerator(session);
! 802: if (enumerator)
! 803: {
! 804: while (enumerator->enumerate(enumerator, &workitem))
! 805: {
! 806: if (workitem->get_imv_id(workitem) != imv_id)
! 807: {
! 808: continue;
! 809: }
! 810: result = bio_writer_create(128);
! 811:
! 812: switch (workitem->get_type(workitem))
! 813: {
! 814: case IMV_WORKITEM_FILE_REF_MEAS:
! 815: case IMV_WORKITEM_FILE_MEAS:
! 816: case IMV_WORKITEM_DIR_REF_MEAS:
! 817: case IMV_WORKITEM_DIR_MEAS:
! 818: result_str = "pending file measurements";
! 819: pending_file_meas++;
! 820: break;
! 821: case IMV_WORKITEM_TPM_ATTEST:
! 822: attestation_state->finalize_components(attestation_state,
! 823: result);
! 824: result->write_data(result,
! 825: chunk_from_str("; pending component evidence"));
! 826: result->write_uint8(result, '\0');
! 827: result_buf = result->get_buf(result);
! 828: result_str = result_buf.ptr;
! 829: break;
! 830: default:
! 831: result->destroy(result);
! 832: continue;
! 833: }
! 834: session->remove_workitem(session, enumerator);
! 835: eval = TNC_IMV_EVALUATION_RESULT_ERROR;
! 836: rec = workitem->set_result(workitem, result_str, eval);
! 837: state->update_recommendation(state, rec, eval);
! 838: imcv_db->finalize_workitem(imcv_db, workitem);
! 839: workitem->destroy(workitem);
! 840: result->destroy(result);
! 841: }
! 842: enumerator->destroy(enumerator);
! 843:
! 844: if (pending_file_meas)
! 845: {
! 846: DBG1(DBG_IMV, "failure due to %d pending file measurements",
! 847: pending_file_meas);
! 848: attestation_state->set_measurement_error(attestation_state,
! 849: IMV_ATTESTATION_ERROR_FILE_MEAS_PEND);
! 850: }
! 851: }
! 852: }
! 853: return this->agent->provide_recommendation(this->agent, state);
! 854: }
! 855:
! 856: METHOD(imv_agent_if_t, destroy, void,
! 857: private_imv_attestation_agent_t *this)
! 858: {
! 859: if (this->pts_creds)
! 860: {
! 861: this->pts_credmgr->remove_set(this->pts_credmgr,
! 862: this->pts_creds->get_set(this->pts_creds));
! 863: this->pts_creds->destroy(this->pts_creds);
! 864: }
! 865: DESTROY_IF(this->pts_db);
! 866: DESTROY_IF(this->pts_credmgr);
! 867: DESTROY_IF(this->agent);
! 868: free(this);
! 869: }
! 870:
! 871: /**
! 872: * Described in header.
! 873: */
! 874: imv_agent_if_t *imv_attestation_agent_create(const char *name, TNC_IMVID id,
! 875: TNC_Version *actual_version)
! 876: {
! 877: private_imv_attestation_agent_t *this;
! 878: imv_agent_t *agent;
! 879: char *hash_alg, *dh_group, *cadir;
! 880: bool mandatory_dh_groups;
! 881:
! 882: agent = imv_agent_create(name, msg_types, countof(msg_types), id,
! 883: actual_version);
! 884: if (!agent)
! 885: {
! 886: return NULL;
! 887: }
! 888:
! 889: hash_alg = lib->settings->get_str(lib->settings,
! 890: "%s.plugins.imv-attestation.hash_algorithm", "sha256", lib->ns);
! 891: dh_group = lib->settings->get_str(lib->settings,
! 892: "%s.plugins.imv-attestation.dh_group", "ecp256", lib->ns);
! 893: mandatory_dh_groups = lib->settings->get_bool(lib->settings,
! 894: "%s.plugins.imv-attestation.mandatory_dh_groups", TRUE, lib->ns);
! 895: cadir = lib->settings->get_str(lib->settings,
! 896: "%s.plugins.imv-attestation.cadir", NULL, lib->ns);
! 897:
! 898: INIT(this,
! 899: .public = {
! 900: .bind_functions = _bind_functions,
! 901: .notify_connection_change = _notify_connection_change,
! 902: .receive_message = _receive_message,
! 903: .receive_message_long = _receive_message_long,
! 904: .batch_ending = _batch_ending,
! 905: .solicit_recommendation = _solicit_recommendation,
! 906: .destroy = _destroy,
! 907: },
! 908: .agent = agent,
! 909: .supported_algorithms = PTS_MEAS_ALGO_NONE,
! 910: .supported_dh_groups = PTS_DH_GROUP_NONE,
! 911: .pts_credmgr = credential_manager_create(),
! 912: .pts_creds = pts_creds_create(cadir),
! 913: .pts_db = pts_database_create(imcv_db),
! 914: );
! 915:
! 916: if (!pts_meas_algo_probe(&this->supported_algorithms) ||
! 917: !pts_dh_group_probe(&this->supported_dh_groups, mandatory_dh_groups) ||
! 918: !pts_meas_algo_update(hash_alg, &this->supported_algorithms) ||
! 919: !pts_dh_group_update(dh_group, &this->supported_dh_groups))
! 920: {
! 921: destroy(this);
! 922: return NULL;
! 923: }
! 924:
! 925: if (this->pts_creds)
! 926: {
! 927: this->pts_credmgr->add_set(this->pts_credmgr,
! 928: this->pts_creds->get_set(this->pts_creds));
! 929: }
! 930:
! 931: return &this->public;
! 932: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>