bound functional component measurements to AIK

This commit is contained in:
Andreas Steffen
2011-11-28 21:24:00 +01:00
parent 86a6f698cb
commit f2a521e795
14 changed files with 1295 additions and 771 deletions
+36 -2
View File
@@ -97,10 +97,12 @@ static void do_args(int argc, char *argv[])
enum { enum {
OP_UNDEF, OP_UNDEF,
OP_USAGE, OP_USAGE,
OP_FILES, OP_KEYS,
OP_COMPONENTS, OP_COMPONENTS,
OP_PRODUCTS, OP_FILES,
OP_HASHES, OP_HASHES,
OP_MEASUREMENTS,
OP_PRODUCTS,
OP_ADD, OP_ADD,
OP_DEL, OP_DEL,
} op = OP_UNDEF; } op = OP_UNDEF;
@@ -116,8 +118,10 @@ static void do_args(int argc, char *argv[])
{ "help", no_argument, NULL, 'h' }, { "help", no_argument, NULL, 'h' },
{ "components", no_argument, NULL, 'c' }, { "components", no_argument, NULL, 'c' },
{ "files", no_argument, NULL, 'f' }, { "files", no_argument, NULL, 'f' },
{ "keys", no_argument, NULL, 'k' },
{ "products", no_argument, NULL, 'p' }, { "products", no_argument, NULL, 'p' },
{ "hashes", no_argument, NULL, 'H' }, { "hashes", no_argument, NULL, 'H' },
{ "measurements", no_argument, NULL, 'M' },
{ "add", no_argument, NULL, 'a' }, { "add", no_argument, NULL, 'a' },
{ "delete", no_argument, NULL, 'd' }, { "delete", no_argument, NULL, 'd' },
{ "del", no_argument, NULL, 'd' }, { "del", no_argument, NULL, 'd' },
@@ -129,6 +133,8 @@ static void do_args(int argc, char *argv[])
{ "directory", required_argument, NULL, 'D' }, { "directory", required_argument, NULL, 'D' },
{ "dir", required_argument, NULL, 'D' }, { "dir", required_argument, NULL, 'D' },
{ "file", required_argument, NULL, 'F' }, { "file", required_argument, NULL, 'F' },
{ "key", required_argument, NULL, 'K' },
{ "owner", required_argument, NULL, 'O' },
{ "product", required_argument, NULL, 'P' }, { "product", required_argument, NULL, 'P' },
{ "sha1", no_argument, NULL, '1' }, { "sha1", no_argument, NULL, '1' },
{ "sha256", no_argument, NULL, '2' }, { "sha256", no_argument, NULL, '2' },
@@ -137,6 +143,7 @@ static void do_args(int argc, char *argv[])
{ "fid", required_argument, NULL, '5' }, { "fid", required_argument, NULL, '5' },
{ "pid", required_argument, NULL, '6' }, { "pid", required_argument, NULL, '6' },
{ "cid", required_argument, NULL, '7' }, { "cid", required_argument, NULL, '7' },
{ "kid", required_argument, NULL, '8' },
{ 0,0,0,0 } { 0,0,0,0 }
}; };
@@ -154,12 +161,18 @@ static void do_args(int argc, char *argv[])
case 'f': case 'f':
op = OP_FILES; op = OP_FILES;
continue; continue;
case 'k':
op = OP_KEYS;
continue;
case 'p': case 'p':
op = OP_PRODUCTS; op = OP_PRODUCTS;
continue; continue;
case 'H': case 'H':
op = OP_HASHES; op = OP_HASHES;
continue; continue;
case 'M':
op = OP_MEASUREMENTS;
continue;
case 'a': case 'a':
op = OP_ADD; op = OP_ADD;
continue; continue;
@@ -199,6 +212,15 @@ static void do_args(int argc, char *argv[])
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
continue; continue;
case 'K':
if (!attest->set_key(attest, optarg, op == OP_ADD))
{
exit(EXIT_FAILURE);
}
continue;
case 'O':
attest->set_owner(attest, optarg);
continue;
case 'P': case 'P':
if (!attest->set_product(attest, optarg, op == OP_ADD)) if (!attest->set_product(attest, optarg, op == OP_ADD))
{ {
@@ -238,6 +260,12 @@ static void do_args(int argc, char *argv[])
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
continue; continue;
case '8':
if (!attest->set_kid(attest, atoi(optarg)))
{
exit(EXIT_FAILURE);
}
continue;
} }
break; break;
} }
@@ -250,6 +278,9 @@ static void do_args(int argc, char *argv[])
case OP_PRODUCTS: case OP_PRODUCTS:
attest->list_products(attest); attest->list_products(attest);
break; break;
case OP_KEYS:
attest->list_keys(attest);
break;
case OP_COMPONENTS: case OP_COMPONENTS:
attest->list_components(attest); attest->list_components(attest);
break; break;
@@ -259,6 +290,9 @@ static void do_args(int argc, char *argv[])
case OP_HASHES: case OP_HASHES:
attest->list_hashes(attest); attest->list_hashes(attest);
break; break;
case OP_MEASUREMENTS:
attest->list_measurements(attest);
break;
case OP_ADD: case OP_ADD:
attest->add(attest); attest->add(attest);
break; break;
File diff suppressed because it is too large Load Diff
+69 -34
View File
@@ -33,40 +33,6 @@ typedef struct attest_db_t attest_db_t;
*/ */
struct attest_db_t { struct attest_db_t {
/**
* Set software product to be queried
*
* @param product software product
* @param create if TRUE create database entry if it doesn't exist
* @return TRUE if successful
*/
bool (*set_product)(attest_db_t *this, char *product, bool create);
/**
* Set primary key of the software product to be queried
*
* @param pid primary key of software product
* @return TRUE if successful
*/
bool (*set_pid)(attest_db_t *this, int pid);
/**
* Set measurement file to be queried
*
* @param file measurement file
* @param create if TRUE create database entry if it doesn't exist
* @return TRUE if successful
*/
bool (*set_file)(attest_db_t *this, char *file, bool create);
/**
* Set primary key of the measurement file to be queried
*
* @param fid primary key of measurement file
* @return TRUE if successful
*/
bool (*set_fid)(attest_db_t *this, int fid);
/** /**
* Set functional component to be queried * Set functional component to be queried
* *
@@ -101,6 +67,57 @@ struct attest_db_t {
*/ */
bool (*set_did)(attest_db_t *this, int did); bool (*set_did)(attest_db_t *this, int did);
/**
* Set measurement file to be queried
*
* @param file measurement file
* @param create if TRUE create database entry if it doesn't exist
* @return TRUE if successful
*/
bool (*set_file)(attest_db_t *this, char *file, bool create);
/**
* Set primary key of the measurement file to be queried
*
* @param fid primary key of measurement file
* @return TRUE if successful
*/
bool (*set_fid)(attest_db_t *this, int fid);
/**
* Set functional component to be queried
*
* @param key AIK
* @param create if TRUE create database entry if it doesn't exist
* @return TRUE if successful
*/
bool (*set_key)(attest_db_t *this, char *key, bool create);
/**
* Set primary key of the AIK to be queried
*
* @param kid primary key of AIK
* @return TRUE if successful
*/
bool (*set_kid)(attest_db_t *this, int kid);
/**
* Set software product to be queried
*
* @param product software product
* @param create if TRUE create database entry if it doesn't exist
* @return TRUE if successful
*/
bool (*set_product)(attest_db_t *this, char *product, bool create);
/**
* Set primary key of the software product to be queried
*
* @param pid primary key of software product
* @return TRUE if successful
*/
bool (*set_pid)(attest_db_t *this, int pid);
/** /**
* Set measurement hash algorithm * Set measurement hash algorithm
* *
@@ -108,6 +125,14 @@ struct attest_db_t {
*/ */
void (*set_algo)(attest_db_t *this, pts_meas_algorithms_t algo); void (*set_algo)(attest_db_t *this, pts_meas_algorithms_t algo);
/**
* Set owner [user/host] of an AIK
*
* @param owner user/host name
* @return TRUE if successful
*/
void (*set_owner)(attest_db_t *this, char *owner);
/** /**
* List all products stored in the database * List all products stored in the database
*/ */
@@ -123,11 +148,21 @@ struct attest_db_t {
*/ */
void (*list_components)(attest_db_t *this); void (*list_components)(attest_db_t *this);
/**
* List all AIKs stored in the database
*/
void (*list_keys)(attest_db_t *this);
/** /**
* List selected measurement hashes stored in the database * List selected measurement hashes stored in the database
*/ */
void (*list_hashes)(attest_db_t *this); void (*list_hashes)(attest_db_t *this);
/**
* List selected component measurement stored in the database
*/
void (*list_measurements)(attest_db_t *this);
/** /**
* Add an entry to the database * Add an entry to the database
*/ */
@@ -24,16 +24,14 @@ void usage(void)
{ {
printf("\ printf("\
Usage:\n\ Usage:\n\
ipsec attest --files|--components|--products|--hashes|--add|--del [options]\n\ ipsec attest --files|--products|--keys|--hashes [options]\n\
\n\
ipsec attest --components|-keys|--measurements|--add|--del [options]\n\
\n\ \n\
ipsec attest --files [--product <name>|--pid <id>]\n\ ipsec attest --files [--product <name>|--pid <id>]\n\
Show a list of files with a software product name or\n\ Show a list of files with a software product name or\n\
its primary key as an optional selector.\n\ its primary key as an optional selector.\n\
\n\ \n\
ipsec attest --components [--product <name>|--pid <id>]\n\
Show a list of components with a software product name or\n\
its primary key as an optional selector.\n\
\n\
ipsec attest --products [--file <path>|--fid <id>]\n\ ipsec attest --products [--file <path>|--fid <id>]\n\
Show a list of supported software products with a file path or\n\ Show a list of supported software products with a file path or\n\
its primary key as an optional selector.\n\ its primary key as an optional selector.\n\
@@ -46,15 +44,37 @@ Usage:\n\
Show a list of measurement hashes for a given file or\n\ Show a list of measurement hashes for a given file or\n\
its primary key as an optional selector.\n\ its primary key as an optional selector.\n\
\n\ \n\
ipsec attest --components [--key <digest>|--kid <id>]\n\
Show a list of components with an AIK digest or\n\
its primary key as an optional selector.\n\
\n\
ipsec attest --keys [--components <cfn>|--cid <id>]\n\
Show a list of AIK key digests with a component or\n\
its primary key as an optional selector.\n\
\n\
ipsec attest --measurements [--sha1|--sha256|--sha384] [--component <cfn>|--cid <id>]\n\
Show a list of component measurements for a given component or\n\
its primary key as an optional selector.\n\
\n\
ipsec attest --measurements [--sha1|--sha256|--sha384] [--key <digest>|--kid <id>]\n\
Show a list of component measurements for a given AIK or\n\
its primary key as an optional selector.\n\
\n\
ipsec attest --add --file <path>|--dir <path>|--product <name>|--component <cfn>\n\ ipsec attest --add --file <path>|--dir <path>|--product <name>|--component <cfn>\n\
Add a file, directory, product or component entry\n\ Add a file, directory, product or component entry\n\
Component <cfn> entries must be of the form <vendor_id>/<name>-<qualifier>\n\ Component <cfn> entries must be of the form <vendor_id>/<name>-<qualifier>\n\
\n\ \n\
ipsec attest --add [--owner <name>] --key <digest>\n\
Add an AIK public key digest entry preceded by an optional owner name\n\
\n\
ipsec attest --del --file <path>|--fid <id>|--dir <path>|--did <id>\n\ ipsec attest --del --file <path>|--fid <id>|--dir <path>|--did <id>\n\
Delete a file or directoryentry referenced either by value or primary key\n\ Delete a file or directory entry referenced either by value or primary key\n\
\n\ \n\
ipsec attest --del --product <name>|--pid <id>|--component <cfn>|--cid <id>\n\ ipsec attest --del --product <name>|--pid <id>|--component <cfn>|--cid <id>\n\
Delete a product or component entry referenced either by value or primary key\n\ Delete a product or component entry referenced either by value or primary key\n\
\n\
ipsec attest --del --key <digest>|--kid <id>\n\
Delete an AIK entry referenced either by value or primary key\n\
\n"); \n");
} }
File diff suppressed because it is too large Load Diff
@@ -210,9 +210,9 @@ bool imv_attestation_build(pa_tnc_msg_t *msg,
{ {
tcg_pts_attr_req_func_comp_evid_t *attr_cast; tcg_pts_attr_req_func_comp_evid_t *attr_cast;
enumerator_t *enumerator; enumerator_t *enumerator;
char *platform_info;
pts_component_t *comp; pts_component_t *comp;
pts_comp_func_name_t *comp_name; pts_comp_func_name_t *comp_name;
chunk_t keyid;
int vid, name, qualifier; int vid, name, qualifier;
u_int8_t flags; u_int8_t flags;
u_int32_t depth; u_int32_t depth;
@@ -221,18 +221,17 @@ bool imv_attestation_build(pa_tnc_msg_t *msg,
attestation_state->set_handshake_state(attestation_state, attestation_state->set_handshake_state(attestation_state,
IMV_ATTESTATION_STATE_END); IMV_ATTESTATION_STATE_END);
/* Get Platform and OS of the PTS-IMC */ if (!pts->get_aik_keyid(pts, &keyid))
platform_info = pts->get_platform_info(pts);
if (!pts_db || !platform_info)
{ {
DBG1(DBG_IMV, "%s%s%s not available", break;
(pts_db) ? "" : "pts database", }
(!pts_db && !platform_info) ? "and" : "", if (!pts_db)
(platform_info) ? "" : "platform info"); {
DBG1(DBG_PTS, "pts database not available");
break; break;
} }
enumerator = pts_db->create_comp_evid_enumerator(pts_db, platform_info); enumerator = pts_db->create_comp_evid_enumerator(pts_db, keyid);
if (!enumerator) if (!enumerator)
{ {
break; break;
@@ -146,6 +146,8 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list,
{ {
tcg_pts_attr_aik_t *attr_cast; tcg_pts_attr_aik_t *attr_cast;
certificate_t *aik, *issuer; certificate_t *aik, *issuer;
public_key_t *public;
chunk_t keyid;
enumerator_t *e; enumerator_t *e;
bool trusted = FALSE; bool trusted = FALSE;
@@ -158,7 +160,11 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list,
} }
if (aik->get_type(aik) == CERT_X509) if (aik->get_type(aik) == CERT_X509)
{ {
DBG1(DBG_IMV, "verifying AIK certificate"); public = aik->get_public_key(aik);
public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &keyid);
DBG1(DBG_IMV, "verifying AIK certificate with keyid %#B", &keyid);
public->destroy(public);
e = pts_credmgr->create_trusted_enumerator(pts_credmgr, e = pts_credmgr->create_trusted_enumerator(pts_credmgr,
KEY_ANY, aik->get_issuer(aik), FALSE); KEY_ANY, aik->get_issuer(aik), FALSE);
while (e->enumerate(e, &issuer)) while (e->enumerate(e, &issuer))
@@ -285,8 +291,10 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list,
default: default:
case FAILED: case FAILED:
attestation_state->set_measurement_error(attestation_state); attestation_state->set_measurement_error(attestation_state);
/* fall through to next case */ comp->destroy(comp);
break;
case SUCCESS: case SUCCESS:
name->log(name, " successfully measured ");
comp->destroy(comp); comp->destroy(comp);
break; break;
case NEED_MORE: case NEED_MORE:
+36 -19
View File
@@ -7,14 +7,6 @@ CREATE TABLE files (
path TEXT NOT NULL path TEXT NOT NULL
); );
DROP TABLE IF EXISTS components;
CREATE TABLE components (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
vendor_id INTEGER NOT NULL,
name INTEGER NOT NULL,
qualifier INTEGER DEFAULT 0
);
DROP TABLE IF EXISTS products; DROP TABLE IF EXISTS products;
CREATE TABLE products ( CREATE TABLE products (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
@@ -34,15 +26,6 @@ CREATE TABLE product_file (
PRIMARY KEY (product, file) PRIMARY KEY (product, file)
); );
DROP TABLE IF EXISTS product_component;
CREATE TABLE product_component (
product INTEGER NOT NULL,
component INTEGER NOT NULL,
depth INTEGER DEFAULT 0,
seq_no INTEGER DEFAULT 0,
PRIMARY KEY (product, component)
);
DROP TABLE IF EXISTS file_hashes; DROP TABLE IF EXISTS file_hashes;
CREATE TABLE file_hashes ( CREATE TABLE file_hashes (
file INTEGER NOT NULL, file INTEGER NOT NULL,
@@ -53,13 +36,47 @@ CREATE TABLE file_hashes (
PRIMARY KEY(file, directory, product, algo) PRIMARY KEY(file, directory, product, algo)
); );
DROP TABLE IF EXISTS keys;
CREATE TABLE keys (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
keyid BLOB NOT NULL,
owner TEXT NOT NULL
);
DROP INDEX IF EXISTS keys_keyid;
CREATE INDEX keys_keyid ON keys (
keyid
);
DROP INDEX IF EXISTS keys_owner;
CREATE INDEX keys_owner ON keys (
owner
);
DROP TABLE IF EXISTS components;
CREATE TABLE components (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
vendor_id INTEGER NOT NULL,
name INTEGER NOT NULL,
qualifier INTEGER DEFAULT 0
);
DROP TABLE IF EXISTS key_component;
CREATE TABLE key_component (
key INTEGER NOT NULL,
component INTEGER NOT NULL,
depth INTEGER DEFAULT 0,
seq_no INTEGER DEFAULT 0,
PRIMARY KEY (key, component)
);
DROP TABLE IF EXISTS component_hashes; DROP TABLE IF EXISTS component_hashes;
CREATE TABLE component_hashes ( CREATE TABLE component_hashes (
component INTEGER NOT NULL, component INTEGER NOT NULL,
product INTEGER NOT NULL, key INTEGER NOT NULL,
seq_no INTEGER NOT NULL, seq_no INTEGER NOT NULL,
pcr INTEGER NOT NULL, pcr INTEGER NOT NULL,
algo INTEGER NOT NULL, algo INTEGER NOT NULL,
hash BLOB NOT NULL, hash BLOB NOT NULL,
PRIMARY KEY(component, product, seq_no, algo) PRIMARY KEY(component, key, seq_no, algo)
); );
+48 -14
View File
@@ -17,6 +17,7 @@
#include "ita_comp_ima.h" #include "ita_comp_ima.h"
#include "ita_comp_func_name.h" #include "ita_comp_func_name.h"
#include "libpts.h"
#include "pts/components/pts_component.h" #include "pts/components/pts_component.h"
#include <debug.h> #include <debug.h>
@@ -31,7 +32,6 @@
#define IMA_SECURITY_DIR "/sys/kernel/security/tpm0/" #define IMA_SECURITY_DIR "/sys/kernel/security/tpm0/"
#define IMA_BIOS_MEASUREMENT_PATH IMA_SECURITY_DIR "binary_bios_measurements" #define IMA_BIOS_MEASUREMENT_PATH IMA_SECURITY_DIR "binary_bios_measurements"
#define IMA_PCR_MAX 8 #define IMA_PCR_MAX 8
#define IMA_SEQUENCE 126
typedef struct pts_ita_comp_ima_t pts_ita_comp_ima_t; typedef struct pts_ita_comp_ima_t pts_ita_comp_ima_t;
@@ -56,6 +56,11 @@ struct pts_ita_comp_ima_t {
*/ */
u_int32_t depth; u_int32_t depth;
/**
* AIK keyid
*/
chunk_t keyid;
/** /**
* IMA BIOS measurement time * IMA BIOS measurement time
*/ */
@@ -66,6 +71,11 @@ struct pts_ita_comp_ima_t {
*/ */
linked_list_t *list; linked_list_t *list;
/**
* Expected measurement count
*/
int count;
/** /**
* Measurement sequence number * Measurement sequence number
*/ */
@@ -247,27 +257,50 @@ METHOD(pts_component_t, verify, status_t,
pts_comp_evidence_t *evidence) pts_comp_evidence_t *evidence)
{ {
bool has_pcr_info; bool has_pcr_info;
char *platform_info; u_int32_t extended_pcr, vid, name;
u_int32_t extended_pcr; enum_name_t *names;
pts_meas_algorithms_t algo; pts_meas_algorithms_t algo;
pts_pcr_transform_t transform; pts_pcr_transform_t transform;
time_t measurement_time; time_t measurement_time;
chunk_t measurement, pcr_before, pcr_after; 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, measurement = evidence->get_measurement(evidence, &extended_pcr,
&algo, &transform, &measurement_time); &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, 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; 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, 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->list->destroy_function(this->list, (void *)free_entry);
this->name->destroy(this->name); this->name->destroy(this->name);
free(this->keyid.ptr);
free(this); free(this);
} }
+50 -18
View File
@@ -17,14 +17,12 @@
#include "ita_comp_tboot.h" #include "ita_comp_tboot.h"
#include "ita_comp_func_name.h" #include "ita_comp_func_name.h"
#include "libpts.h"
#include "pts/components/pts_component.h" #include "pts/components/pts_component.h"
#include "pts/components/pts_comp_evidence.h"
#include <debug.h> #include <debug.h>
#include <pen/pen.h> #include <pen/pen.h>
#define TBOOT_SEQUENCE 2
typedef struct pts_ita_comp_tboot_t pts_ita_comp_tboot_t; typedef struct pts_ita_comp_tboot_t pts_ita_comp_tboot_t;
/** /**
@@ -48,11 +46,21 @@ struct pts_ita_comp_tboot_t {
*/ */
u_int32_t depth; u_int32_t depth;
/**
* AIK keyid
*/
chunk_t keyid;
/** /**
* Time of TBOOT measurement * Time of TBOOT measurement
*/ */
time_t measurement_time; time_t measurement_time;
/**
* Expected measurement count
*/
int count;
/** /**
* Measurement sequence number * Measurement sequence number
*/ */
@@ -144,7 +152,7 @@ METHOD(pts_component_t, measure, status_t,
this->measurement_time, measurement); this->measurement_time, measurement);
evid->set_pcr_info(evid, pcr_before, pcr_after); 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, METHOD(pts_component_t, verify, status_t,
@@ -152,27 +160,50 @@ METHOD(pts_component_t, verify, status_t,
pts_comp_evidence_t *evidence) pts_comp_evidence_t *evidence)
{ {
bool has_pcr_info; bool has_pcr_info;
char *platform_info; u_int32_t extended_pcr, vid, name;
u_int32_t extended_pcr; enum_name_t *names;
pts_meas_algorithms_t algo; pts_meas_algorithms_t algo;
pts_pcr_transform_t transform; pts_pcr_transform_t transform;
time_t measurement_time; 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, measurement = evidence->get_measurement(evidence, &extended_pcr,
&algo, &transform, &measurement_time); &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, 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; 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, METHOD(pts_component_t, destroy, void,
pts_ita_comp_tboot_t *this) pts_ita_comp_tboot_t *this)
{ {
this->name->destroy(this->name); this->name->destroy(this->name);
free(this->keyid.ptr);
free(this); free(this);
} }
+28 -1
View File
@@ -459,6 +459,33 @@ METHOD(pts_t, set_aik, void,
this->aik = aik->get_ref(aik); 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, METHOD(pts_t, hash_file, bool,
private_pts_t *this, hasher_t *hasher, char *pathname, u_char *hash) 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) if (this->pcr_select[i] & f)
{ {
DBG2(DBG_TNC, "PCR %02d selected for TPM Quote", pcr);
result = use_quote2 ? result = use_quote2 ?
Tspi_PcrComposite_SelectPcrIndexEx(hPcrComposite, pcr, Tspi_PcrComposite_SelectPcrIndexEx(hPcrComposite, pcr,
TSS_PCRS_DIRECTION_RELEASE) : TSS_PCRS_DIRECTION_RELEASE) :
@@ -1510,6 +1536,7 @@ pts_t *pts_create(bool is_imc)
.get_pcr_len = _get_pcr_len, .get_pcr_len = _get_pcr_len,
.get_aik = _get_aik, .get_aik = _get_aik,
.set_aik = _set_aik, .set_aik = _set_aik,
.get_aik_keyid = _get_aik_keyid,
.is_path_valid = _is_path_valid, .is_path_valid = _is_path_valid,
.hash_file = _hash_file, .hash_file = _hash_file,
.do_measurements = _do_measurements, .do_measurements = _do_measurements,
+8
View File
@@ -245,6 +245,14 @@ struct pts_t {
*/ */
void (*set_aik)(pts_t *this, certificate_t *aik); 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 * Check whether path is valid file/directory on filesystem
* *
+73 -23
View File
@@ -69,23 +69,6 @@ METHOD(pts_database_t, create_file_meta_enumerator, enumerator_t*,
return e; 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*, METHOD(pts_database_t, create_file_hash_enumerator, enumerator_t*,
private_pts_database_t *this, char *product, pts_meas_algorithms_t algo, private_pts_database_t *this, char *product, pts_meas_algorithms_t algo,
int id, bool is_dir) int id, bool is_dir)
@@ -114,9 +97,25 @@ METHOD(pts_database_t, create_file_hash_enumerator, enumerator_t*,
return e; 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, METHOD(pts_database_t, check_comp_measurement, status_t,
private_pts_database_t *this, chunk_t measurement, 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) int seq_no, int pcr, pts_meas_algorithms_t algo)
{ {
enumerator_t *e; enumerator_t *e;
@@ -125,14 +124,14 @@ METHOD(pts_database_t, check_comp_measurement, status_t,
e = this->db->query(this->db, e = this->db->query(this->db,
"SELECT ch.hash FROM component_hashes AS ch " "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 " "JOIN components AS c ON ch.component = c.id "
"WHERE c.vendor_id = ? AND c.name = ? AND c.qualifier = ? " "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_vendor_id(comp_name),
DB_INT, comp_name->get_name(comp_name), DB_INT, comp_name->get_name(comp_name),
DB_INT, comp_name->get_qualifier(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); DB_BLOB);
if (!e) if (!e)
{ {
@@ -144,8 +143,6 @@ METHOD(pts_database_t, check_comp_measurement, status_t,
{ {
if (chunk_equals(hash, measurement)) if (chunk_equals(hash, measurement))
{ {
DBG2(DBG_PTS, "PCR %2d matching component measurement #%d "
"found in database", pcr, seq_no);
status = SUCCESS; status = SUCCESS;
break; break;
} }
@@ -170,6 +167,58 @@ METHOD(pts_database_t, check_comp_measurement, status_t,
return status; 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, METHOD(pts_database_t, destroy, void,
private_pts_database_t *this) 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_comp_evid_enumerator = _create_comp_evid_enumerator,
.create_file_hash_enumerator = _create_file_hash_enumerator, .create_file_hash_enumerator = _create_file_hash_enumerator,
.check_comp_measurement = _check_comp_measurement, .check_comp_measurement = _check_comp_measurement,
.get_comp_measurement_count = _get_comp_measurement_count,
.destroy = _destroy, .destroy = _destroy,
}, },
.db = lib->db->create(lib->db, uri), .db = lib->db->create(lib->db, uri),
+23 -11
View File
@@ -51,15 +51,6 @@ struct pts_database_t {
enumerator_t* (*create_file_meta_enumerator)(pts_database_t *this, enumerator_t* (*create_file_meta_enumerator)(pts_database_t *this,
char *product); 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 * Get stored measurement hash for single file or directory entries
* *
@@ -73,21 +64,42 @@ struct pts_database_t {
char *product, pts_meas_algorithms_t algo, char *product, pts_meas_algorithms_t algo,
int id, bool is_dir); 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 * Check a functional component measurement against value stored in database
* *
* @param measurement measurement hash * @param measurement measurement hash
* @param comp_name Component Functional Name * @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 seq_no Measurement sequence number
* @param prc Number of the PCR the measurement was extended into * @param prc Number of the PCR the measurement was extended into
* @param algo Hash algorithm used for measurement * @param algo Hash algorithm used for measurement
* @return return code * @return return code
*/ */
status_t (*check_comp_measurement)(pts_database_t *this, chunk_t measurement, 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); 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. * Destroys a pts_database_t object.
*/ */