Annotation of embedaddon/strongswan/src/libimcv/pts/pts_database.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2011-2012 Sansar Choinyambuu
! 3: * Copyright (C) 2012-2017 Andreas Steffen
! 4: * HSR Hochschule fuer Technik Rapperswil
! 5: *
! 6: * This program is free software; you can redistribute it and/or modify it
! 7: * under the terms of the GNU General Public License as published by the
! 8: * Free Software Foundation; either version 2 of the License, or (at your
! 9: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 10: *
! 11: * This program is distributed in the hope that it will be useful, but
! 12: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 13: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 14: * for more details.
! 15: */
! 16:
! 17: #define _GNU_SOURCE
! 18: #include <stdio.h>
! 19: #include <libgen.h>
! 20:
! 21: #include "pts_database.h"
! 22:
! 23: #include <utils/debug.h>
! 24: #include <crypto/hashers/hasher.h>
! 25:
! 26:
! 27: typedef struct private_pts_database_t private_pts_database_t;
! 28:
! 29: /**
! 30: * Private data of a pts_database_t object.
! 31: *
! 32: */
! 33: struct private_pts_database_t {
! 34:
! 35: /**
! 36: * Public pts_database_t interface.
! 37: */
! 38: pts_database_t public;
! 39:
! 40: /**
! 41: * database instance
! 42: */
! 43: database_t *db;
! 44:
! 45: };
! 46:
! 47: METHOD(pts_database_t, get_pathname, char*,
! 48: private_pts_database_t *this, bool is_dir, int id)
! 49: {
! 50: enumerator_t *e;
! 51: char *path, *name, *sep, *pathname = NULL;
! 52:
! 53: if (is_dir)
! 54: {
! 55: e = this->db->query(this->db,
! 56: "SELECT path FROM directories WHERE id = ?",
! 57: DB_INT, id, DB_TEXT);
! 58: if (!e || !e->enumerate(e, &path))
! 59: {
! 60: pathname = NULL;
! 61: }
! 62: else
! 63: {
! 64: pathname = strdup(path);
! 65: }
! 66: }
! 67: else
! 68: {
! 69: e = this->db->query(this->db,
! 70: "SELECT d.path, f.name FROM files AS f "
! 71: "JOIN directories AS d ON d.id = f.dir WHERE f.id = ?",
! 72: DB_INT, id, DB_TEXT, DB_TEXT);
! 73: if (e && e->enumerate(e, &path, &name))
! 74: {
! 75: if (path[0] == '/')
! 76: { /* Unix style absolute path */
! 77: sep = "/";
! 78: }
! 79: else
! 80: { /* Windows absolute path */
! 81: sep = "\\";
! 82: }
! 83: if (asprintf(&pathname, "%s%s%s",
! 84: path, streq(path, "/") ? "" : sep, name) == -1)
! 85: {
! 86: pathname = NULL;
! 87: }
! 88: }
! 89: }
! 90: DESTROY_IF(e);
! 91:
! 92: return pathname;
! 93: }
! 94:
! 95: METHOD(pts_database_t, create_file_hash_enumerator, enumerator_t*,
! 96: private_pts_database_t *this, int pid, pts_meas_algorithms_t algo,
! 97: bool is_dir, int id)
! 98: {
! 99: enumerator_t *e;
! 100:
! 101: if (is_dir)
! 102: {
! 103: e = this->db->query(this->db,
! 104: "SELECT f.id, f.name, fh.hash FROM file_hashes AS fh "
! 105: "JOIN files AS f ON f.id = fh.file "
! 106: "JOIN directories as d ON d.id = f.dir "
! 107: "JOIN versions as v ON v.id = fh.version "
! 108: "WHERE v.product = ? AND fh.algo = ? AND d.id = ? "
! 109: "ORDER BY f.name",
! 110: DB_INT, pid, DB_INT, algo, DB_INT, id, DB_INT, DB_TEXT, DB_TEXT);
! 111: }
! 112: else
! 113: {
! 114: e = this->db->query(this->db,
! 115: "SELECT f.id, f.name, fh.hash FROM file_hashes AS fh "
! 116: "JOIN files AS f ON f.id = fh.file "
! 117: "JOIN versions AS v ON v.id = fh.version "
! 118: "WHERE v.product = ? AND fh.algo = ? AND fh.file = ?",
! 119: DB_INT, pid, DB_INT, algo, DB_INT, id, DB_INT, DB_TEXT, DB_TEXT);
! 120: }
! 121: return e;
! 122: }
! 123:
! 124:
! 125: METHOD(pts_database_t, get_product_version, bool,
! 126: private_pts_database_t *this, int pid, int *vid)
! 127: {
! 128: enumerator_t *e;
! 129: int pkg_id;
! 130:
! 131: /* does empty package name already exist? */
! 132: e = this->db->query(this->db,
! 133: "SELECT id FROM packages WHERE name = ''", DB_INT);
! 134: if (!e)
! 135: {
! 136: return FALSE;
! 137: }
! 138: if (!e->enumerate(e, &pkg_id))
! 139: {
! 140: /* create generic product version entry */
! 141: if (this->db->execute(this->db, &pkg_id,
! 142: "INSERT INTO packages (name) VALUES ('')") != 1)
! 143: {
! 144: DBG1(DBG_PTS, "could not insert package into database");
! 145: e->destroy(e);
! 146: return FALSE;
! 147: }
! 148: }
! 149: e->destroy(e);
! 150:
! 151: /* does generic product version already exist? */
! 152: e = this->db->query(this->db,
! 153: "SELECT id FROM versions WHERE product = ? AND package = ?",
! 154: DB_INT, pid, DB_INT, pkg_id);
! 155: if (!e)
! 156: {
! 157: return FALSE;
! 158: }
! 159: if (!e->enumerate(e, vid))
! 160: {
! 161: /* create generic product version entry */
! 162: if (this->db->execute(this->db, vid,
! 163: "INSERT INTO versions (product, package) VALUES (?, ?)",
! 164: DB_INT, pid, DB_INT, pkg_id) != 1)
! 165: {
! 166: DBG1(DBG_PTS, "could not insert version into database");
! 167: e->destroy(e);
! 168: return FALSE;
! 169: }
! 170: }
! 171: e->destroy(e);
! 172:
! 173: return TRUE;
! 174: }
! 175:
! 176: METHOD(pts_database_t, add_file_measurement, bool,
! 177: private_pts_database_t *this, int vid, pts_meas_algorithms_t algo,
! 178: chunk_t measurement, char *filename, bool is_dir, int id)
! 179: {
! 180: enumerator_t *e;
! 181: char *name;
! 182: uint8_t hash_buf[HASH_SIZE_SHA512];
! 183: uint8_t hex_meas_buf[2*HASH_SIZE_SHA512+1], *hex_hash_buf;
! 184: chunk_t hash, hex_hash, hex_meas;
! 185: int hash_id, fid;
! 186: bool success = TRUE;
! 187:
! 188: if (is_dir)
! 189: {
! 190: /* does filename entry already exist? */
! 191: e = this->db->query(this->db,
! 192: "SELECT id FROM files WHERE name = ? AND dir = ?",
! 193: DB_TEXT, filename, DB_INT, id, DB_INT);
! 194: if (!e)
! 195: {
! 196: return FALSE;
! 197: }
! 198: if (!e->enumerate(e, &fid))
! 199: {
! 200: /* create filename entry */
! 201: if (this->db->execute(this->db, &fid,
! 202: "INSERT INTO files (name, dir) VALUES (?, ?)",
! 203: DB_TEXT, filename, DB_INT, id) != 1)
! 204: {
! 205: DBG1(DBG_PTS, "could not insert filename into database");
! 206: success = FALSE;
! 207: }
! 208: }
! 209: e->destroy(e);
! 210: }
! 211: else
! 212: {
! 213: fid = id;
! 214:
! 215: /* verify filename */
! 216: e = this->db->query(this->db,
! 217: "SELECT name FROM files WHERE id = ?", DB_INT, fid, DB_TEXT);
! 218: if (!e)
! 219: {
! 220: return FALSE;
! 221: }
! 222: if (!e->enumerate(e, &name) || !streq(name, filename))
! 223: {
! 224: DBG1(DBG_PTS, "filename of reference measurement does not match");
! 225: success = FALSE;
! 226: }
! 227: e->destroy(e);
! 228: }
! 229:
! 230: if (!success)
! 231: {
! 232: return FALSE;
! 233: }
! 234:
! 235: /* does hash measurement value already exist? */
! 236: e = this->db->query(this->db,
! 237: "SELECT id, hash FROM file_hashes "
! 238: "WHERE algo = ? AND file = ? AND version = ?",
! 239: DB_INT, algo, DB_INT, fid, DB_INT, vid, DB_INT, DB_TEXT);
! 240: if (!e)
! 241: {
! 242: return FALSE;
! 243: }
! 244: if (e->enumerate(e, &hash_id, &hex_hash_buf))
! 245: {
! 246: hex_hash = chunk_from_str(hex_hash_buf);
! 247: hash = chunk_from_hex(hex_hash, hash_buf);
! 248:
! 249: if (!chunk_equals(measurement, hash))
! 250: {
! 251: /* update hash measurement value */
! 252: if (this->db->execute(this->db, &hash_id,
! 253: "UPDATE file_hashes SET hash = ? WHERE id = ?",
! 254: DB_BLOB, measurement, DB_INT, hash_id) != 1)
! 255: {
! 256: success = FALSE;
! 257: }
! 258: }
! 259: }
! 260: else
! 261: {
! 262: hex_meas = chunk_to_hex(measurement, hex_meas_buf, FALSE);
! 263: hex_meas_buf[hex_meas.len] = '\0';
! 264:
! 265: /* insert hash measurement value */
! 266: if (this->db->execute(this->db, &hash_id,
! 267: "INSERT INTO file_hashes (file, version, algo, hash) "
! 268: "VALUES (?, ?, ?, ?)", DB_INT, fid, DB_INT, vid,
! 269: DB_INT, algo, DB_TEXT, hex_meas_buf) != 1)
! 270: {
! 271: success = FALSE;
! 272: }
! 273: }
! 274: e->destroy(e);
! 275:
! 276: return success;
! 277: }
! 278:
! 279: METHOD(pts_database_t, create_file_meas_enumerator, enumerator_t*,
! 280: private_pts_database_t *this, int pid, pts_meas_algorithms_t algo,
! 281: char *filename)
! 282: {
! 283: enumerator_t *e;
! 284: char *dir, *file;
! 285:
! 286: if (strlen(filename) < 1)
! 287: {
! 288: return NULL;
! 289: }
! 290:
! 291: /* separate filename into directory and basename components */
! 292: dir = path_dirname(filename);
! 293: file = path_basename(filename);
! 294:
! 295: if (*dir == '.')
! 296: { /* relative pathname */
! 297: e = this->db->query(this->db,
! 298: "SELECT fh.hash FROM file_hashes AS fh "
! 299: "JOIN files AS f ON f.id = fh.file "
! 300: "JOIN versions AS v ON v.id = fh.version "
! 301: "WHERE v.product = ? AND f.name = ? AND fh.algo = ? "
! 302: "ORDER BY v.time DESC",
! 303: DB_INT, pid, DB_TEXT, file, DB_INT, algo, DB_TEXT);
! 304: }
! 305: else
! 306: { /* absolute pathname */
! 307: int did;
! 308:
! 309: /* find directory entry first */
! 310: e = this->db->query(this->db,
! 311: "SELECT id FROM directories WHERE path = ?",
! 312: DB_TEXT, dir, DB_INT);
! 313:
! 314: if (!e || !e->enumerate(e, &did))
! 315: {
! 316: goto err;
! 317: }
! 318: e->destroy(e);
! 319:
! 320: e = this->db->query(this->db,
! 321: "SELECT fh.hash FROM file_hashes AS fh "
! 322: "JOIN files AS f ON f.id = fh.file "
! 323: "JOIN versions AS v ON v.id = fh.version "
! 324: "WHERE v.product = ? AND f.dir = ? AND f.name = ? AND fh.algo = ? "
! 325: "ORDER BY v.time DESC",
! 326: DB_INT, pid, DB_INT, did, DB_TEXT, file, DB_INT, algo, DB_TEXT);
! 327: }
! 328:
! 329: err:
! 330: free(file);
! 331: free(dir);
! 332:
! 333: return e;
! 334: }
! 335:
! 336: METHOD(pts_database_t, check_comp_measurement, status_t,
! 337: private_pts_database_t *this, chunk_t measurement, int cid, int aik_id,
! 338: int seq_no, int pcr, pts_meas_algorithms_t algo)
! 339: {
! 340: enumerator_t *e;
! 341: chunk_t hash;
! 342: status_t status = NOT_FOUND;
! 343:
! 344: e = this->db->query(this->db,
! 345: "SELECT hash FROM component_hashes "
! 346: "WHERE component = ? AND key = ? "
! 347: "AND seq_no = ? AND pcr = ? AND algo = ? ",
! 348: DB_INT, cid, DB_INT, aik_id, DB_INT, seq_no,
! 349: DB_INT, pcr, DB_INT, algo, DB_BLOB);
! 350: if (!e)
! 351: {
! 352: DBG1(DBG_PTS, "no database query enumerator returned");
! 353: return FAILED;
! 354: }
! 355:
! 356: while (e->enumerate(e, &hash))
! 357: {
! 358: if (chunk_equals(hash, measurement))
! 359: {
! 360: status = SUCCESS;
! 361: break;
! 362: }
! 363: else
! 364: {
! 365: DBG1(DBG_PTS, "PCR %2d no matching component measurement #%d "
! 366: "found in database", pcr, seq_no);
! 367: DBG1(DBG_PTS, " expected: %#B", &hash);
! 368: DBG1(DBG_PTS, " received: %#B", &measurement);
! 369: status = VERIFY_ERROR;
! 370: break;
! 371: }
! 372: }
! 373: e->destroy(e);
! 374:
! 375: if (status == NOT_FOUND)
! 376: {
! 377: DBG1(DBG_PTS, "PCR %2d no measurement #%d "
! 378: "found in database", pcr, seq_no);
! 379: }
! 380:
! 381: return status;
! 382: }
! 383:
! 384: METHOD(pts_database_t, insert_comp_measurement, status_t,
! 385: private_pts_database_t *this, chunk_t measurement, int cid, int aik_id,
! 386: int seq_no, int pcr, pts_meas_algorithms_t algo)
! 387: {
! 388: int id;
! 389:
! 390: if (this->db->execute(this->db, &id,
! 391: "INSERT INTO component_hashes "
! 392: "(component, key, seq_no, pcr, algo, hash) "
! 393: "VALUES (?, ?, ?, ?, ?, ?)",
! 394: DB_INT, cid, DB_INT, aik_id, DB_INT, seq_no, DB_INT, pcr,
! 395: DB_INT, algo, DB_BLOB, measurement) == 1)
! 396: {
! 397: return SUCCESS;
! 398: }
! 399:
! 400: DBG1(DBG_PTS, "could not insert component measurement into database");
! 401: return FAILED;
! 402: }
! 403:
! 404: METHOD(pts_database_t, delete_comp_measurements, int,
! 405: private_pts_database_t *this, int cid, int aik_id)
! 406: {
! 407: return this->db->execute(this->db, NULL,
! 408: "DELETE FROM component_hashes "
! 409: "WHERE component = ? AND key = ?",
! 410: DB_INT, cid, DB_INT, aik_id);
! 411: }
! 412:
! 413: METHOD(pts_database_t, get_comp_measurement_count, status_t,
! 414: private_pts_database_t *this, pts_comp_func_name_t *comp_name,
! 415: int aik_id, pts_meas_algorithms_t algo, int *cid, int *count)
! 416: {
! 417: enumerator_t *e;
! 418: status_t status = SUCCESS;
! 419:
! 420: /* Initialize count */
! 421: *count = 0;
! 422:
! 423: /* Get the primary key of the Component Functional Name */
! 424: e = this->db->query(this->db,
! 425: "SELECT id FROM components "
! 426: " WHERE vendor_id = ? AND name = ? AND qualifier = ?",
! 427: DB_INT, comp_name->get_vendor_id(comp_name),
! 428: DB_INT, comp_name->get_name(comp_name),
! 429: DB_INT, comp_name->get_qualifier(comp_name),
! 430: DB_INT);
! 431: if (!e)
! 432: {
! 433: DBG1(DBG_PTS, "no database query enumerator returned");
! 434: return FAILED;
! 435: }
! 436: if (!e->enumerate(e, cid))
! 437: {
! 438: DBG1(DBG_PTS, "component functional name not found in database");
! 439: e->destroy(e);
! 440: return FAILED;
! 441: }
! 442: e->destroy(e);
! 443:
! 444: /* Get the number of stored measurements for a given AIK and component */
! 445: e = this->db->query(this->db,
! 446: "SELECT COUNT(*) FROM component_hashes AS ch "
! 447: "WHERE component = ? AND key = ? AND algo = ?",
! 448: DB_INT, *cid, DB_INT, aik_id, DB_INT, algo, DB_INT);
! 449: if (!e)
! 450: {
! 451: DBG1(DBG_PTS, "no database query enumerator returned");
! 452: return FAILED;
! 453: }
! 454: if (!e->enumerate(e, count))
! 455: {
! 456: DBG1(DBG_PTS, "no component measurement count returned from database");
! 457: status = FAILED;
! 458: }
! 459: e->destroy(e);
! 460:
! 461: return status;
! 462: }
! 463:
! 464: METHOD(pts_database_t, destroy, void,
! 465: private_pts_database_t *this)
! 466: {
! 467: free(this);
! 468: }
! 469:
! 470: /**
! 471: * See header
! 472: */
! 473: pts_database_t *pts_database_create(imv_database_t *imv_db)
! 474: {
! 475: private_pts_database_t *this;
! 476:
! 477: if (!imv_db)
! 478: {
! 479: return NULL;
! 480: }
! 481:
! 482: INIT(this,
! 483: .public = {
! 484: .get_pathname = _get_pathname,
! 485: .create_file_hash_enumerator = _create_file_hash_enumerator,
! 486: .get_product_version = _get_product_version,
! 487: .add_file_measurement = _add_file_measurement,
! 488: .create_file_meas_enumerator = _create_file_meas_enumerator,
! 489: .check_comp_measurement = _check_comp_measurement,
! 490: .insert_comp_measurement = _insert_comp_measurement,
! 491: .delete_comp_measurements = _delete_comp_measurements,
! 492: .get_comp_measurement_count = _get_comp_measurement_count,
! 493: .destroy = _destroy,
! 494: },
! 495: .db = imv_db->get_database(imv_db),
! 496: );
! 497:
! 498: return &this->public;
! 499: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>