Annotation of embedaddon/strongswan/src/libimcv/plugins/imv_attestation/imv_attestation_agent.c, revision 1.1.1.2

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: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>