Annotation of embedaddon/strongswan/src/libimcv/pts/pts_ima_event_list.c, revision 1.1.1.2

1.1       misho       1: /*
                      2:  * Copyright (C) 2011-2014 Andreas Steffen
                      3:  * HSR Hochschule fuer Technik Rapperswil
                      4:  *
                      5:  * This program is free software; you can redistribute it and/or modify it
                      6:  * under the terms of the GNU General Public License as published by the
                      7:  * Free Software Foundation; either version 2 of the License, or (at your
                      8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                      9:  *
                     10:  * This program is distributed in the hope that it will be useful, but
                     11:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     12:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     13:  * for more details.
                     14:  */
                     15: 
                     16: #include "pts_ima_event_list.h"
                     17: 
                     18: #include <utils/debug.h>
                     19: #include <crypto/hashers/hasher.h>
                     20: 
                     21: #include <sys/types.h>
                     22: #include <sys/stat.h>
                     23: #include <unistd.h>
                     24: #include <fcntl.h>
                     25: #include <errno.h>
                     26: 
                     27: typedef struct private_pts_ima_event_list_t private_pts_ima_event_list_t;
                     28: typedef struct event_entry_t event_entry_t;
                     29: 
                     30: #define IMA_TYPE_LEN                           3
                     31: #define IMA_NG_TYPE_LEN                                6
                     32: #define IMA_TYPE_LEN_MAX                       10
                     33: #define IMA_ALGO_DIGEST_LEN_MAX                IMA_ALGO_LEN_MAX + HASH_SIZE_SHA512
1.1.1.2 ! misho      34: #define IMA_FILENAME_LEN_MAX           255
        !            35: 
        !            36: 
1.1       misho      37: 
                     38: /**
                     39:  * Private data of a pts_ima_event_list_t object.
                     40:  *
                     41:  */
                     42: struct private_pts_ima_event_list_t {
                     43: 
                     44:        /**
                     45:         * Public pts_ima_event_list_t interface.
                     46:         */
                     47:        pts_ima_event_list_t public;
                     48: 
                     49:        /**
                     50:         * List of BIOS measurement entries
                     51:         */
                     52:        linked_list_t *list;
                     53: 
                     54:        /**
                     55:         * Time when IMA runtime file measurements were taken
                     56:         */
                     57:        time_t creation_time;
                     58: 
                     59: };
                     60: 
                     61: /**
                     62:  * Linux IMA runtime file measurement entry
                     63:  */
                     64: struct event_entry_t {
                     65: 
                     66:        /**
1.1.1.2 ! misho      67:         * Special IMA measurement hash
1.1       misho      68:         */
                     69:        chunk_t measurement;
                     70: 
                     71:        /**
                     72:         * IMA-NG hash algorithm name or NULL
                     73:         */
                     74:        char *algo;
                     75: 
                     76:        /**
                     77:         * IMA-NG eventname or IMA filename
                     78:         */
                     79:        char *name;
                     80: };
                     81: 
                     82: /**
                     83:  * Free an ima_event_t object
                     84:  */
                     85: static void free_event_entry(event_entry_t *this)
                     86: {
                     87:        free(this->measurement.ptr);
                     88:        free(this->algo);
                     89:        free(this->name);
                     90:        free(this);
                     91: }
                     92: 
                     93: METHOD(pts_ima_event_list_t, get_time, time_t,
                     94:        private_pts_ima_event_list_t *this)
                     95: {
                     96:        return this->creation_time;
                     97: }
                     98: 
                     99: METHOD(pts_ima_event_list_t, get_count, int,
                    100:        private_pts_ima_event_list_t *this)
                    101: {
                    102:        return this->list->get_count(this->list);
                    103: }
                    104: 
                    105: METHOD(pts_ima_event_list_t, get_next, status_t,
                    106:        private_pts_ima_event_list_t *this, chunk_t *measurement, char **algo,
                    107:        char **name)
                    108: {
                    109:        event_entry_t *entry;
                    110:        status_t status;
                    111: 
                    112:        status = this->list->remove_first(this->list, (void**)&entry);
                    113:        *measurement = entry->measurement;
                    114:        *algo = entry->algo;
                    115:        *name = entry->name;
                    116:        free(entry);
                    117: 
                    118:        return status;
                    119: }
                    120: 
                    121: METHOD(pts_ima_event_list_t, destroy, void,
                    122:        private_pts_ima_event_list_t *this)
                    123: {
                    124:        this->list->destroy_function(this->list, (void *)free_event_entry);
                    125:        free(this);
                    126: }
                    127: 
                    128: /**
                    129:  * See header
                    130:  */
1.1.1.2 ! misho     131: pts_ima_event_list_t* pts_ima_event_list_create(char *file,
        !           132:                                                        pts_meas_algorithms_t pcr_algo, bool pcr_padding)
1.1       misho     133: {
                    134:        private_pts_ima_event_list_t *this;
                    135:        event_entry_t *entry;
1.1.1.2 ! misho     136:        chunk_t digest;
1.1       misho     137:        uint32_t pcr, type_len, name_len, eventdata_len, algo_digest_len, algo_len;
1.1.1.2 ! misho     138:        size_t hash_size;
1.1       misho     139:        char type[IMA_TYPE_LEN_MAX];
                    140:        char algo_digest[IMA_ALGO_DIGEST_LEN_MAX];
                    141:        char *pos, *error = "";
                    142:        struct stat st;
                    143:        ssize_t res;
                    144:        bool ima_ng;
                    145:        int fd;
                    146: 
                    147:        fd = open(file, O_RDONLY);
                    148:        if (fd == -1)
                    149:        {
                    150:                DBG1(DBG_PTS, "opening '%s' failed: %s", file, strerror(errno));
                    151:                return NULL;
                    152:        }
                    153: 
                    154:        if (fstat(fd, &st) == -1)
                    155:        {
                    156:                DBG1(DBG_PTS, "getting statistics of '%s' failed: %s", file,
                    157:                         strerror(errno));
                    158:                close(fd);
                    159:                return NULL;
                    160:        }
                    161: 
                    162:        INIT(this,
                    163:                .public = {
                    164:                        .get_time = _get_time,
                    165:                        .get_count = _get_count,
                    166:                        .get_next = _get_next,
                    167:                        .destroy = _destroy,
                    168:                },
                    169:                .creation_time = st.st_ctime,
                    170:                .list = linked_list_create(),
                    171:        );
                    172: 
1.1.1.2 ! misho     173:        hash_size = pts_meas_algo_hash_size(pcr_algo);
        !           174: 
1.1       misho     175:        while (TRUE)
                    176:        {
                    177:                /* read 32 bit PCR number in host order */
                    178:                res = read(fd, &pcr, 4);
                    179: 
                    180:                /* exit if no more measurement data is available */
                    181:                if (res == 0)
                    182:                {
                    183:                        DBG2(DBG_PTS, "loaded ima measurements '%s' (%d entries)",
                    184:                                 file, this->list->get_count(this->list));
                    185:                        close(fd);
1.1.1.2 ! misho     186: 
1.1       misho     187:                        return &this->public;
                    188:                }
                    189: 
                    190:                /* create and initialize new IMA entry */
                    191:                entry = malloc_thing(event_entry_t);
1.1.1.2 ! misho     192:                entry->measurement = chunk_alloc(hash_size);
1.1       misho     193:                entry->algo = NULL;
                    194:                entry->name = NULL;
                    195: 
                    196:                if (res != 4 || pcr != IMA_PCR)
                    197:                {
                    198:                        error = "invalid IMA PCR field";
                    199:                        break;
                    200:                }
                    201: 
1.1.1.2 ! misho     202:                if (pcr_padding)
        !           203:                {
        !           204:                        memset(entry->measurement.ptr, 0x00, hash_size);
        !           205:                }
        !           206: 
        !           207:                /* read 20 byte SHA-1 IMA measurement digest */
1.1       misho     208:                if (read(fd, entry->measurement.ptr, HASH_SIZE_SHA1) != HASH_SIZE_SHA1)
                    209:                {
                    210:                        error = "invalid SHA-1 digest field";
                    211:                        break;
                    212:                }
                    213: 
                    214:                /* read 32 bit length of IMA type string in host order */
                    215:                if (read(fd, &type_len, 4) != 4 || type_len > IMA_TYPE_LEN_MAX)
                    216:                {
                    217:                        error = "invalid IMA type field length";
                    218:                        break;
                    219:                }
                    220: 
                    221:                /* read and interpret IMA type string */
                    222:                if (read(fd, type, type_len) != type_len)
                    223:                {
                    224:                        error = "invalid IMA type field";
                    225:                        break;
                    226:                }
                    227:                if (type_len == IMA_NG_TYPE_LEN &&
                    228:                        memeq(type, "ima-ng", IMA_NG_TYPE_LEN))
                    229:                {
                    230:                        ima_ng = TRUE;
                    231:                }
                    232:                else if (type_len == IMA_TYPE_LEN &&
                    233:                                 memeq(type, "ima", IMA_TYPE_LEN))
                    234:                {
                    235:                        ima_ng = FALSE;
                    236:                }
                    237:                else
                    238:                {
                    239:                        error = "unknown IMA type";
                    240:                        break;
                    241:                }
                    242: 
                    243:                if (ima_ng)
                    244:                {
                    245:                        /* read the 32 bit length of the event data in host order */
                    246:                        if (read(fd, &eventdata_len, 4) != 4 || eventdata_len < 4)
                    247:                        {
                    248:                                error = "invalid event data field length";
                    249:                                break;
                    250:                        }
                    251: 
                    252:                        /* read the 32 bit length of the algo_digest string in host order */
                    253:                        if (read(fd, &algo_digest_len, 4) != 4 ||
                    254:                                algo_digest_len > IMA_ALGO_DIGEST_LEN_MAX ||
                    255:                                eventdata_len < 4 + algo_digest_len + 4)
                    256:                        {
                    257:                                error = "invalid digest_with_algo field length";
                    258:                                break;
                    259:                        }
                    260: 
                    261:                        /* read the IMA algo_digest string */
                    262:                        if (read(fd, algo_digest, algo_digest_len) != algo_digest_len)
                    263:                        {
                    264:                                error = "invalid digest_with_algo field";
                    265:                                break;
                    266:                        }
                    267: 
                    268:                        /* extract the hash algorithm name */
                    269:                        pos = memchr(algo_digest, '\0', algo_digest_len);
                    270:                        if (!pos)
                    271:                        {
                    272:                                error = "no algo field";
                    273:                                break;
                    274:                        }
                    275:                        algo_len = pos - algo_digest + 1;
                    276: 
                    277:                        if (algo_len > IMA_ALGO_LEN_MAX ||
                    278:                                algo_len < IMA_ALGO_LEN_MIN || *(pos - 1) != ':')
                    279:                        {
                    280:                                error = "invalid algo field";
                    281:                                break;
                    282:                        }
                    283: 
                    284:                        /* copy and store the hash algorithm name */
                    285:                        entry->algo = malloc(algo_len);
                    286:                        memcpy(entry->algo, algo_digest, algo_len);
                    287: 
1.1.1.2 ! misho     288:                        /* extract the digest */
        !           289:                        digest = chunk_create(pos + 1, algo_digest_len - algo_len);
        !           290: 
1.1       misho     291:                        /* read the 32 bit length of the event name in host order */
                    292:                        if (read(fd, &name_len, 4) != 4 ||
                    293:                                eventdata_len != 4 + algo_digest_len + 4 + name_len)
                    294:                        {
                    295:                                error = "invalid filename field length";
                    296:                                break;
                    297:                        }
                    298: 
                    299:                        /* allocate memory for the file name */
                    300:                        entry->name = malloc(name_len);
                    301: 
                    302:                        /* read file name */
                    303:                        if (read(fd, entry->name, name_len) != name_len)
                    304:                        {
                    305:                                error = "invalid filename field";
                    306:                                break;
                    307:                        }
1.1.1.2 ! misho     308: 
        !           309:                        /* re-compute IMA measurement digest for non-SHA1 hash algorithms */
        !           310:                        if (pcr_algo != PTS_MEAS_ALGO_SHA1 && !pcr_padding)
        !           311:                        {
        !           312:                                if (!pts_ima_event_hash(digest, entry->algo, entry->name,
        !           313:                                                                                pcr_algo, entry->measurement.ptr))
        !           314:                                {
        !           315:                                        break;
        !           316:                                }
        !           317: 
        !           318:                        }
1.1       misho     319:                }
                    320:                else
                    321:                {
                    322:                        /* skip SHA-1 digest of the file content */
                    323:                        if (lseek(fd, HASH_SIZE_SHA1, SEEK_CUR) == -1)
                    324:                        {
                    325:                                break;
                    326:                        }
                    327: 
                    328:                        /* read the 32 bit length of the file name in host order */
                    329:                        if (read(fd, &name_len, 4) != 4 || name_len == UINT32_MAX)
                    330:                        {
                    331:                                error = "invalid filename field length";
                    332:                                break;
                    333:                        }
                    334: 
                    335:                        /* allocate memory for the file name */
                    336:                        entry->name = malloc(name_len + 1);
                    337: 
                    338:                        /* read file name */
                    339:                        if (read(fd, entry->name, name_len) != name_len)
                    340:                        {
                    341:                                error = "invalid eventname field";
                    342:                                break;
                    343:                        }
                    344: 
                    345:                        /* terminate the file name with a nul character */
                    346:                        entry->name[name_len] = '\0';
                    347:                }
                    348: 
                    349:                this->list->insert_last(this->list, entry);
                    350:        }
                    351: 
                    352:        DBG1(DBG_PTS, "loading ima measurements '%s' failed: %s", file, error);
                    353:        free_event_entry(entry);
                    354:        close(fd);
                    355:        destroy(this);
                    356: 
                    357:        return NULL;
                    358: }
1.1.1.2 ! misho     359: 
        !           360: /**
        !           361:  * See header
        !           362:  */
        !           363: bool pts_ima_event_hash(chunk_t digest, char *ima_algo, char *ima_name,
        !           364:                                                pts_meas_algorithms_t pcr_algo, char *hash_buf)
        !           365: {
        !           366:        hash_algorithm_t hash_alg;
        !           367:        hasher_t *hasher;
        !           368:        bool success;
        !           369: 
        !           370:        hash_alg = pts_meas_algo_to_hash(pcr_algo);
        !           371:        hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
        !           372:        if (!hasher)
        !           373:        {
        !           374:                DBG1(DBG_PTS, "%N hasher could not be created",
        !           375:                         hash_algorithm_short_names, hash_alg);
        !           376:                return FALSE;
        !           377:        }
        !           378: 
        !           379:        if (ima_algo)
        !           380:        {
        !           381:                uint32_t ad_len, n_len;
        !           382:                chunk_t algo_name, event_name, algo_digest_len, name_len;
        !           383: 
        !           384:                /* IMA-NG hash */
        !           385:                algo_name  = chunk_create(ima_algo, strlen(ima_algo) + 1);
        !           386:                event_name = chunk_create(ima_name, strlen(ima_name) + 1);
        !           387: 
        !           388:                ad_len = htole32(algo_name.len + digest.len);
        !           389:                algo_digest_len = chunk_create((uint8_t*)&ad_len, sizeof(ad_len));
        !           390: 
        !           391:                n_len = htole32(event_name.len);
        !           392:                name_len = chunk_create((uint8_t*)&n_len, sizeof(n_len));
        !           393: 
        !           394:                success = hasher->get_hash(hasher, algo_digest_len, NULL) &&
        !           395:                                  hasher->get_hash(hasher, algo_name, NULL) &&
        !           396:                                  hasher->get_hash(hasher, digest, NULL) &&
        !           397:                                  hasher->get_hash(hasher, name_len, NULL) &&
        !           398:                                  hasher->get_hash(hasher, event_name, hash_buf);
        !           399:        }
        !           400:        else
        !           401:        {
        !           402:                u_char filename_buffer[IMA_FILENAME_LEN_MAX + 1];
        !           403:                chunk_t file_name;
        !           404: 
        !           405:                /* IMA legacy hash */
        !           406:                memset(filename_buffer, 0, sizeof(filename_buffer));
        !           407:                strncpy(filename_buffer, ima_name, IMA_FILENAME_LEN_MAX);
        !           408:                file_name = chunk_create (filename_buffer, sizeof(filename_buffer));
        !           409: 
        !           410:                success = hasher->get_hash(hasher, digest, NULL) &&
        !           411:                                  hasher->get_hash(hasher, file_name, hash_buf);
        !           412:        }
        !           413:        hasher->destroy(hasher);
        !           414: 
        !           415:        return success;
        !           416: }

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