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