Annotation of embedaddon/strongswan/src/libimcv/pts/pts_database.c, revision 1.1.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>