aboutsummaryrefslogtreecommitdiffstats
path: root/src/libpts/pts
diff options
context:
space:
mode:
Diffstat (limited to 'src/libpts/pts')
-rw-r--r--src/libpts/pts/components/ita/ita_comp_ima.c62
-rw-r--r--src/libpts/pts/components/ita/ita_comp_tboot.c68
-rw-r--r--src/libpts/pts/pts.c29
-rw-r--r--src/libpts/pts/pts.h8
-rw-r--r--src/libpts/pts/pts_database.c96
-rw-r--r--src/libpts/pts/pts_database.h34
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);