diff options
Diffstat (limited to 'src/libpts/pts')
-rw-r--r-- | src/libpts/pts/components/ita/ita_comp_ima.c | 62 | ||||
-rw-r--r-- | src/libpts/pts/components/ita/ita_comp_tboot.c | 68 | ||||
-rw-r--r-- | src/libpts/pts/pts.c | 29 | ||||
-rw-r--r-- | src/libpts/pts/pts.h | 8 | ||||
-rw-r--r-- | src/libpts/pts/pts_database.c | 96 | ||||
-rw-r--r-- | src/libpts/pts/pts_database.h | 34 |
6 files changed, 230 insertions, 67 deletions
diff --git a/src/libpts/pts/components/ita/ita_comp_ima.c b/src/libpts/pts/components/ita/ita_comp_ima.c index a05dc7e5e..808a59580 100644 --- a/src/libpts/pts/components/ita/ita_comp_ima.c +++ b/src/libpts/pts/components/ita/ita_comp_ima.c @@ -17,6 +17,7 @@ #include "ita_comp_ima.h" #include "ita_comp_func_name.h" +#include "libpts.h" #include "pts/components/pts_component.h" #include <debug.h> @@ -31,7 +32,6 @@ #define IMA_SECURITY_DIR "/sys/kernel/security/tpm0/" #define IMA_BIOS_MEASUREMENT_PATH IMA_SECURITY_DIR "binary_bios_measurements" #define IMA_PCR_MAX 8 -#define IMA_SEQUENCE 126 typedef struct pts_ita_comp_ima_t pts_ita_comp_ima_t; @@ -57,6 +57,11 @@ struct pts_ita_comp_ima_t { u_int32_t depth; /** + * AIK keyid + */ + chunk_t keyid; + + /** * IMA BIOS measurement time */ time_t bios_measurement_time; @@ -67,6 +72,11 @@ struct pts_ita_comp_ima_t { linked_list_t *list; /** + * Expected measurement count + */ + int count; + + /** * Measurement sequence number */ int seq_no; @@ -247,27 +257,50 @@ METHOD(pts_component_t, verify, status_t, pts_comp_evidence_t *evidence) { bool has_pcr_info; - char *platform_info; - u_int32_t extended_pcr; + u_int32_t extended_pcr, vid, name; + enum_name_t *names; pts_meas_algorithms_t algo; pts_pcr_transform_t transform; time_t measurement_time; chunk_t measurement, pcr_before, pcr_after; - platform_info = pts->get_platform_info(pts); - if (!pts_db || !platform_info) - { - DBG1(DBG_PTS, "%s%s%s not available", - (pts_db) ? "" : "pts database", - (!pts_db && !platform_info) ? "and" : "", - (platform_info) ? "" : "platform info"); - return FAILED; - } measurement = evidence->get_measurement(evidence, &extended_pcr, &algo, &transform, &measurement_time); + if (!this->keyid.ptr) + { + if (!pts->get_aik_keyid(pts, &this->keyid)) + { + return FAILED; + } + this->keyid = chunk_clone(this->keyid); + + if (!pts_db) + { + DBG1(DBG_PTS, "pts database not available"); + return FAILED; + } + if (!pts_db->get_comp_measurement_count(pts_db, this->name, this->keyid, + algo, &this->count)) + { + return FAILED; + } + vid = this->name->get_vendor_id(this->name); + name = this->name->get_name(this->name); + names = pts_components->get_comp_func_names(pts_components, vid); + + if (this->count == 0) + { + DBG1(DBG_PTS, "no %N '%N' functional component evidence measurements " + "available", pen_names, vid, names, name); + return FAILED; + } + DBG1(DBG_PTS, "checking %d %N '%N' functional component evidence measurements", + this->count, pen_names, vid, names, name); + } + if (pts_db->check_comp_measurement(pts_db, measurement, this->name, - platform_info, ++this->seq_no, extended_pcr, algo) != SUCCESS) + this->keyid, ++this->seq_no, extended_pcr, algo) != SUCCESS) { return FAILED; } @@ -281,7 +314,7 @@ METHOD(pts_component_t, verify, status_t, } } - return (this->seq_no < IMA_SEQUENCE) ? NEED_MORE : SUCCESS; + return (this->seq_no < this->count) ? NEED_MORE : SUCCESS; } METHOD(pts_component_t, destroy, void, @@ -295,6 +328,7 @@ METHOD(pts_component_t, destroy, void, } this->list->destroy_function(this->list, (void *)free_entry); this->name->destroy(this->name); + free(this->keyid.ptr); free(this); } diff --git a/src/libpts/pts/components/ita/ita_comp_tboot.c b/src/libpts/pts/components/ita/ita_comp_tboot.c index 572828ad1..67ad2d432 100644 --- a/src/libpts/pts/components/ita/ita_comp_tboot.c +++ b/src/libpts/pts/components/ita/ita_comp_tboot.c @@ -17,14 +17,12 @@ #include "ita_comp_tboot.h" #include "ita_comp_func_name.h" +#include "libpts.h" #include "pts/components/pts_component.h" -#include "pts/components/pts_comp_evidence.h" #include <debug.h> #include <pen/pen.h> -#define TBOOT_SEQUENCE 2 - typedef struct pts_ita_comp_tboot_t pts_ita_comp_tboot_t; /** @@ -49,11 +47,21 @@ struct pts_ita_comp_tboot_t { u_int32_t depth; /** + * AIK keyid + */ + chunk_t keyid; + + /** * Time of TBOOT measurement */ time_t measurement_time; /** + * Expected measurement count + */ + int count; + + /** * Measurement sequence number */ int seq_no; @@ -144,7 +152,7 @@ METHOD(pts_component_t, measure, status_t, this->measurement_time, measurement); evid->set_pcr_info(evid, pcr_before, pcr_after); - return (this->seq_no < TBOOT_SEQUENCE) ? NEED_MORE : SUCCESS; + return (this->seq_no < 2) ? NEED_MORE : SUCCESS; } METHOD(pts_component_t, verify, status_t, @@ -152,27 +160,50 @@ METHOD(pts_component_t, verify, status_t, pts_comp_evidence_t *evidence) { bool has_pcr_info; - char *platform_info; - u_int32_t extended_pcr; + u_int32_t extended_pcr, vid, name; + enum_name_t *names; pts_meas_algorithms_t algo; pts_pcr_transform_t transform; time_t measurement_time; - chunk_t measurement, pcr_before, pcr_after, hash; + chunk_t measurement, pcr_before, pcr_after; - platform_info = pts->get_platform_info(pts); - if (!pts_db || !platform_info) - { - DBG1(DBG_PTS, "%s%s%s not available", - (pts_db) ? "" : "pts database", - (!pts_db && !platform_info) ? "and" : "", - (platform_info) ? "" : "platform info"); - return FAILED; - } measurement = evidence->get_measurement(evidence, &extended_pcr, &algo, &transform, &measurement_time); + if (!this->keyid.ptr) + { + if (!pts->get_aik_keyid(pts, &this->keyid)) + { + return FAILED; + } + this->keyid = chunk_clone(this->keyid); + + if (!pts_db) + { + DBG1(DBG_PTS, "pts database not available"); + return FAILED; + } + if (!pts_db->get_comp_measurement_count(pts_db, this->name, this->keyid, + algo, &this->count)) + { + return FAILED; + } + vid = this->name->get_vendor_id(this->name); + name = this->name->get_name(this->name); + names = pts_components->get_comp_func_names(pts_components, vid); + + if (this->count == 0) + { + DBG1(DBG_PTS, "no %N '%N' functional component evidence measurements " + "available", pen_names, vid, names, name); + return FAILED; + } + DBG1(DBG_PTS, "checking %d %N '%N' functional component evidence measurements", + this->count, pen_names, vid, names, name); + } + if (pts_db->check_comp_measurement(pts_db, measurement, this->name, - platform_info, ++this->seq_no, extended_pcr, algo) != SUCCESS) + this->keyid, ++this->seq_no, extended_pcr, algo) != SUCCESS) { return FAILED; } @@ -186,13 +217,14 @@ METHOD(pts_component_t, verify, status_t, } } - return (this->seq_no < TBOOT_SEQUENCE) ? NEED_MORE : SUCCESS; + return (this->seq_no < this->count) ? NEED_MORE : SUCCESS; } METHOD(pts_component_t, destroy, void, pts_ita_comp_tboot_t *this) { this->name->destroy(this->name); + free(this->keyid.ptr); free(this); } diff --git a/src/libpts/pts/pts.c b/src/libpts/pts/pts.c index bf5c2bcf7..c30a55719 100644 --- a/src/libpts/pts/pts.c +++ b/src/libpts/pts/pts.c @@ -459,6 +459,33 @@ METHOD(pts_t, set_aik, void, this->aik = aik->get_ref(aik); } +METHOD(pts_t, get_aik_keyid, bool, + private_pts_t *this, chunk_t *keyid) +{ + public_key_t *public; + bool success; + + if (!this->aik) + { + DBG1(DBG_PTS, "no AIK certificate available"); + return FALSE; + } + public = this->aik->get_public_key(this->aik); + if (!public) + { + DBG1(DBG_PTS, "no AIK public key available"); + return FALSE; + } + success = public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, keyid); + if (!success) + { + DBG1(DBG_PTS, "no SHA-1 AIK public key info ID available"); + } + public->destroy(public); + + return success; +} + METHOD(pts_t, hash_file, bool, private_pts_t *this, hasher_t *hasher, char *pathname, u_char *hash) { @@ -932,7 +959,6 @@ METHOD(pts_t, quote_tpm, bool, } if (this->pcr_select[i] & f) { - DBG2(DBG_TNC, "PCR %02d selected for TPM Quote", pcr); result = use_quote2 ? Tspi_PcrComposite_SelectPcrIndexEx(hPcrComposite, pcr, TSS_PCRS_DIRECTION_RELEASE) : @@ -1510,6 +1536,7 @@ pts_t *pts_create(bool is_imc) .get_pcr_len = _get_pcr_len, .get_aik = _get_aik, .set_aik = _set_aik, + .get_aik_keyid = _get_aik_keyid, .is_path_valid = _is_path_valid, .hash_file = _hash_file, .do_measurements = _do_measurements, diff --git a/src/libpts/pts/pts.h b/src/libpts/pts/pts.h index 3a40c1e1d..327b1a13d 100644 --- a/src/libpts/pts/pts.h +++ b/src/libpts/pts/pts.h @@ -246,6 +246,14 @@ struct pts_t { void (*set_aik)(pts_t *this, certificate_t *aik); /** + * Get SHA-1 Attestation Identity Public Key Info ID + * + * @param keyid AIK ID + * @return TRUE if AIK ID exists + */ + bool (*get_aik_keyid)(pts_t *this, chunk_t *keyid); + + /** * Check whether path is valid file/directory on filesystem * * @param path Absolute path diff --git a/src/libpts/pts/pts_database.c b/src/libpts/pts/pts_database.c index cb2d104f0..d91a408cf 100644 --- a/src/libpts/pts/pts_database.c +++ b/src/libpts/pts/pts_database.c @@ -69,23 +69,6 @@ METHOD(pts_database_t, create_file_meta_enumerator, enumerator_t*, return e; } -METHOD(pts_database_t, create_comp_evid_enumerator, enumerator_t*, - private_pts_database_t *this, char *product) -{ - enumerator_t *e; - - /* look for all entries belonging to a product in the components table */ - e = this->db->query(this->db, - "SELECT c.vendor_id, c.name, c.qualifier, pc.depth " - "FROM components AS c " - "JOIN product_component AS pc ON c.id = pc.component " - "JOIN products AS p ON p.id = pc.product " - "WHERE p.name = ? ORDER BY pc.seq_no", - DB_TEXT, product, DB_INT, DB_INT, DB_INT, DB_INT); - return e; -} - - METHOD(pts_database_t, create_file_hash_enumerator, enumerator_t*, private_pts_database_t *this, char *product, pts_meas_algorithms_t algo, int id, bool is_dir) @@ -114,9 +97,25 @@ METHOD(pts_database_t, create_file_hash_enumerator, enumerator_t*, return e; } +METHOD(pts_database_t, create_comp_evid_enumerator, enumerator_t*, + private_pts_database_t *this, chunk_t keyid) +{ + enumerator_t *e; + + /* look for all entries belonging to a product in the components table */ + e = this->db->query(this->db, + "SELECT c.vendor_id, c.name, c.qualifier, kc.depth " + "FROM components AS c " + "JOIN key_component AS kc ON c.id = kc.component " + "JOIN keys AS k ON k.id = kc.key " + "WHERE k.keyid = ? ORDER BY kc.seq_no", + DB_BLOB, keyid, DB_INT, DB_INT, DB_INT, DB_INT); + return e; +} + METHOD(pts_database_t, check_comp_measurement, status_t, private_pts_database_t *this, chunk_t measurement, - pts_comp_func_name_t *comp_name, char *product, + pts_comp_func_name_t *comp_name, chunk_t keyid, int seq_no, int pcr, pts_meas_algorithms_t algo) { enumerator_t *e; @@ -125,14 +124,14 @@ METHOD(pts_database_t, check_comp_measurement, status_t, e = this->db->query(this->db, "SELECT ch.hash FROM component_hashes AS ch " - "JOIN products AS p ON ch.product = p.id " + "JOIN keys AS k ON ch.key = k.id " "JOIN components AS c ON ch.component = c.id " "WHERE c.vendor_id = ? AND c.name = ? AND c.qualifier = ? " - "AND p.name = ? AND ch.seq_no = ? AND ch.pcr = ? AND ch.algo = ? ", + "AND k.keyid = ? AND ch.seq_no = ? AND ch.pcr = ? AND ch.algo = ? ", DB_INT, comp_name->get_vendor_id(comp_name), DB_INT, comp_name->get_name(comp_name), DB_INT, comp_name->get_qualifier(comp_name), - DB_TEXT, product, DB_INT, seq_no, DB_INT, pcr, DB_INT, algo, + DB_BLOB, keyid, DB_INT, seq_no, DB_INT, pcr, DB_INT, algo, DB_BLOB); if (!e) { @@ -144,8 +143,6 @@ METHOD(pts_database_t, check_comp_measurement, status_t, { if (chunk_equals(hash, measurement)) { - DBG2(DBG_PTS, "PCR %2d matching component measurement #%d " - "found in database", pcr, seq_no); status = SUCCESS; break; } @@ -170,6 +167,58 @@ METHOD(pts_database_t, check_comp_measurement, status_t, return status; } +METHOD(pts_database_t, get_comp_measurement_count, bool, + private_pts_database_t *this, pts_comp_func_name_t *comp_name, + chunk_t keyid, pts_meas_algorithms_t algo, int *count) +{ + enumerator_t *e; + int kid; + bool success = TRUE; + + /* Initialize count */ + *count = 0; + + /* Is the AIK registered? */ + e = this->db->query(this->db, + "SELECT id FROM keys WHERE keyid = ?", DB_BLOB, keyid, DB_INT); + if (!e) + { + DBG1(DBG_PTS, "no database query enumerator returned"); + return FALSE; + } + if (!e->enumerate(e, &kid)) + { + DBG1(DBG_PTS, "AIK %#B is not registered in database", &keyid); + e->destroy(e); + return FALSE; + } + e->destroy(e); + + /* Get the number of stored measurements for a given AIK and component */ + e = this->db->query(this->db, + "SELECT COUNT(*) FROM component_hashes AS ch " + "JOIN components AS c ON ch.component = c.id " + "WHERE c.vendor_id = ? AND c.name = ? AND c.qualifier = ? " + "AND ch.key = ? AND ch.algo = ? ", + DB_INT, comp_name->get_vendor_id(comp_name), + DB_INT, comp_name->get_name(comp_name), + DB_INT, comp_name->get_qualifier(comp_name), + DB_INT, kid, DB_INT, algo, DB_INT); + if (!e) + { + DBG1(DBG_PTS, "no database query enumerator returned"); + return FALSE; + } + if (!e->enumerate(e, count)) + { + DBG1(DBG_PTS, "no component measurement count returned from database"); + success = FALSE; + } + e->destroy(e); + + return success; +} + METHOD(pts_database_t, destroy, void, private_pts_database_t *this) { @@ -191,6 +240,7 @@ pts_database_t *pts_database_create(char *uri) .create_comp_evid_enumerator = _create_comp_evid_enumerator, .create_file_hash_enumerator = _create_file_hash_enumerator, .check_comp_measurement = _check_comp_measurement, + .get_comp_measurement_count = _get_comp_measurement_count, .destroy = _destroy, }, .db = lib->db->create(lib->db, uri), diff --git a/src/libpts/pts/pts_database.h b/src/libpts/pts/pts_database.h index 3ed0b5bd5..61c00a1e9 100644 --- a/src/libpts/pts/pts_database.h +++ b/src/libpts/pts/pts_database.h @@ -52,15 +52,6 @@ struct pts_database_t { char *product); /** - * Get functional components to request evidence of - * - * @param product Software product (os, vpn client, etc.) - * @return Enumerator over all matching components - */ - enumerator_t* (*create_comp_evid_enumerator)(pts_database_t *this, - char *product); - - /** * Get stored measurement hash for single file or directory entries * * @param product Software product (os, vpn client, etc.) @@ -74,21 +65,42 @@ struct pts_database_t { int id, bool is_dir); /** + * Get functional components to request evidence of + * + * @param keyid SHA-1 hash of AIK public key info + * @return Enumerator over all matching components + */ + enumerator_t* (*create_comp_evid_enumerator)(pts_database_t *this, + chunk_t keyid); + + /** * Check a functional component measurement against value stored in database * * @param measurement measurement hash * @param comp_name Component Functional Name - * @param product Software product (os, vpn client, etc.) + * @param keyid SHA-1 hash of AIK public key info * @param seq_no Measurement sequence number * @param prc Number of the PCR the measurement was extended into * @param algo Hash algorithm used for measurement * @return return code */ status_t (*check_comp_measurement)(pts_database_t *this, chunk_t measurement, - pts_comp_func_name_t *comp_name, char *product, + pts_comp_func_name_t *comp_name, chunk_t keyid, int seq_no, int pcr, pts_meas_algorithms_t algo); /** + * Get the number of measurements for a functional component and AIK + * + * @param comp_name Component Functional Name + * @param keyid SHA-1 hash of AIK public key info + * @param algo Hash algorithm used for measurement + * @return measurement count + */ + bool (*get_comp_measurement_count)(pts_database_t *this, + pts_comp_func_name_t *comp_name, chunk_t keyid, + pts_meas_algorithms_t algo, int *count); + + /** * Destroys a pts_database_t object. */ void (*destroy)(pts_database_t *this); |