Annotation of embedaddon/strongswan/src/libimcv/plugins/imv_attestation/imv_attestation_agent.c, revision 1.1.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>