Annotation of embedaddon/strongswan/src/libimcv/pts/pts.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) 2012-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: #include "pts.h"
                     18: 
                     19: #include <utils/debug.h>
                     20: #include <crypto/hashers/hasher.h>
                     21: #include <bio/bio_writer.h>
                     22: #include <bio/bio_reader.h>
                     23: 
                     24: #include <tpm_tss_trousers.h>
                     25: 
                     26: #include <sys/types.h>
                     27: #include <sys/stat.h>
                     28: #include <libgen.h>
                     29: #include <unistd.h>
1.1.1.2 ! misho      30: #include <dirent.h>
1.1       misho      31: #include <errno.h>
                     32: 
1.1.1.2 ! misho      33: 
1.1       misho      34: #ifndef TPM_TAG_QUOTE_INFO2
                     35: #define TPM_TAG_QUOTE_INFO2 0x0036
                     36: #endif
                     37: #ifndef TPM_LOC_ZERO
                     38: #define TPM_LOC_ZERO 0x01
                     39: #endif
                     40: 
                     41: typedef struct private_pts_t private_pts_t;
                     42: 
                     43: /**
                     44:  * Private data of a pts_t object.
                     45:  *
                     46:  */
                     47: struct private_pts_t {
                     48: 
                     49:        /**
                     50:         * Public pts_t interface.
                     51:         */
                     52:        pts_t public;
                     53: 
                     54:        /**
                     55:         * PTS Protocol Capabilities
                     56:         */
                     57:        pts_proto_caps_flag_t proto_caps;
                     58: 
                     59:        /**
                     60:         * PTS Measurement Algorithm
                     61:         */
                     62:        pts_meas_algorithms_t algorithm;
                     63: 
                     64:        /**
                     65:         * DH Hash Algorithm
                     66:         */
                     67:        pts_meas_algorithms_t dh_hash_algorithm;
                     68: 
                     69:        /**
                     70:         * PTS Diffie-Hellman Secret
                     71:         */
                     72:        diffie_hellman_t *dh;
                     73: 
                     74:        /**
                     75:         * PTS Diffie-Hellman Initiator Nonce
                     76:         */
                     77:        chunk_t initiator_nonce;
                     78: 
                     79:        /**
                     80:         * PTS Diffie-Hellman Responder Nonce
                     81:         */
                     82:        chunk_t responder_nonce;
                     83: 
                     84:        /**
                     85:         * Secret assessment value to be used for TPM Quote as an external data
                     86:         */
                     87:        chunk_t secret;
                     88: 
                     89:        /**
                     90:         * Primary key of platform entry in database
                     91:         */
                     92:        int platform_id;
                     93: 
                     94:        /**
1.1.1.2 ! misho      95:         * List of directory symlinks received from IMC
        !            96:         */
        !            97:        pts_symlinks_t *symlinks;
        !            98: 
        !            99:        /**
1.1       misho     100:         * TRUE if IMC-PTS, FALSE if IMV-PTS
                    101:         */
                    102:        bool is_imc;
                    103: 
                    104:        /**
1.1.1.2 ! misho     105:         * IMC-PTS: own TPM / IMV-PTS: unused
1.1       misho     106:         */
                    107:        tpm_tss_t *tpm;
                    108: 
                    109:        /**
1.1.1.2 ! misho     110:         * IMC-PTS: own TPM version / IMV-PTS: peer TPM version
        !           111:         */
        !           112:        tpm_version_t tpm_version;
        !           113: 
        !           114:        /**
        !           115:         * Contains a TPM Version Info struct
1.1       misho     116:         */
                    117:        chunk_t tpm_version_info;
                    118: 
                    119:        /**
                    120:         * AIK object handle
                    121:         */
                    122:        uint32_t aik_handle;
                    123: 
                    124:        /**
                    125:         * Contains an Attestation Identity Key Certificate
                    126:         */
                    127:        certificate_t *aik_cert;
                    128: 
                    129:        /**
                    130:         * Primary key referencing AIK in database
                    131:         */
                    132:        int aik_id;
                    133: 
                    134:        /**
                    135:         * Shadow PCR set
                    136:         */
                    137:        pts_pcr_t *pcrs;
                    138: 
                    139: };
                    140: 
                    141: METHOD(pts_t, get_proto_caps, pts_proto_caps_flag_t,
                    142:           private_pts_t *this)
                    143: {
                    144:        return this->proto_caps;
                    145: }
                    146: 
                    147: METHOD(pts_t, set_proto_caps, void,
                    148:        private_pts_t *this, pts_proto_caps_flag_t flags)
                    149: {
                    150:        this->proto_caps = flags;
                    151:        DBG2(DBG_PTS, "supported PTS protocol capabilities: %s%s%s%s%s",
                    152:                 flags & PTS_PROTO_CAPS_C ? "C" : ".",
                    153:                 flags & PTS_PROTO_CAPS_V ? "V" : ".",
                    154:                 flags & PTS_PROTO_CAPS_D ? "D" : ".",
                    155:                 flags & PTS_PROTO_CAPS_T ? "T" : ".",
                    156:                 flags & PTS_PROTO_CAPS_X ? "X" : ".");
                    157: }
                    158: 
                    159: METHOD(pts_t, get_meas_algorithm, pts_meas_algorithms_t,
                    160:        private_pts_t *this)
                    161: {
                    162:        return this->algorithm;
                    163: }
                    164: 
                    165: METHOD(pts_t, set_meas_algorithm, void,
                    166:        private_pts_t *this, pts_meas_algorithms_t algorithm)
                    167: {
                    168:        hash_algorithm_t hash_alg;
                    169: 
                    170:        hash_alg = pts_meas_algo_to_hash(algorithm);
                    171:        DBG2(DBG_PTS, "selected PTS measurement algorithm is %N",
                    172:                                   hash_algorithm_names, hash_alg);
                    173:        if (hash_alg != HASH_UNKNOWN)
                    174:        {
                    175:                this->algorithm = algorithm;
                    176:        }
                    177: }
                    178: 
                    179: METHOD(pts_t, get_dh_hash_algorithm, pts_meas_algorithms_t,
                    180:        private_pts_t *this)
                    181: {
                    182:        return this->dh_hash_algorithm;
                    183: }
                    184: 
                    185: METHOD(pts_t, set_dh_hash_algorithm, void,
                    186:        private_pts_t *this, pts_meas_algorithms_t algorithm)
                    187: {
                    188:        hash_algorithm_t hash_alg;
                    189: 
                    190:        hash_alg = pts_meas_algo_to_hash(algorithm);
                    191:        DBG2(DBG_PTS, "selected DH hash algorithm is %N",
                    192:                                   hash_algorithm_names, hash_alg);
                    193:        if (hash_alg != HASH_UNKNOWN)
                    194:        {
                    195:                this->dh_hash_algorithm = algorithm;
                    196:        }
                    197: }
                    198: 
                    199: METHOD(pts_t, create_dh_nonce, bool,
                    200:        private_pts_t *this, pts_dh_group_t group, int nonce_len)
                    201: {
                    202:        diffie_hellman_group_t dh_group;
                    203:        chunk_t *nonce;
                    204:        rng_t *rng;
                    205: 
                    206:        dh_group = pts_dh_group_to_ike(group);
                    207:        DBG2(DBG_PTS, "selected PTS DH group is %N",
                    208:                                   diffie_hellman_group_names, dh_group);
                    209:        DESTROY_IF(this->dh);
                    210:        this->dh = lib->crypto->create_dh(lib->crypto, dh_group);
                    211: 
                    212:        rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
                    213:        if (!rng)
                    214:        {
                    215:                DBG1(DBG_PTS, "no rng available");
                    216:                return FALSE;
                    217:        }
                    218:        DBG2(DBG_PTS, "nonce length is %d", nonce_len);
                    219:        nonce = this->is_imc ? &this->responder_nonce : &this->initiator_nonce;
                    220:        chunk_free(nonce);
                    221:        if (!rng->allocate_bytes(rng, nonce_len, nonce))
                    222:        {
                    223:                DBG1(DBG_PTS, "failed to allocate nonce");
                    224:                rng->destroy(rng);
                    225:                return FALSE;
                    226:        }
                    227:        rng->destroy(rng);
                    228:        return TRUE;
                    229: }
                    230: 
                    231: METHOD(pts_t, get_my_public_value, bool,
                    232:        private_pts_t *this, chunk_t *value, chunk_t *nonce)
                    233: {
                    234:        if (!this->dh->get_my_public_value(this->dh, value))
                    235:        {
                    236:                return FALSE;
                    237:        }
                    238:        *nonce = this->is_imc ? this->responder_nonce : this->initiator_nonce;
                    239:        return TRUE;
                    240: }
                    241: 
                    242: METHOD(pts_t, set_peer_public_value, bool,
                    243:        private_pts_t *this, chunk_t value, chunk_t nonce)
                    244: {
                    245:        if (!this->dh->set_other_public_value(this->dh, value))
                    246:        {
                    247:                return FALSE;
                    248:        }
                    249: 
                    250:        nonce = chunk_clone(nonce);
                    251:        if (this->is_imc)
                    252:        {
                    253:                this->initiator_nonce = nonce;
                    254:        }
                    255:        else
                    256:        {
                    257:                this->responder_nonce = nonce;
                    258:        }
                    259:        return TRUE;
                    260: }
                    261: 
                    262: METHOD(pts_t, calculate_secret, bool,
                    263:        private_pts_t *this)
                    264: {
                    265:        hasher_t *hasher;
                    266:        hash_algorithm_t hash_alg;
                    267:        chunk_t shared_secret;
                    268: 
                    269:        /* Check presence of nonces */
                    270:        if (!this->initiator_nonce.len || !this->responder_nonce.len)
                    271:        {
                    272:                DBG1(DBG_PTS, "initiator and/or responder nonce is not available");
                    273:                return FALSE;
                    274:        }
                    275:        DBG3(DBG_PTS, "initiator nonce: %B", &this->initiator_nonce);
                    276:        DBG3(DBG_PTS, "responder nonce: %B", &this->responder_nonce);
                    277: 
                    278:        /* Calculate the DH secret */
                    279:        if (!this->dh->get_shared_secret(this->dh, &shared_secret))
                    280:        {
                    281:                DBG1(DBG_PTS, "shared DH secret computation failed");
                    282:                return FALSE;
                    283:        }
                    284:        DBG3(DBG_PTS, "shared DH secret: %B", &shared_secret);
                    285: 
                    286:        /* Calculate the secret assessment value */
                    287:        hash_alg = pts_meas_algo_to_hash(this->dh_hash_algorithm);
                    288:        hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
                    289: 
                    290:        if (!hasher ||
                    291:                !hasher->get_hash(hasher, chunk_from_chars('1'), NULL) ||
                    292:                !hasher->get_hash(hasher, this->initiator_nonce, NULL) ||
                    293:                !hasher->get_hash(hasher, this->responder_nonce, NULL) ||
                    294:                !hasher->allocate_hash(hasher, shared_secret, &this->secret))
                    295:        {
                    296:                DESTROY_IF(hasher);
                    297:                return FALSE;
                    298:        }
                    299:        hasher->destroy(hasher);
                    300:        chunk_clear(&shared_secret);
                    301: 
                    302:        DBG3(DBG_PTS, "secret assessment value: %B", &this->secret);
1.1.1.2 ! misho     303: 
1.1       misho     304:        return TRUE;
                    305: }
                    306: 
                    307: METHOD(pts_t, get_platform_id, int,
                    308:        private_pts_t *this)
                    309: {
                    310:        return this->platform_id;
                    311: }
                    312: 
                    313: METHOD(pts_t, set_platform_id, void,
                    314:        private_pts_t *this, int pid)
                    315: {
                    316:        this->platform_id = pid;
                    317: }
                    318: 
1.1.1.2 ! misho     319: METHOD(pts_t, extract_symlinks, pts_symlinks_t*,
        !           320:        private_pts_t *this, chunk_t pathname)
        !           321: {
        !           322: #ifndef WIN32
        !           323:        char path[BUF_LEN], real_path[BUF_LEN];
        !           324:        size_t path_len, real_path_len;
        !           325:        struct dirent *entry;
        !           326:        struct stat st;
        !           327:        DIR *dir;
        !           328: 
        !           329:        /* open directory and prepare pathnames */
        !           330:        snprintf(path, BUF_LEN-1, "%.*s", (int)pathname.len, pathname.ptr);
        !           331:        dir = opendir(path);
        !           332:        if (!dir)
        !           333:        {
        !           334:                DBG1(DBG_PTS, "opening directory '%s' failed: %s", path,
        !           335:                                           strerror(errno));
        !           336:                return NULL;
        !           337:        }
        !           338:        if (pathname.len == 1 && path[0] == '/')
        !           339:        {
        !           340:                path_len = 1;
        !           341:        }
        !           342:        else
        !           343:        {
        !           344:                path[pathname.len] = '/';
        !           345:                path_len = pathname.len + 1;
        !           346:        }
        !           347:        real_path[0] = '/';
        !           348: 
        !           349:        /* symlinks object is owned by pts object */
        !           350:        DESTROY_IF(this->symlinks);
        !           351:        this->symlinks = pts_symlinks_create();
        !           352: 
        !           353:        while (TRUE)
        !           354:        {
        !           355: 
        !           356:                entry = readdir(dir);
        !           357:                if (!entry)
        !           358:                {
        !           359:                        /* no more entries -> exit */
        !           360:                        break;
        !           361:                }
        !           362:                if (streq(entry->d_name, ".") || streq(entry->d_name, ".."))
        !           363:                {
        !           364:                        continue;
        !           365:                }
        !           366: 
        !           367:                /* assemble absolute path */
        !           368:                snprintf(path + path_len, BUF_LEN - path_len, "%s", entry->d_name);
        !           369: 
        !           370:                /* only evaluate symlinks pointing to directories */
        !           371:                if (lstat(path, &st) == -1 || !S_ISLNK(st.st_mode) ||
        !           372:                         stat(path, &st) == -1 || !S_ISDIR(st.st_mode))
        !           373:                {
        !           374:                        continue;
        !           375:                }
        !           376: 
        !           377:                real_path_len = readlink(path, real_path + 1, BUF_LEN - 1);
        !           378:                if (real_path_len <= 0)
        !           379:                {
        !           380:                        continue;
        !           381:                }
        !           382:                this->symlinks->add(this->symlinks, chunk_from_str(path),
        !           383:                                                        chunk_create(real_path, 1 + real_path_len));
        !           384:        }
        !           385:        closedir(dir);
        !           386: #endif
        !           387: 
        !           388:        return this->symlinks;
        !           389: }
        !           390: 
        !           391: 
        !           392: METHOD(pts_t, get_symlinks, pts_symlinks_t*,
        !           393:        private_pts_t *this)
        !           394: {
        !           395:        return this->symlinks;
        !           396: }
        !           397: 
        !           398: METHOD(pts_t, set_symlinks, void,
        !           399:        private_pts_t *this, pts_symlinks_t *symlinks)
        !           400: {
        !           401:        enumerator_t *enumerator;
        !           402:        chunk_t symlink, dir;
        !           403: 
        !           404:        DESTROY_IF(this->symlinks);
        !           405:        this->symlinks = symlinks->get_ref(symlinks);
        !           406: 
        !           407:        DBG2(DBG_PTS, "adding directory symlinks:");
        !           408:        enumerator = symlinks->create_enumerator(symlinks);
        !           409:        while (enumerator->enumerate(enumerator, &symlink, &dir))
        !           410:        {
        !           411:                DBG2(DBG_PTS, "  %.*s -> %.*s", (int)symlink.len, symlink.ptr,
        !           412:                                                                                (int)dir.len, dir.ptr);
        !           413:        }
        !           414:        enumerator->destroy(enumerator);
        !           415: }
        !           416: 
        !           417: METHOD(pts_t, get_tpm, tpm_tss_t*,
        !           418:        private_pts_t *this)
        !           419: {
        !           420:        return this->tpm;
        !           421: }
        !           422: 
1.1       misho     423: METHOD(pts_t, get_tpm_version_info, bool,
                    424:        private_pts_t *this, chunk_t *info)
                    425: {
1.1.1.2 ! misho     426:        *info = this->tpm_version_info;
        !           427: 
1.1       misho     428:        return info->len > 0;
                    429: }
                    430: 
1.1.1.2 ! misho     431: #define TPM_VERSION_INFO_TAG_1_2       0x0030
        !           432: #define TPM_VERSION_INFO_TAG_2_0       0x0200
        !           433: #define TPM_VERSION_INFO_LABEL         "Version Information: TPM"
        !           434: 
1.1       misho     435: METHOD(pts_t, set_tpm_version_info, void,
                    436:        private_pts_t *this, chunk_t info)
                    437: {
1.1.1.2 ! misho     438:        bio_reader_t *reader;
        !           439:        uint16_t tpm_version_info_tag;
        !           440:        chunk_t vendor;
        !           441: 
        !           442:        reader = bio_reader_create(info);
        !           443:        reader->read_uint16(reader, &tpm_version_info_tag);
        !           444: 
        !           445:        if (tpm_version_info_tag == TPM_VERSION_INFO_TAG_1_2)
        !           446:        {
        !           447:                uint8_t major, minor, rev_major, rev_minor, errata_rev;
        !           448:                uint16_t spec_level;
        !           449: 
        !           450:                this->tpm_version = TPM_VERSION_1_2;
        !           451: 
        !           452:                if (reader->read_uint8 (reader, &major)      &&
        !           453:                        reader->read_uint8 (reader, &minor)      &&
        !           454:                        reader->read_uint8 (reader, &rev_major)  &&
        !           455:                        reader->read_uint8 (reader, &rev_minor)  &&
        !           456:                        reader->read_uint16(reader, &spec_level) &&
        !           457:                        reader->read_uint8 (reader, &errata_rev) &&
        !           458:                        reader->read_data  (reader, 4, &vendor))
        !           459:                {
        !           460:                        DBG2(DBG_PTS, "%s 1.2 rev. %u.%u.%u.%u %.*s", TPM_VERSION_INFO_LABEL,
        !           461:                                (uint32_t)major, (uint32_t)minor, (uint32_t)rev_major,
        !           462:                                (uint32_t)rev_minor, (int)vendor.len, vendor.ptr);
        !           463:                }
        !           464:                else
        !           465:                {
        !           466:                        DBG2(DBG_PTS, "%s 1.2", TPM_VERSION_INFO_LABEL);
        !           467:                }
        !           468: 
        !           469:        }
        !           470:        else if (tpm_version_info_tag == TPM_VERSION_INFO_TAG_2_0)
        !           471:        {
        !           472:                uint32_t revision, year;
        !           473:                uint8_t reserved, locality;
        !           474: 
        !           475:                this->tpm_version = TPM_VERSION_2_0;
        !           476: 
        !           477:                if (reader->read_uint8 (reader, &reserved)  &&
        !           478:                        reader->read_uint8 (reader, &locality)  &&
        !           479:                        reader->read_uint32(reader, &revision)  &&
        !           480:                        reader->read_uint32(reader, &year)      &&
        !           481:                        reader->read_data  (reader, 4, &vendor))
        !           482:                {
        !           483:                        DBG2(DBG_PTS, "%s 2.0 rev. %4.2f %u %.*s - startup locality: %u",
        !           484:                                 TPM_VERSION_INFO_LABEL, revision/100.0, year,
        !           485:                                 (int)vendor.len, vendor.ptr, (uint32_t)locality);
        !           486:                }
        !           487:                else
        !           488:                {
        !           489:                        DBG2(DBG_PTS, "%s 2.0", TPM_VERSION_INFO_LABEL);
        !           490:                }
        !           491:        }
        !           492:        reader->destroy(reader);
        !           493: 
1.1       misho     494:        this->tpm_version_info = chunk_clone(info);
                    495: }
                    496: 
                    497: /**
                    498:  * Load an AIK handle and an optional AIK certificate and
                    499:  * in the case of a TPM 1.2 an AIK private key blob plus matching public key,
                    500:  * the certificate having precedence over the public key if both are present
                    501:  */
                    502: static void load_aik(private_pts_t *this)
                    503: {
                    504:        char *handle_str, *cert_path, *key_path, *blob_path;
                    505:        chunk_t aik_pubkey = chunk_empty;
                    506: 
                    507:        handle_str = lib->settings->get_str(lib->settings,
                    508:                                                "%s.plugins.imc-attestation.aik_handle", NULL, lib->ns);
                    509:        cert_path = lib->settings->get_str(lib->settings,
                    510:                                                "%s.plugins.imc-attestation.aik_cert", NULL, lib->ns);
                    511:        key_path = lib->settings->get_str(lib->settings,
                    512:                                                "%s.plugins.imc-attestation.aik_pubkey", NULL, lib->ns);
                    513:        blob_path = lib->settings->get_str(lib->settings,
                    514:                                                "%s.plugins.imc-attestation.aik_blob", NULL, lib->ns);
                    515: 
                    516:        if (handle_str)
                    517:        {
                    518:                this->aik_handle = strtoll(handle_str, NULL, 16);
                    519:        }
                    520:        if (cert_path)
                    521:        {
                    522:                this->aik_cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
                    523:                                                                           CERT_X509, BUILD_FROM_FILE,
                    524:                                                                           cert_path, BUILD_END);
                    525:                if (this->aik_cert)
                    526:                {
                    527:                        DBG2(DBG_PTS, "loaded AIK certificate from '%s'", cert_path);
                    528:                }
                    529:        }
                    530: 
                    531:        if (this->tpm->get_version(this->tpm) == TPM_VERSION_1_2)
                    532:        {
                    533:                tpm_tss_trousers_t *tpm_12;
                    534:                chunk_t aik_blob = chunk_empty;
                    535:                chunk_t *map;
                    536: 
                    537:                /* get AIK private key blob */
                    538:                if (blob_path)
                    539:                {
                    540:                        map = chunk_map(blob_path, FALSE);
                    541:                        if (map)
                    542:                        {
                    543:                                DBG2(DBG_PTS, "loaded AIK Blob from '%s'", blob_path);
                    544:                                DBG3(DBG_PTS, "AIK Blob: %B", map);
                    545:                                aik_blob = chunk_clone(*map);
                    546:                                chunk_unmap(map);
                    547:                        }
                    548:                        else
                    549:                        {
                    550:                                DBG1(DBG_PTS, "unable to map AIK Blob file '%s': %s",
                    551:                                                           blob_path, strerror(errno));
                    552:                        }
                    553:                }
                    554:                else
                    555:                {
                    556:                        DBG1(DBG_PTS, "AIK Blob is not available");
                    557:                }
                    558: 
                    559:                /* get AIK public key if no AIK certificate is available */
                    560:                if (!this->aik_cert)
                    561:                {
                    562:                        if (key_path)
                    563:                        {
                    564:                                map = chunk_map(key_path, FALSE);
                    565:                                if (map)
                    566:                                {
                    567:                                        DBG2(DBG_PTS, "loaded AIK public key from '%s'", key_path);
                    568:                                        aik_pubkey = chunk_clone(*map);
                    569:                                        chunk_unmap(map);
                    570:                                }
                    571:                                else
                    572:                                {
                    573:                                        DBG1(DBG_PTS, "unable to map AIK public key file '%s': %s",
                    574:                                                                   key_path, strerror(errno));
                    575:                                }
                    576:                        }
                    577:                        else
                    578:                        {
                    579:                                DBG1(DBG_PTS, "AIK public key is not available");
                    580:                        }
                    581:                }
                    582: 
                    583:                /* Load AIK item into TPM 1.2 object */
                    584:                tpm_12 = (tpm_tss_trousers_t *)this->tpm;
                    585:                tpm_12->load_aik(tpm_12, aik_blob, aik_pubkey, this->aik_handle);
                    586:        }
                    587: 
                    588:        /* if no signed X.509 AIK certificate is available use public key instead */
                    589:        if (!this->aik_cert)
                    590:        {
                    591:                aik_pubkey = this->tpm->get_public(this->tpm, this->aik_handle);
                    592:                if (aik_pubkey.len > 0)
                    593:                {
                    594:                        this->aik_cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
                    595:                                                                           CERT_TRUSTED_PUBKEY, BUILD_BLOB,
                    596:                                                                           aik_pubkey, BUILD_END);
                    597:                        chunk_free(&aik_pubkey);
                    598:                }
                    599:                else
                    600:                {
                    601:                        DBG1(DBG_PTS, "neither AIK certificate nor public key is available");
                    602:                }
                    603:        }
                    604: }
                    605: 
                    606: METHOD(pts_t, get_aik, certificate_t*,
                    607:        private_pts_t *this)
                    608: {
                    609:        return this->aik_cert;
                    610: }
                    611: 
                    612: METHOD(pts_t, set_aik, void,
                    613:        private_pts_t *this, certificate_t *aik, int aik_id)
                    614: {
                    615:        DESTROY_IF(this->aik_cert);
                    616:        this->aik_cert = aik->get_ref(aik);
                    617:        this->aik_id = aik_id;
                    618: }
                    619: 
                    620: METHOD(pts_t, get_aik_id, int,
                    621:        private_pts_t *this)
                    622: {
                    623:        return this->aik_id;
                    624: }
                    625: 
                    626: METHOD(pts_t, is_path_valid, bool,
                    627:        private_pts_t *this, char *path, pts_error_code_t *error_code)
                    628: {
                    629:        struct stat st;
                    630: 
                    631:        *error_code = 0;
                    632: 
                    633:        if (!stat(path, &st))
                    634:        {
                    635:                return TRUE;
                    636:        }
                    637:        else if (errno == ENOENT || errno == ENOTDIR)
                    638:        {
                    639:                DBG1(DBG_PTS, "file/directory does not exist %s", path);
                    640:                *error_code = TCG_PTS_FILE_NOT_FOUND;
                    641:        }
                    642:        else if (errno == EFAULT)
                    643:        {
                    644:                DBG1(DBG_PTS, "bad address %s", path);
                    645:                *error_code = TCG_PTS_INVALID_PATH;
                    646:        }
                    647:        else
                    648:        {
                    649:                DBG1(DBG_PTS, "error: %s occurred while validating path: %s",
                    650:                                           strerror(errno), path);
                    651:                return FALSE;
                    652:        }
                    653: 
                    654:        return TRUE;
                    655: }
                    656: 
                    657: /**
                    658:  * Obtain statistical information describing a file
                    659:  */
                    660: static bool file_metadata(char *pathname, pts_file_metadata_t **entry)
                    661: {
                    662:        struct stat st;
                    663:        pts_file_metadata_t *this;
                    664: 
                    665:        this = malloc_thing(pts_file_metadata_t);
                    666: 
                    667:        if (stat(pathname, &st))
                    668:        {
                    669:                DBG1(DBG_PTS, "unable to obtain statistics about '%s'", pathname);
                    670:                free(this);
                    671:                return FALSE;
                    672:        }
                    673: 
                    674:        if (S_ISREG(st.st_mode))
                    675:        {
                    676:                this->type = PTS_FILE_REGULAR;
                    677:        }
                    678:        else if (S_ISDIR(st.st_mode))
                    679:        {
                    680:                this->type = PTS_FILE_DIRECTORY;
                    681:        }
                    682:        else if (S_ISCHR(st.st_mode))
                    683:        {
                    684:                this->type = PTS_FILE_CHAR_SPEC;
                    685:        }
                    686:        else if (S_ISBLK(st.st_mode))
                    687:        {
                    688:                this->type = PTS_FILE_BLOCK_SPEC;
                    689:        }
                    690:        else if (S_ISFIFO(st.st_mode))
                    691:        {
                    692:                this->type = PTS_FILE_FIFO;
                    693:        }
                    694: #ifndef WIN32
                    695:        else if (S_ISLNK(st.st_mode))
                    696:        {
                    697:                this->type = PTS_FILE_SYM_LINK;
                    698:        }
                    699:        else if (S_ISSOCK(st.st_mode))
                    700:        {
                    701:                this->type = PTS_FILE_SOCKET;
                    702:        }
                    703: #endif /* WIN32 */
                    704:        else
                    705:        {
                    706:                this->type = PTS_FILE_OTHER;
                    707:        }
                    708: 
                    709:        this->filesize = st.st_size;
                    710:        this->created =  st.st_ctime;
                    711:        this->modified = st.st_mtime;
                    712:        this->accessed = st.st_atime;
                    713:        this->owner =    st.st_uid;
                    714:        this->group =    st.st_gid;
                    715: 
                    716:        *entry = this;
                    717:        return TRUE;
                    718: }
                    719: 
                    720: METHOD(pts_t, get_metadata, pts_file_meta_t*,
                    721:        private_pts_t *this, char *pathname, bool is_directory)
                    722: {
                    723:        pts_file_meta_t *metadata;
                    724:        pts_file_metadata_t *entry;
                    725: 
                    726:        /* Create a metadata object */
                    727:        metadata = pts_file_meta_create();
                    728: 
                    729:        if (is_directory)
                    730:        {
                    731:                enumerator_t *enumerator;
                    732:                char *rel_name, *abs_name;
                    733:                struct stat st;
                    734: 
                    735:                enumerator = enumerator_create_directory(pathname);
                    736:                if (!enumerator)
                    737:                {
                    738:                        DBG1(DBG_PTS,"  directory '%s' can not be opened, %s", pathname,
                    739:                                 strerror(errno));
                    740:                        metadata->destroy(metadata);
                    741:                        return NULL;
                    742:                }
                    743:                while (enumerator->enumerate(enumerator, &rel_name, &abs_name, &st))
                    744:                {
                    745:                        /* measure regular files only */
                    746:                        if (S_ISREG(st.st_mode) && *rel_name != '.')
                    747:                        {
                    748:                                if (!file_metadata(abs_name, &entry))
                    749:                                {
                    750:                                        enumerator->destroy(enumerator);
                    751:                                        metadata->destroy(metadata);
                    752:                                        return NULL;
                    753:                                }
                    754:                                entry->filename = strdup(rel_name);
                    755:                                metadata->add(metadata, entry);
                    756:                        }
                    757:                }
                    758:                enumerator->destroy(enumerator);
                    759:        }
                    760:        else
                    761:        {
                    762:                if (!file_metadata(pathname, &entry))
                    763:                {
                    764:                        metadata->destroy(metadata);
                    765:                        return NULL;
                    766:                }
                    767:                entry->filename = path_basename(pathname);
                    768:                metadata->add(metadata, entry);
                    769:        }
                    770: 
                    771:        return metadata;
                    772: }
                    773: 
                    774: METHOD(pts_t, read_pcr, bool,
                    775:        private_pts_t *this, uint32_t pcr_num, chunk_t *pcr_value,
                    776:        hash_algorithm_t alg)
                    777: {
                    778:        return this->tpm ? this->tpm->read_pcr(this->tpm, pcr_num, pcr_value, alg)
                    779:                                     : FALSE;
                    780: }
                    781: 
                    782: METHOD(pts_t, extend_pcr, bool,
                    783:        private_pts_t *this, uint32_t pcr_num, chunk_t *pcr_value, chunk_t data,
                    784:        hash_algorithm_t alg)
                    785: {
                    786:        if (!this->tpm->extend_pcr(this->tpm, pcr_num, pcr_value, data, alg))
                    787:        {
                    788:                return FALSE;
                    789:        }
                    790:        DBG3(DBG_PTS, "PCR %d extended with:   %#B", pcr_num, &data);
                    791:        DBG3(DBG_PTS, "PCR %d after extension: %#B", pcr_num, pcr_value);
                    792: 
                    793:        return TRUE;
                    794: }
                    795: 
                    796: METHOD(pts_t, quote, bool,
                    797:        private_pts_t *this, tpm_quote_mode_t *quote_mode,
                    798:        tpm_tss_quote_info_t **quote_info, chunk_t *quote_sig)
                    799: {
                    800:        chunk_t pcr_value, pcr_computed;
1.1.1.2 ! misho     801:        hash_algorithm_t hash_alg;
1.1       misho     802:        uint32_t pcr, pcr_sel = 0;
                    803:        enumerator_t *enumerator;
                    804: 
1.1.1.2 ! misho     805:        hash_alg = pts_meas_algo_to_hash(this->pcrs->get_pcr_algo(this->pcrs));
        !           806: 
1.1       misho     807:        /* select PCRs */
                    808:        DBG2(DBG_PTS, "PCR values hashed into PCR Composite:");
                    809:        enumerator = this->pcrs->create_enumerator(this->pcrs);
                    810:        while (enumerator->enumerate(enumerator, &pcr))
                    811:        {
1.1.1.2 ! misho     812:                if (this->tpm->read_pcr(this->tpm, pcr, &pcr_value, hash_alg))
1.1       misho     813:                {
                    814:                        pcr_computed = this->pcrs->get(this->pcrs, pcr);
                    815:                        DBG2(DBG_PTS, "PCR %2d %#B  %s", pcr, &pcr_value,
                    816:                                 chunk_equals(pcr_value, pcr_computed) ? "ok" : "differs");
                    817:                        chunk_free(&pcr_value);
                    818:                };
                    819: 
                    820:                /* add PCR to selection list */
                    821:                pcr_sel |= (1 << pcr);
                    822:        }
                    823:        enumerator->destroy(enumerator);
                    824: 
                    825:        /* TPM Quote */
1.1.1.2 ! misho     826:        return this->tpm->quote(this->tpm, this->aik_handle, pcr_sel, hash_alg,
1.1       misho     827:                                                        this->secret, quote_mode, quote_info, quote_sig);
                    828: }
                    829: 
                    830: METHOD(pts_t, get_quote, bool,
                    831:        private_pts_t *this, tpm_tss_quote_info_t *quote_info, chunk_t *quoted)
                    832: {
                    833:        tpm_tss_pcr_composite_t *pcr_composite;
                    834:        bool success;
                    835: 
                    836:        if (!this->pcrs->get_count(this->pcrs))
                    837:        {
                    838:                DBG1(DBG_PTS, "No extended PCR entries available, "
                    839:                                          "unable to construct TPM Quote Info");
                    840:                return FALSE;
                    841:        }
                    842:        if (!this->secret.ptr)
                    843:        {
                    844:                DBG1(DBG_PTS, "Secret assessment value unavailable, ",
                    845:                                          "unable to construct TPM Quote Info");
                    846:                return FALSE;
                    847:        }
                    848:        if (quote_info->get_quote_mode(quote_info) == TPM_QUOTE2_VERSION_INFO)
                    849:        {
                    850:                if (!this->tpm_version_info.ptr)
                    851:                {
                    852:                        DBG1(DBG_PTS, "TPM Version Information unavailable, ",
                    853:                                                  "unable to construct TPM Quote Info2");
                    854:                        return FALSE;
                    855:                }
                    856:                quote_info->set_version_info(quote_info, this->tpm_version_info);
                    857:        }
                    858:        pcr_composite = this->pcrs->get_composite(this->pcrs);
                    859: 
                    860:        success = quote_info->get_quote(quote_info, this->secret,
                    861:                                                                        pcr_composite, quoted);
                    862:        chunk_free(&pcr_composite->pcr_select);
                    863:        chunk_free(&pcr_composite->pcr_composite);
                    864:        free(pcr_composite);
                    865: 
                    866:        return success;
                    867: }
                    868: 
                    869: METHOD(pts_t, verify_quote_signature, bool,
                    870:        private_pts_t *this, hash_algorithm_t digest_alg, chunk_t digest,
                    871:        chunk_t signature)
                    872: {
                    873:        public_key_t *aik_pubkey;
                    874:        signature_scheme_t scheme;
                    875: 
                    876:        aik_pubkey = this->aik_cert->get_public_key(this->aik_cert);
                    877:        if (!aik_pubkey)
                    878:        {
                    879:                DBG1(DBG_PTS, "failed to get public key from AIK certificate");
                    880:                return FALSE;
                    881:        }
                    882: 
                    883:        /* Determine signing scheme */
                    884:        switch (aik_pubkey->get_type(aik_pubkey))
                    885:        {
                    886:                case KEY_RSA:
                    887:                        switch (digest_alg)
                    888:                        {
                    889:                                case HASH_SHA1:
                    890:                                        scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
                    891:                                        break;
                    892:                                case HASH_SHA256:
                    893:                                        scheme = SIGN_RSA_EMSA_PKCS1_SHA2_256;
                    894:                                        break;
                    895:                                case HASH_SHA384:
                    896:                                        scheme = SIGN_RSA_EMSA_PKCS1_SHA2_384;
                    897:                                        break;
                    898:                                case HASH_SHA512:
                    899:                                        scheme = SIGN_RSA_EMSA_PKCS1_SHA2_512;
                    900:                                        break;
                    901:                                case HASH_SHA3_256:
                    902:                                        scheme = SIGN_RSA_EMSA_PKCS1_SHA3_256;
                    903:                                        break;
                    904:                                case HASH_SHA3_384:
                    905:                                        scheme = SIGN_RSA_EMSA_PKCS1_SHA3_384;
                    906:                                        break;
                    907:                                case HASH_SHA3_512:
                    908:                                        scheme = SIGN_RSA_EMSA_PKCS1_SHA3_512;
                    909:                                        break;
                    910:                                default:
                    911:                                        scheme = SIGN_UNKNOWN;
                    912:                        }
                    913:                        break;
                    914:                case KEY_ECDSA:
                    915:                        switch (digest_alg)
                    916:                        {
                    917:                                case HASH_SHA256:
                    918:                                        scheme = SIGN_ECDSA_256;
                    919:                                        break;
                    920:                                case HASH_SHA384:
                    921:                                        scheme = SIGN_ECDSA_384;
                    922:                                        break;
                    923:                                case HASH_SHA512:
                    924:                                        scheme = SIGN_ECDSA_521;
                    925:                                        break;
                    926:                                default:
                    927:                                        scheme = SIGN_UNKNOWN;
                    928:                        }
                    929:                        break;
                    930:                default:
                    931:                        DBG1(DBG_PTS, "%N AIK key type not supported", key_type_names,
                    932:                                                   aik_pubkey->get_type(aik_pubkey));
                    933:                        return FALSE;
                    934:        }
                    935: 
                    936:        if (!aik_pubkey->verify(aik_pubkey, scheme, NULL, digest, signature))
                    937:        {
                    938:                DBG1(DBG_PTS, "signature verification failed for TPM Quote Info");
                    939:                DESTROY_IF(aik_pubkey);
                    940:                return FALSE;
                    941:        }
                    942: 
                    943:        aik_pubkey->destroy(aik_pubkey);
                    944:        return TRUE;
                    945: }
                    946: 
1.1.1.2 ! misho     947: /**
        !           948:  * Extracts the locality from a TPM 2.0 Version Info struct
        !           949:  */
        !           950: static uint8_t get_tpm_locality(chunk_t tpm_version_info)
        !           951: {
        !           952:        if (tpm_version_info.len < 4 ||
        !           953:            tpm_version_info.ptr[0] != 0x02 || tpm_version_info.ptr[1] != 0x00)
        !           954:        {
        !           955:                return 0;
        !           956:        }
        !           957:        else
        !           958:        {
        !           959:                return tpm_version_info.ptr[3];
        !           960:        }
        !           961: }
        !           962: 
1.1       misho     963: METHOD(pts_t, get_pcrs, pts_pcr_t*,
                    964:        private_pts_t *this)
                    965: {
1.1.1.2 ! misho     966:        if (!this->pcrs)
        !           967:        {
        !           968:                this->pcrs = pts_pcr_create(this->tpm_version, this->algorithm,
        !           969:                                                        get_tpm_locality(this->tpm_version_info));
        !           970:        }
1.1       misho     971:        return this->pcrs;
                    972: }
                    973: 
                    974: METHOD(pts_t, destroy, void,
                    975:        private_pts_t *this)
                    976: {
                    977:        DESTROY_IF(this->tpm);
                    978:        DESTROY_IF(this->pcrs);
                    979:        DESTROY_IF(this->aik_cert);
                    980:        DESTROY_IF(this->dh);
1.1.1.2 ! misho     981:        DESTROY_IF(this->symlinks);
1.1       misho     982:        free(this->initiator_nonce.ptr);
                    983:        free(this->responder_nonce.ptr);
                    984:        free(this->secret.ptr);
                    985:        free(this->tpm_version_info.ptr);
                    986:        free(this);
                    987: }
                    988: 
                    989: /**
                    990:  * See header
                    991:  */
                    992: pts_t *pts_create(bool is_imc)
                    993: {
                    994:        private_pts_t *this;
                    995: 
                    996:        INIT(this,
                    997:                .public = {
                    998:                        .get_proto_caps = _get_proto_caps,
                    999:                        .set_proto_caps = _set_proto_caps,
                   1000:                        .get_meas_algorithm = _get_meas_algorithm,
                   1001:                        .set_meas_algorithm = _set_meas_algorithm,
                   1002:                        .get_dh_hash_algorithm = _get_dh_hash_algorithm,
                   1003:                        .set_dh_hash_algorithm = _set_dh_hash_algorithm,
                   1004:                        .create_dh_nonce = _create_dh_nonce,
                   1005:                        .get_my_public_value = _get_my_public_value,
                   1006:                        .set_peer_public_value = _set_peer_public_value,
                   1007:                        .calculate_secret = _calculate_secret,
                   1008:                        .get_platform_id = _get_platform_id,
                   1009:                        .set_platform_id = _set_platform_id,
1.1.1.2 ! misho    1010:                        .extract_symlinks = _extract_symlinks,
        !          1011:                        .get_symlinks = _get_symlinks,
        !          1012:                        .set_symlinks = _set_symlinks,
        !          1013:                        .get_tpm = _get_tpm,
1.1       misho    1014:                        .get_tpm_version_info = _get_tpm_version_info,
                   1015:                        .set_tpm_version_info = _set_tpm_version_info,
                   1016:                        .get_aik = _get_aik,
                   1017:                        .set_aik = _set_aik,
                   1018:                        .get_aik_id = _get_aik_id,
                   1019:                        .is_path_valid = _is_path_valid,
                   1020:                        .get_metadata = _get_metadata,
                   1021:                        .read_pcr = _read_pcr,
                   1022:                        .extend_pcr = _extend_pcr,
                   1023:                        .quote = _quote,
                   1024:                        .get_pcrs = _get_pcrs,
                   1025:                        .get_quote = _get_quote,
                   1026:                        .verify_quote_signature  = _verify_quote_signature,
                   1027:                        .destroy = _destroy,
                   1028:                },
                   1029:                .is_imc = is_imc,
                   1030:                .proto_caps = PTS_PROTO_CAPS_V,
1.1.1.2 ! misho    1031:                .algorithm = PTS_MEAS_ALGO_SHA384,
        !          1032:                .dh_hash_algorithm = PTS_MEAS_ALGO_SHA384,
1.1       misho    1033:        );
                   1034: 
                   1035:        if (is_imc)
                   1036:        {
                   1037:                this->tpm = tpm_tss_probe(TPM_VERSION_ANY);
                   1038:                if (this->tpm)
                   1039:                {
                   1040:                        this->proto_caps |= PTS_PROTO_CAPS_T | PTS_PROTO_CAPS_D;
1.1.1.2 ! misho    1041:                        this->tpm_version = this->tpm->get_version(this->tpm);
        !          1042:                        this->tpm_version_info = chunk_clone(
        !          1043:                                                                                this->tpm->get_version_info(this->tpm));
1.1       misho    1044:                        load_aik(this);
                   1045:                }
                   1046:        }
                   1047:        else
                   1048:        {
                   1049:                this->proto_caps |= PTS_PROTO_CAPS_T | PTS_PROTO_CAPS_D;
1.1.1.2 ! misho    1050:                this->tpm_version = TPM_VERSION_2_0;
1.1       misho    1051:        }
                   1052: 
                   1053:        return &this->public;
                   1054: }

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