imv-attestation: Fixed file hash measurements
authorAndreas Steffen <andreas.steffen@strongswan.org>
Fri, 1 Sep 2017 00:53:28 +0000 (02:53 +0200)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Fri, 1 Sep 2017 08:51:15 +0000 (10:51 +0200)
The introduction of file versions broke file hash measurements.
This has been fixed by using a generic product versions having an
empty package name.

src/libimcv/plugins/imv_attestation/imv_attestation_process.c
src/libimcv/pts/pts_database.c
src/libimcv/pts/pts_database.h
src/libimcv/pts/pts_file_meas.c
testing/tests/tnc/tnccs-20-os-pts/evaltest.dat
testing/tests/tnc/tnccs-20-os-pts/hosts/carol/etc/strongswan.conf
testing/tests/tnc/tnccs-20-os-pts/hosts/dave/etc/strongswan.conf
testing/tests/tnc/tnccs-20-os-pts/hosts/moon/etc/strongswan.conf
testing/tests/tnc/tnccs-20-os-pts/pretest.dat

index b1ee16b..60a9edc 100644 (file)
@@ -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);
index 4a47b06..8b99d68 100644 (file)
@@ -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,
index a6c9fb3..3a5ff59 100644 (file)
@@ -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
index 92f513a..2f8935a 100644 (file)
@@ -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",
index 8056a90..5dbfa82 100644 (file)
@@ -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
index d3941d8..533cfd1 100644 (file)
@@ -14,7 +14,7 @@ charon {
       default = 0
     }
     daemon {
-      tnc = 3
+      tnc = 
       imc = 3
       pts = 3
     }
index 134cd99..8443744 100644 (file)
@@ -15,7 +15,7 @@ charon {
       default = 0
     }
     daemon {
-      tnc = 3
+      tnc = 
       imc = 3
       pts = 3
     }
index e58bab6..5451416 100644 (file)
@@ -14,7 +14,7 @@ charon {
       default = 0
     }
     daemon {
-      tnc = 3
+      tnc = 
       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
     }
   }
 }
index 03e5f22..5445575 100644 (file)
@@ -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