From: Andreas Steffen Date: Fri, 1 Sep 2017 00:53:28 +0000 (+0200) Subject: imv-attestation: Fixed file hash measurements X-Git-Tag: 5.6.1dr1~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=076aac70693d7e49c1357cee406ad21ca98000bc;p=thirdparty%2Fstrongswan.git imv-attestation: Fixed file hash measurements The introduction of file versions broke file hash measurements. This has been fixed by using a generic product versions having an empty package name. --- diff --git a/src/libimcv/plugins/imv_attestation/imv_attestation_process.c b/src/libimcv/plugins/imv_attestation/imv_attestation_process.c index b1ee16bf80..60a9edc0f2 100644 --- a/src/libimcv/plugins/imv_attestation/imv_attestation_process.c +++ b/src/libimcv/plugins/imv_attestation/imv_attestation_process.c @@ -318,15 +318,24 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg, enumerator_t *e; char *filename; chunk_t measurement; + int vid; + + if (!pts_db->get_product_version(pts_db, + pts->get_platform_id(pts), &vid)) + { + eval = TNC_IMV_EVALUATION_RESULT_ERROR; + break; + } e = measurements->create_enumerator(measurements); while (e->enumerate(e, &filename, &measurement)) { - if (pts_db->add_file_measurement(pts_db, - pts->get_platform_id(pts), algo, measurement, - filename, is_dir, arg_int) != SUCCESS) + if (!pts_db->add_file_measurement(pts_db, vid, algo, + measurement, filename, is_dir, arg_int)) { eval = TNC_IMV_EVALUATION_RESULT_ERROR; + e->destroy(e); + break; } } e->destroy(e); diff --git a/src/libimcv/pts/pts_database.c b/src/libimcv/pts/pts_database.c index 4a47b06f09..8b99d689b3 100644 --- a/src/libimcv/pts/pts_database.c +++ b/src/libimcv/pts/pts_database.c @@ -121,15 +121,69 @@ METHOD(pts_database_t, create_file_hash_enumerator, enumerator_t*, return e; } -METHOD(pts_database_t, add_file_measurement, status_t, - private_pts_database_t *this, int pid, pts_meas_algorithms_t algo, + +METHOD(pts_database_t, get_product_version, bool, + private_pts_database_t *this, int pid, int *vid) +{ + enumerator_t *e; + int pkg_id; + + /* does empty package name already exist? */ + e = this->db->query(this->db, + "SELECT id FROM packages WHERE name = ''", DB_INT); + if (!e) + { + return FALSE; + } + if (!e->enumerate(e, &pkg_id)) + { + /* create generic product version entry */ + if (this->db->execute(this->db, &pkg_id, + "INSERT INTO packages (name) VALUES ('')") != 1) + { + DBG1(DBG_PTS, "could not insert package into database"); + e->destroy(e); + return FALSE; + } + } + e->destroy(e); + + /* does generic product version already exist? */ + e = this->db->query(this->db, + "SELECT id FROM versions WHERE product = ? AND package = ?", + DB_INT, pid, DB_INT, pkg_id); + if (!e) + { + return FALSE; + } + if (!e->enumerate(e, vid)) + { + /* create generic product version entry */ + if (this->db->execute(this->db, vid, + "INSERT INTO versions (product, package) VALUES (?, ?)", + DB_INT, pid, DB_INT, pkg_id) != 1) + { + DBG1(DBG_PTS, "could not insert version into database"); + e->destroy(e); + return FALSE; + } + } + e->destroy(e); + + return TRUE; +} + +METHOD(pts_database_t, add_file_measurement, bool, + private_pts_database_t *this, int vid, pts_meas_algorithms_t algo, chunk_t measurement, char *filename, bool is_dir, int id) { enumerator_t *e; char *name; - chunk_t hash_value; + uint8_t hash_buf[HASH_SIZE_SHA512]; + uint8_t hex_meas_buf[2*HASH_SIZE_SHA512+1], *hex_hash_buf; + chunk_t hash, hex_hash, hex_meas; int hash_id, fid; - status_t status = SUCCESS; + bool success = TRUE; if (is_dir) { @@ -139,7 +193,7 @@ METHOD(pts_database_t, add_file_measurement, status_t, DB_TEXT, filename, DB_INT, id, DB_INT); if (!e) { - return FAILED; + return FALSE; } if (!e->enumerate(e, &fid)) { @@ -149,7 +203,7 @@ METHOD(pts_database_t, add_file_measurement, status_t, DB_TEXT, filename, DB_INT, id) != 1) { DBG1(DBG_PTS, "could not insert filename into database"); - status = FAILED; + success = FALSE; } } e->destroy(e); @@ -163,58 +217,63 @@ METHOD(pts_database_t, add_file_measurement, status_t, "SELECT name FROM files WHERE id = ?", DB_INT, fid, DB_TEXT); if (!e) { - return FAILED; + return FALSE; } if (!e->enumerate(e, &name) || !streq(name, filename)) { DBG1(DBG_PTS, "filename of reference measurement does not match"); - status = FAILED; + success = FALSE; } e->destroy(e); } - if (status != SUCCESS) + if (!success) { - return status; + return FALSE; } /* does hash measurement value already exist? */ e = this->db->query(this->db, - "SELECT fh.id, fh.hash FROM file_hashes AS fh " - "JOIN versions AS v ON v.id = fh.version " - "WHERE v.product = ? AND fh.algo = ? AND fh.file = ?", - DB_INT, pid, DB_INT, algo, DB_INT, fid, DB_INT, DB_BLOB); + "SELECT id, hash FROM file_hashes " + "WHERE algo = ? AND file = ? AND version = ?", + DB_INT, algo, DB_INT, fid, DB_INT, vid, DB_INT, DB_TEXT); if (!e) { - return FAILED; + return FALSE; } - if (e->enumerate(e, &hash_id, &hash_value)) + if (e->enumerate(e, &hash_id, &hex_hash_buf)) { - if (!chunk_equals_const(measurement, hash_value)) + hex_hash = chunk_from_str(hex_hash_buf); + hash = chunk_from_hex(hex_hash, hash_buf); + + if (!chunk_equals(measurement, hash)) { /* update hash measurement value */ if (this->db->execute(this->db, &hash_id, "UPDATE file_hashes SET hash = ? WHERE id = ?", DB_BLOB, measurement, DB_INT, hash_id) != 1) { - status = FAILED; + success = FALSE; } } } else { + hex_meas = chunk_to_hex(measurement, hex_meas_buf, FALSE); + hex_meas_buf[hex_meas.len] = '\0'; + /* insert hash measurement value */ if (this->db->execute(this->db, &hash_id, - "INSERT INTO file_hashes (file, product, algo, hash) " - "VALUES (?, ?, ?, ?)", DB_INT, fid, DB_INT, pid, - DB_INT, algo, DB_BLOB, measurement) != 1) + "INSERT INTO file_hashes (file, version, algo, hash) " + "VALUES (?, ?, ?, ?)", DB_INT, fid, DB_INT, vid, + DB_INT, algo, DB_TEXT, hex_meas_buf) != 1) { - status = FAILED; + success = FALSE; } } e->destroy(e); - return status; + return success; } METHOD(pts_database_t, create_file_meas_enumerator, enumerator_t*, @@ -296,7 +355,7 @@ METHOD(pts_database_t, check_comp_measurement, status_t, while (e->enumerate(e, &hash)) { - if (chunk_equals_const(hash, measurement)) + if (chunk_equals(hash, measurement)) { status = SUCCESS; break; @@ -424,6 +483,7 @@ pts_database_t *pts_database_create(imv_database_t *imv_db) .public = { .get_pathname = _get_pathname, .create_file_hash_enumerator = _create_file_hash_enumerator, + .get_product_version = _get_product_version, .add_file_measurement = _add_file_measurement, .create_file_meas_enumerator = _create_file_meas_enumerator, .check_comp_measurement = _check_comp_measurement, diff --git a/src/libimcv/pts/pts_database.h b/src/libimcv/pts/pts_database.h index a6c9fb3b6a..3a5ff59920 100644 --- a/src/libimcv/pts/pts_database.h +++ b/src/libimcv/pts/pts_database.h @@ -60,18 +60,27 @@ struct pts_database_t { /** * Add PTS file measurement reference value * - * @param pid Primary key of software product in database + * @param pid Primary key of platform product + * @param vid Primary key of generic product version + * @return TRUE if successful + */ + bool (*get_product_version)(pts_database_t *this, int pid, int *vid); + + /** + * Add PTS file measurement reference value + * + * @param vid Primary key of generic product version * @param algo File measurement hash algorithm used * @param measurement File measurement hash * @param filename Optional name of the file to be checked * @param is_dir TRUE if part of directory measurement * @param id Primary key into direcories/files table - * @return Status + * @return TRUE if successful */ - status_t (*add_file_measurement)(pts_database_t *this, int pid, - pts_meas_algorithms_t algo, - chunk_t measurement, char *filename, - bool is_dir, int id); + bool (*add_file_measurement)(pts_database_t *this, int vid, + pts_meas_algorithms_t algo, + chunk_t measurement, char *filename, + bool is_dir, int id); /** * Get PTS measurement[s] for a given filename stored in database diff --git a/src/libimcv/pts/pts_file_meas.c b/src/libimcv/pts/pts_file_meas.c index 92f513a2de..2f8935a878 100644 --- a/src/libimcv/pts/pts_file_meas.c +++ b/src/libimcv/pts/pts_file_meas.c @@ -140,7 +140,7 @@ METHOD(pts_file_meas_t, check, bool, { while (e->enumerate(e, &hash)) { - if (chunk_equals_const(entry->measurement, hash)) + if (chunk_equals(entry->measurement, hash)) { status = SUCCESS; break; @@ -193,12 +193,13 @@ METHOD(pts_file_meas_t, verify, bool, { int fid, fid_last = 0; char *filename; - chunk_t measurement; + uint8_t measurement_buf[HASH_SIZE_SHA512], *hex_meas_buf; + chunk_t measurement, hex_meas; entry_t *entry; enumerator_t *enumerator = NULL; bool found = FALSE, match = FALSE, success = TRUE; - while (e_hash->enumerate(e_hash, &fid, &filename, &measurement)) + while (e_hash->enumerate(e_hash, &fid, &filename, &hex_meas_buf)) { if (fid != fid_last) { @@ -241,7 +242,10 @@ METHOD(pts_file_meas_t, verify, bool, if (found && !match) { - if (chunk_equals_const(measurement, entry->measurement)) + hex_meas = chunk_from_str(hex_meas_buf); + measurement = chunk_from_hex(hex_meas, measurement_buf); + + if (chunk_equals(measurement, entry->measurement)) { match = TRUE; DBG2(DBG_PTS, " %#B for '%s' is ok", diff --git a/testing/tests/tnc/tnccs-20-os-pts/evaltest.dat b/testing/tests/tnc/tnccs-20-os-pts/evaltest.dat index 8056a90e99..5dbfa82471 100644 --- a/testing/tests/tnc/tnccs-20-os-pts/evaltest.dat +++ b/testing/tests/tnc/tnccs-20-os-pts/evaltest.dat @@ -1,19 +1,19 @@ -carol::cat /var/log/daemon.log::PB-TNC access recommendation is 'Access Allowed'::YES -carol::cat /var/log/daemon.log::EAP method EAP_TTLS succeeded, MSK established::YES -carol::cat /var/log/daemon.log::authentication of 'moon.strongswan.org' with EAP successful::YES dave:: cat /var/log/daemon.log::PB-TNC access recommendation is 'Quarantined'::YES dave:: cat /var/log/daemon.log::EAP method EAP_TTLS succeeded, MSK established::YES dave:: cat /var/log/daemon.log::authentication of 'moon.strongswan.org' with EAP successful::YES +carol::cat /var/log/daemon.log::PB-TNC access recommendation is 'Access Allowed'::YES +carol::cat /var/log/daemon.log::EAP method EAP_TTLS succeeded, MSK established::YES +carol::cat /var/log/daemon.log::authentication of 'moon.strongswan.org' with EAP successful::YES moon:: ipsec attest --session 2> /dev/null::Debian.*x86_64.*carol@strongswan.org - allow::YES moon:: cat /var/log/daemon.log::added group membership 'allow'::YES moon:: cat /var/log/daemon.log::authentication of 'carol@strongswan.org' with EAP successful::YES moon:: ipsec attest --session 2> /dev/null::Debian.*x86_64.*dave@strongswan.org - isolate::YES moon:: cat /var/log/daemon.log::added group membership 'isolate'::YES moon:: cat /var/log/daemon.log::authentication of 'dave@strongswan.org' with EAP successful::YES -carol::swanctl --list-sas --raw 2> /dev/null::home.*version=2 state=ESTABLISHED local-host=192.168.0.100 local-port=4500 local-id=carol@strongswan.org remote-host=192.168.0.1 remote-port=4500 remote-id=moon.strongswan.org initiator=yes.*encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128 prf-alg=PRF_HMAC_SHA2_256 dh-group=MODP_3072.*child-sas.*home.*state=INSTALLED mode=TUNNEL protocol=ESP.*encr-alg=AES_GCM_16 encr-keysize=128.*local-ts=\[192.168.0.100/32] remote-ts=\[10.1.0.0/28]::YES dave:: swanctl --list-sas --raw 2> /dev/null::home.*version=2 state=ESTABLISHED local-host=192.168.0.200 local-port=4500 local-id=dave@strongswan.org remote-host=192.168.0.1 remote-port=4500 remote-id=moon.strongswan.org initiator=yes.*encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128 prf-alg=PRF_HMAC_SHA2_256 dh-group=MODP_3072.*child-sas.*home.*state=INSTALLED mode=TUNNEL protocol=ESP.*encr-alg=AES_GCM_16 encr-keysize=128.*local-ts=\[192.168.0.200/32] remote-ts=\[10.1.0.16/28]::YES -moon:: swanctl --list-sas --ike-id 1 --raw 2> /dev/null::rw-allow.*version=2 state=ESTABLISHED local-host=192.168.0.1 local-port=4500 local-id=moon.strongswan.org remote-host=192.168.0.100 remote-port=4500 remote-id=carol@strongswan.org.*encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128 prf-alg=PRF_HMAC_SHA2_256 dh-group=MODP_3072.*child-sas.*rw-allow.*state=INSTALLED mode=TUNNEL protocol=ESP.*encr-alg=AES_GCM_16 encr-keysize=128.*local-ts=\[10.1.0.0/28] remote-ts=\[192.168.0.100/32]::YES -moon:: swanctl --list-sas --ike-id 2 --raw 2> /dev/null::rw-isolate.*version=2 state=ESTABLISHED local-host=192.168.0.1 local-port=4500 local-id=moon.strongswan.org remote-host=192.168.0.200 remote-port=4500 remote-id=dave@strongswan.org.*encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128 prf-alg=PRF_HMAC_SHA2_256 dh-group=MODP_3072.*child-sas.*rw-isolate.*state=INSTALLED mode=TUNNEL protocol=ESP.*encr-alg=AES_GCM_16 encr-keysize=128.*local-ts=\[10.1.0.16/28] remote-ts=\[192.168.0.200/32]::YES +carol::swanctl --list-sas --raw 2> /dev/null::home.*version=2 state=ESTABLISHED local-host=192.168.0.100 local-port=4500 local-id=carol@strongswan.org remote-host=192.168.0.1 remote-port=4500 remote-id=moon.strongswan.org initiator=yes.*encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128 prf-alg=PRF_HMAC_SHA2_256 dh-group=MODP_3072.*child-sas.*home.*state=INSTALLED mode=TUNNEL protocol=ESP.*encr-alg=AES_GCM_16 encr-keysize=128.*local-ts=\[192.168.0.100/32] remote-ts=\[10.1.0.0/28]::YES +moon:: swanctl --list-sas --ike-id 1 --raw 2> /dev/null::rw-isolate.*version=2 state=ESTABLISHED local-host=192.168.0.1 local-port=4500 local-id=moon.strongswan.org remote-host=192.168.0.200 remote-port=4500 remote-id=dave@strongswan.org.*encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128 prf-alg=PRF_HMAC_SHA2_256 dh-group=MODP_3072.*child-sas.*rw-isolate.*state=INSTALLED mode=TUNNEL protocol=ESP.*encr-alg=AES_GCM_16 encr-keysize=128.*local-ts=\[10.1.0.16/28] remote-ts=\[192.168.0.200/32]::YES +moon:: swanctl --list-sas --ike-id 2 --raw 2> /dev/null::rw-allow.*version=2 state=ESTABLISHED local-host=192.168.0.1 local-port=4500 local-id=moon.strongswan.org remote-host=192.168.0.100 remote-port=4500 remote-id=carol@strongswan.org.*encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128 prf-alg=PRF_HMAC_SHA2_256 dh-group=MODP_3072.*child-sas.*rw-allow.*state=INSTALLED mode=TUNNEL protocol=ESP.*encr-alg=AES_GCM_16 encr-keysize=128.*local-ts=\[10.1.0.0/28] remote-ts=\[192.168.0.100/32]::YES carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_.eq=1::YES carol::ping -c 1 -W 1 PH_IP_VENUS::64 bytes from PH_IP_VENUS: icmp_.eq=1::NO dave:: ping -c 1 PH_IP_VENUS::64 bytes from PH_IP_VENUS: icmp_.eq=1::YES diff --git a/testing/tests/tnc/tnccs-20-os-pts/hosts/carol/etc/strongswan.conf b/testing/tests/tnc/tnccs-20-os-pts/hosts/carol/etc/strongswan.conf index d3941d8117..533cfd1bd2 100644 --- a/testing/tests/tnc/tnccs-20-os-pts/hosts/carol/etc/strongswan.conf +++ b/testing/tests/tnc/tnccs-20-os-pts/hosts/carol/etc/strongswan.conf @@ -14,7 +14,7 @@ charon { default = 0 } daemon { - tnc = 3 + tnc = 2 imc = 3 pts = 3 } diff --git a/testing/tests/tnc/tnccs-20-os-pts/hosts/dave/etc/strongswan.conf b/testing/tests/tnc/tnccs-20-os-pts/hosts/dave/etc/strongswan.conf index 134cd991c6..8443744337 100644 --- a/testing/tests/tnc/tnccs-20-os-pts/hosts/dave/etc/strongswan.conf +++ b/testing/tests/tnc/tnccs-20-os-pts/hosts/dave/etc/strongswan.conf @@ -15,7 +15,7 @@ charon { default = 0 } daemon { - tnc = 3 + tnc = 2 imc = 3 pts = 3 } diff --git a/testing/tests/tnc/tnccs-20-os-pts/hosts/moon/etc/strongswan.conf b/testing/tests/tnc/tnccs-20-os-pts/hosts/moon/etc/strongswan.conf index e58bab6114..54514160db 100644 --- a/testing/tests/tnc/tnccs-20-os-pts/hosts/moon/etc/strongswan.conf +++ b/testing/tests/tnc/tnccs-20-os-pts/hosts/moon/etc/strongswan.conf @@ -14,7 +14,7 @@ charon { default = 0 } daemon { - tnc = 3 + tnc = 2 imv = 3 pts = 3 } @@ -37,7 +37,7 @@ libimcv { policy_script = /usr/local/libexec/ipsec/imv_policy_manager plugins { imv-attestation { - hash_algorithm = sha1 + hash_algorithm = sha256 } } } diff --git a/testing/tests/tnc/tnccs-20-os-pts/pretest.dat b/testing/tests/tnc/tnccs-20-os-pts/pretest.dat index 03e5f22afc..544557566d 100644 --- a/testing/tests/tnc/tnccs-20-os-pts/pretest.dat +++ b/testing/tests/tnc/tnccs-20-os-pts/pretest.dat @@ -17,9 +17,9 @@ carol::service charon start dave::service charon start moon::expect-connection rw-allow moon::expect-connection rw-isolate -carol::expect-connection home -carol::swanctl --initiate --child home 2> /dev/null dave::expect-connection home dave::swanctl --initiate --child home 2> /dev/null +carol::expect-connection home +carol::swanctl --initiate --child home 2> /dev/null moon::ipsec attest --sessions moon::ipsec attest --devices