Properly initialize ima flag when adding file measurements
[strongswan.git] / src / libpts / plugins / imv_attestation / attest_db.c
1 /*
2 * Copyright (C) 2011-2012 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "attest_db.h"
17
18 #include "libpts.h"
19 #include "pts/pts_meas_algo.h"
20 #include "pts/pts_file_meas.h"
21 #include "pts/components/pts_comp_func_name.h"
22
23 #include <libgen.h>
24
25 #define IMA_MAX_NAME_LEN 255
26
27 typedef struct private_attest_db_t private_attest_db_t;
28
29 /**
30 * Private data of an attest_db_t object.
31 */
32 struct private_attest_db_t {
33
34 /**
35 * Public members of attest_db_state_t
36 */
37 attest_db_t public;
38
39 /**
40 * Component Functional Name to be queried
41 */
42 pts_comp_func_name_t *cfn;
43
44 /**
45 * Primary key of the Component Functional Name to be queried
46 */
47 int cid;
48
49 /**
50 * TRUE if Component Functional Name has been set
51 */
52 bool comp_set;
53
54 /**
55 * Directory containing the Measurement file to be queried
56 */
57 char *dir;
58
59 /**
60 * Primary key of the directory to be queried
61 */
62 int did;
63
64 /**
65 * TRUE if directory has been set
66 */
67 bool dir_set;
68
69 /**
70 * Measurement file to be queried
71 */
72 char *file;
73
74 /**
75 * Primary key of measurement file to be queried
76 */
77 int fid;
78
79 /**
80 * TRUE if file has been set
81 */
82 bool file_set;
83
84 /**
85 * AIK to be queried
86 */
87 chunk_t key;
88
89 /**
90 * Primary key of the AIK to be queried
91 */
92 int kid;
93
94 /**
95 * TRUE if AIK has been set
96 */
97 bool key_set;
98
99 /**
100 * Software product to be queried
101 */
102 char *product;
103
104 /**
105 * Primary key of software product to be queried
106 */
107 int pid;
108
109 /**
110 * TRUE if product has been set
111 */
112 bool product_set;
113
114 /**
115 * TRUE if relative filenames are to be used
116 */
117 bool relative;
118
119 /**
120 * Sequence number for ordering entries
121 */
122 int seq_no;
123
124 /**
125 * File measurement hash algorithm
126 */
127 pts_meas_algorithms_t algo;
128
129 /**
130 * Optional owner (user/host name)
131 */
132 char *owner;
133
134 /**
135 * Attestation database
136 */
137 database_t *db;
138
139 };
140
141 char* print_cfn(pts_comp_func_name_t *cfn)
142 {
143 static char buf[BUF_LEN];
144 char flags[8];
145 int type, vid, name, qualifier, n;
146 enum_name_t *names, *types;
147
148 vid = cfn->get_vendor_id(cfn),
149 name = cfn->get_name(cfn);
150 qualifier = cfn->get_qualifier(cfn);
151 n = snprintf(buf, BUF_LEN, "0x%06x/0x%08x-0x%02x", vid, name, qualifier);
152
153 names = pts_components->get_comp_func_names(pts_components, vid);
154 types = pts_components->get_qualifier_type_names(pts_components, vid);
155 type = pts_components->get_qualifier(pts_components, cfn, flags);
156 if (names && types)
157 {
158 n = snprintf(buf + n, BUF_LEN - n, " %N/%N [%s] %N",
159 pen_names, vid, names, name, flags, types, type);
160 }
161 return buf;
162 }
163
164 METHOD(attest_db_t, set_component, bool,
165 private_attest_db_t *this, char *comp, bool create)
166 {
167 enumerator_t *e;
168 char *pos1, *pos2;
169 int vid, name, qualifier;
170 pts_comp_func_name_t *cfn;
171
172 if (this->comp_set)
173 {
174 printf("component has already been set\n");
175 return FALSE;
176 }
177
178 /* parse component string */
179 pos1 = strchr(comp, '/');
180 pos2 = strchr(comp, '-');
181 if (!pos1 || !pos2)
182 {
183 printf("component string must have the form \"vendor_id/name-qualifier\"\n");
184 return FALSE;
185 }
186 vid = atoi(comp);
187 name = atoi(pos1 + 1);
188 qualifier = atoi(pos2 + 1);
189 cfn = pts_comp_func_name_create(vid, name, qualifier);
190
191 e = this->db->query(this->db,
192 "SELECT id FROM components "
193 "WHERE vendor_id = ? AND name = ? AND qualifier = ?",
194 DB_UINT, vid, DB_INT, name, DB_INT, qualifier, DB_INT);
195 if (e)
196 {
197 if (e->enumerate(e, &this->cid))
198 {
199 this->comp_set = TRUE;
200 this->cfn = cfn;
201 }
202 e->destroy(e);
203 }
204 if (this->comp_set)
205 {
206 return TRUE;
207 }
208
209 if (!create)
210 {
211 printf("component '%s' not found in database\n", print_cfn(cfn));
212 cfn->destroy(cfn);
213 return FALSE;
214 }
215
216 /* Add a new database entry */
217 this->comp_set = this->db->execute(this->db, &this->cid,
218 "INSERT INTO components (vendor_id, name, qualifier) "
219 "VALUES (?, ?, ?)",
220 DB_INT, vid, DB_INT, name, DB_INT, qualifier) == 1;
221
222 printf("component '%s' %sinserted into database\n", print_cfn(cfn),
223 this->comp_set ? "" : "could not be ");
224 if (this->comp_set)
225 {
226 this->cfn = cfn;
227 }
228 else
229 {
230 cfn->destroy(cfn);
231 }
232 return this->comp_set;
233 }
234
235 METHOD(attest_db_t, set_cid, bool,
236 private_attest_db_t *this, int cid)
237 {
238 enumerator_t *e;
239 int vid, name, qualifier;
240
241 if (this->comp_set)
242 {
243 printf("component has already been set\n");
244 return FALSE;
245 }
246 this->cid = cid;
247
248 e = this->db->query(this->db, "SELECT vendor_id, name, qualifier "
249 "FROM components WHERE id = ?",
250 DB_UINT, cid, DB_INT, DB_INT, DB_INT);
251 if (e)
252 {
253 if (e->enumerate(e, &vid, &name, &qualifier))
254 {
255 this->cfn = pts_comp_func_name_create(vid, name, qualifier);
256 this->comp_set = TRUE;
257 }
258 else
259 {
260 printf("no component found with cid %d\n", cid);
261 }
262 e->destroy(e);
263 }
264 return this->comp_set;
265 }
266
267 METHOD(attest_db_t, set_directory, bool,
268 private_attest_db_t *this, char *dir, bool create)
269 {
270 enumerator_t *e;
271 size_t len;
272
273 if (this->dir_set)
274 {
275 printf("directory has already been set\n");
276 return FALSE;
277 }
278 free(this->dir);
279
280 /* remove trailing '/' character */
281 len = strlen(dir);
282 if (len && dir[len-1] == '/')
283 {
284 dir[len-1] = '\0';
285 }
286 this->dir = strdup(dir);
287
288 e = this->db->query(this->db,
289 "SELECT id FROM files WHERE type = 1 AND path = ?",
290 DB_TEXT, dir, DB_INT);
291 if (e)
292 {
293 if (e->enumerate(e, &this->did))
294 {
295 this->dir_set = TRUE;
296 }
297 e->destroy(e);
298 }
299 if (this->dir_set)
300 {
301 return TRUE;
302 }
303
304 if (!create)
305 {
306 printf("directory '%s' not found in database\n", dir);
307 return FALSE;
308 }
309
310 /* Add a new database entry */
311 this->dir_set = this->db->execute(this->db, &this->did,
312 "INSERT INTO files (type, path) VALUES (1, ?)",
313 DB_TEXT, dir) == 1;
314
315 printf("directory '%s' %sinserted into database\n", dir,
316 this->dir_set ? "" : "could not be ");
317
318 return this->dir_set;
319 }
320
321 METHOD(attest_db_t, set_did, bool,
322 private_attest_db_t *this, int did)
323 {
324 enumerator_t *e;
325 char *dir;
326
327 if (this->dir_set)
328 {
329 printf("directory has already been set\n");
330 return FALSE;
331 }
332 this->did = did;
333
334 e = this->db->query(this->db, "SELECT path FROM files WHERE id = ?",
335 DB_UINT, did, DB_TEXT);
336 if (e)
337 {
338 if (e->enumerate(e, &dir))
339 {
340 free(this->dir);
341 this->dir = strdup(dir);
342 this->dir_set = TRUE;
343 }
344 else
345 {
346 printf("no directory found with did %d\n", did);
347 }
348 e->destroy(e);
349 }
350 return this->dir_set;
351 }
352
353 METHOD(attest_db_t, set_file, bool,
354 private_attest_db_t *this, char *file, bool create)
355 {
356 enumerator_t *e;
357 char *filename;
358
359 if (this->file_set)
360 {
361 printf("file has already been set\n");
362 return FALSE;
363 }
364 this->file = strdup(file);
365 filename = this->relative ? basename(file) : file;
366
367 e = this->db->query(this->db, "SELECT id FROM files WHERE path = ?",
368 DB_TEXT, filename, DB_INT);
369 if (e)
370 {
371 if (e->enumerate(e, &this->fid))
372 {
373 this->file_set = TRUE;
374 }
375 e->destroy(e);
376 }
377 if (this->file_set)
378 {
379 return TRUE;
380 }
381
382 if (!create)
383 {
384 printf("file '%s' not found in database\n", file);
385 return FALSE;
386 }
387
388 /* Add a new database entry */
389 this->file_set = this->db->execute(this->db, &this->fid,
390 "INSERT INTO files (type, path) VALUES (0, ?)",
391 DB_TEXT, filename) == 1;
392
393 printf("file '%s' %sinserted into database\n", filename,
394 this->file_set ? "" : "could not be ");
395
396 return this->file_set;
397 }
398
399 METHOD(attest_db_t, set_fid, bool,
400 private_attest_db_t *this, int fid)
401 {
402 enumerator_t *e;
403 char *file;
404
405 if (this->file_set)
406 {
407 printf("file has already been set\n");
408 return FALSE;
409 }
410 this->fid = fid;
411
412 e = this->db->query(this->db, "SELECT path FROM files WHERE id = ?",
413 DB_UINT, fid, DB_TEXT);
414 if (e)
415 {
416 if (e->enumerate(e, &file))
417 {
418 this->file = strdup(file);
419 this->file_set = TRUE;
420 }
421 else
422 {
423 printf("no file found with fid %d\n", fid);
424 }
425 e->destroy(e);
426 }
427 return this->file_set;
428 }
429
430 METHOD(attest_db_t, set_key, bool,
431 private_attest_db_t *this, chunk_t key, bool create)
432 {
433 enumerator_t *e;
434 char *owner;
435
436 if (this->key_set)
437 {
438 printf("key has already been set\n");
439 return FALSE;
440 }
441 this->key = key;
442
443 e = this->db->query(this->db, "SELECT id, owner FROM keys WHERE keyid= ?",
444 DB_BLOB, this->key, DB_INT, DB_TEXT);
445 if (e)
446 {
447 if (e->enumerate(e, &this->kid, &owner))
448 {
449 free(this->owner);
450 this->owner = strdup(owner);
451 this->key_set = TRUE;
452 }
453 e->destroy(e);
454 }
455 if (this->key_set)
456 {
457 return TRUE;
458 }
459
460 if (!create)
461 {
462 printf("key '%#B' not found in database\n", &this->key);
463 return FALSE;
464 }
465
466 /* Add a new database entry */
467 if (!this->owner)
468 {
469 this->owner = strdup("");
470 }
471 this->key_set = this->db->execute(this->db, &this->kid,
472 "INSERT INTO keys (keyid, owner) VALUES (?, ?)",
473 DB_BLOB, this->key, DB_TEXT, this->owner) == 1;
474
475 printf("key '%#B' %sinserted into database\n", &this->key,
476 this->key_set ? "" : "could not be ");
477
478 return this->key_set;
479
480 };
481
482 METHOD(attest_db_t, set_kid, bool,
483 private_attest_db_t *this, int kid)
484 {
485 enumerator_t *e;
486 chunk_t key;
487 char *owner;
488
489 if (this->key_set)
490 {
491 printf("key has already been set\n");
492 return FALSE;
493 }
494 this->kid = kid;
495
496 e = this->db->query(this->db, "SELECT keyid, owner FROM keys WHERE id = ?",
497 DB_UINT, kid, DB_BLOB, DB_TEXT);
498 if (e)
499 {
500 if (e->enumerate(e, &key, &owner))
501 {
502 this->owner = strdup(owner);
503 this->key = chunk_clone(key);
504 this->key_set = TRUE;
505 }
506 else
507 {
508 printf("no key found with kid %d\n", kid);
509 }
510 e->destroy(e);
511 }
512 return this->key_set;
513
514 };
515
516 METHOD(attest_db_t, set_product, bool,
517 private_attest_db_t *this, char *product, bool create)
518 {
519 enumerator_t *e;
520
521 if (this->product_set)
522 {
523 printf("product has already been set\n");
524 return FALSE;
525 }
526 this->product = strdup(product);
527
528 e = this->db->query(this->db, "SELECT id FROM products WHERE name = ?",
529 DB_TEXT, product, DB_INT);
530 if (e)
531 {
532 if (e->enumerate(e, &this->pid))
533 {
534 this->product_set = TRUE;
535 }
536 e->destroy(e);
537 }
538 if (this->product_set)
539 {
540 return TRUE;
541 }
542
543 if (!create)
544 {
545 printf("product '%s' not found in database\n", product);
546 return FALSE;
547 }
548
549 /* Add a new database entry */
550 this->product_set = this->db->execute(this->db, &this->pid,
551 "INSERT INTO products (name) VALUES (?)",
552 DB_TEXT, product) == 1;
553
554 printf("product '%s' %sinserted into database\n", product,
555 this->product_set ? "" : "could not be ");
556
557 return this->product_set;
558 }
559
560 METHOD(attest_db_t, set_pid, bool,
561 private_attest_db_t *this, int pid)
562 {
563 enumerator_t *e;
564 char *product;
565
566 if (this->product_set)
567 {
568 printf("product has already been set\n");
569 return FALSE;
570 }
571 this->pid = pid;
572
573 e = this->db->query(this->db, "SELECT name FROM products WHERE id = ?",
574 DB_UINT, pid, DB_TEXT);
575 if (e)
576 {
577 if (e->enumerate(e, &product))
578 {
579 this->product = strdup(product);
580 this->product_set = TRUE;
581 }
582 else
583 {
584 printf("no product found with pid %d in database\n", pid);
585 }
586 e->destroy(e);
587 }
588 return this->product_set;
589 }
590
591 METHOD(attest_db_t, set_algo, void,
592 private_attest_db_t *this, pts_meas_algorithms_t algo)
593 {
594 this->algo = algo;
595 }
596
597 METHOD(attest_db_t, set_relative, void,
598 private_attest_db_t *this)
599 {
600 this->relative = TRUE;
601 }
602
603 METHOD(attest_db_t, set_sequence, void,
604 private_attest_db_t *this, int seq_no)
605 {
606 this->seq_no = seq_no;
607 }
608
609 METHOD(attest_db_t, set_owner, void,
610 private_attest_db_t *this, char *owner)
611 {
612 free(this->owner);
613 this->owner = strdup(owner);
614 }
615
616 METHOD(attest_db_t, list_components, void,
617 private_attest_db_t *this)
618 {
619 enumerator_t *e;
620 pts_comp_func_name_t *cfn;
621 int seq_no, cid, vid, name, qualifier, count = 0;
622
623 if (this->kid)
624 {
625 e = this->db->query(this->db,
626 "SELECT kc.seq_no, c.id, c.vendor_id, c.name, c.qualifier "
627 "FROM components AS c "
628 "JOIN key_component AS kc ON c.id = kc.component "
629 "WHERE kc.key = ? ORDER BY kc.seq_no",
630 DB_UINT, this->kid, DB_INT, DB_INT, DB_INT, DB_INT, DB_INT);
631 if (e)
632 {
633 while (e->enumerate(e, &cid, &seq_no, &vid, &name, &qualifier))
634 {
635 cfn = pts_comp_func_name_create(vid, name, qualifier);
636 printf("%4d: #%-2d %s\n", seq_no, cid, print_cfn(cfn));
637 cfn->destroy(cfn);
638 count++;
639 }
640 e->destroy(e);
641 printf("%d component%s found for key %#B\n", count,
642 (count == 1) ? "" : "s", &this->key);
643 }
644 }
645 else
646 {
647 e = this->db->query(this->db,
648 "SELECT id, vendor_id, name, qualifier FROM components "
649 "ORDER BY vendor_id, name, qualifier",
650 DB_INT, DB_INT, DB_INT, DB_INT);
651 if (e)
652 {
653 while (e->enumerate(e, &cid, &vid, &name, &qualifier))
654 {
655 cfn = pts_comp_func_name_create(vid, name, qualifier);
656 printf("%4d: %s\n", cid, print_cfn(cfn));
657 cfn->destroy(cfn);
658 count++;
659 }
660 e->destroy(e);
661 printf("%d component%s found\n", count, (count == 1) ? "" : "s");
662 }
663 }
664 }
665
666 METHOD(attest_db_t, list_keys, void,
667 private_attest_db_t *this)
668 {
669 enumerator_t *e;
670 chunk_t keyid;
671 char *owner;
672 int kid, count = 0;
673
674 if (this->cid)
675 {
676 e = this->db->query(this->db,
677 "SELECT k.id, k.keyid, k.owner FROM keys AS k "
678 "JOIN key_component AS kc ON k.id = kc.key "
679 "WHERE kc.component = ? ORDER BY k.keyid",
680 DB_UINT, this->cid, DB_INT, DB_BLOB, DB_TEXT);
681 if (e)
682 {
683 while (e->enumerate(e, &kid, &keyid, &owner))
684 {
685 printf("%4d: %#B '%s'\n", kid, &keyid, owner);
686 count++;
687 }
688 e->destroy(e);
689 }
690 }
691 else
692 {
693 e = this->db->query(this->db, "SELECT id, keyid, owner FROM keys "
694 "ORDER BY keyid",
695 DB_INT, DB_BLOB, DB_TEXT);
696 if (e)
697 {
698 while (e->enumerate(e, &kid, &keyid, &owner))
699 {
700 printf("%4d: %#B '%s'\n", kid, &keyid, owner);
701 count++;
702 }
703 e->destroy(e);
704 }
705 }
706
707 printf("%d key%s found", count, (count == 1) ? "" : "s");
708 if (this->comp_set)
709 {
710 printf(" for component '%s'", print_cfn(this->cfn));
711 }
712 printf("\n");
713 }
714
715 METHOD(attest_db_t, list_files, void,
716 private_attest_db_t *this)
717 {
718 enumerator_t *e;
719 char *file, *file_type[] = { " ", "d", "r" };
720 int fid, type, meas, meta, count = 0;
721
722 if (this->pid)
723 {
724 e = this->db->query(this->db,
725 "SELECT f.id, f.type, f.path, pf.measurement, pf.metadata "
726 "FROM files AS f "
727 "JOIN product_file AS pf ON f.id = pf.file "
728 "WHERE pf.product = ? ORDER BY f.path",
729 DB_UINT, this->pid, DB_INT, DB_INT, DB_TEXT, DB_INT, DB_INT);
730 if (e)
731 {
732 while (e->enumerate(e, &fid, &type, &file, &meas, &meta))
733 {
734 type = (type < 0 || type > 2) ? 0 : type;
735 printf("%4d: |%s%s| %s %s\n", fid, meas ? "M":" ", meta ? "T":" ",
736 file_type[type], file);
737 count++;
738 }
739 e->destroy(e);
740 }
741 }
742 else
743 {
744 e = this->db->query(this->db,
745 "SELECT id, type, path FROM files "
746 "ORDER BY path",
747 DB_INT, DB_INT, DB_TEXT);
748 if (e)
749 {
750 while (e->enumerate(e, &fid, &type, &file))
751 {
752 type = (type < 0 || type > 2) ? 0 : type;
753 printf("%4d: %s %s\n", fid, file_type[type], file);
754 count++;
755 }
756 e->destroy(e);
757 }
758 }
759
760 printf("%d file%s found", count, (count == 1) ? "" : "s");
761 if (this->product_set)
762 {
763 printf(" for product '%s'", this->product);
764 }
765 printf("\n");
766 }
767
768 METHOD(attest_db_t, list_products, void,
769 private_attest_db_t *this)
770 {
771 enumerator_t *e;
772 char *product;
773 int pid, meas, meta, count = 0;
774
775 if (this->fid)
776 {
777 e = this->db->query(this->db,
778 "SELECT p.id, p.name, pf.measurement, pf.metadata "
779 "FROM products AS p "
780 "JOIN product_file AS pf ON p.id = pf.product "
781 "WHERE pf.file = ? ORDER BY p.name",
782 DB_UINT, this->fid, DB_INT, DB_TEXT, DB_INT, DB_INT);
783 if (e)
784 {
785 while (e->enumerate(e, &pid, &product, &meas, &meta))
786 {
787 printf("%4d: |%s%s| %s\n", pid, meas ? "M":" ", meta ? "T":" ",
788 product);
789 count++;
790 }
791 e->destroy(e);
792 }
793 }
794 else
795 {
796 e = this->db->query(this->db, "SELECT id, name FROM products "
797 "ORDER BY name",
798 DB_INT, DB_TEXT);
799 if (e)
800 {
801 while (e->enumerate(e, &pid, &product))
802 {
803 printf("%4d: %s\n", pid, product);
804 count++;
805 }
806 e->destroy(e);
807 }
808 }
809
810 printf("%d product%s found", count, (count == 1) ? "" : "s");
811 if (this->file_set)
812 {
813 printf(" for file '%s'", this->file);
814 }
815 printf("\n");
816 }
817
818 /**
819 * get the directory if there is one from the files tables
820 */
821 static void get_directory(private_attest_db_t *this, int did, char **directory)
822 {
823 enumerator_t *e;
824 char *dir;
825
826 free(*directory);
827 *directory = strdup("");
828
829 if (did)
830 {
831 e = this->db->query(this->db,
832 "SELECT path from files WHERE id = ?",
833 DB_UINT, did, DB_TEXT);
834 if (e)
835 {
836 if (e->enumerate(e, &dir))
837 {
838 free(*directory);
839 *directory = strdup(dir);
840 }
841 e->destroy(e);
842 }
843 }
844 }
845
846 static bool slash(char *directory, char *file)
847 {
848 return *file != '/' && directory[max(0, strlen(directory)-1)] != '/';
849 }
850
851 METHOD(attest_db_t, list_hashes, void,
852 private_attest_db_t *this)
853 {
854 enumerator_t *e;
855 chunk_t hash;
856 char *file, *dir, *product;
857 int fid, fid_old = 0, did, did_old = 0, count = 0;
858
859 dir = strdup("");
860
861 if (this->pid && this->fid)
862 {
863 e = this->db->query(this->db,
864 "SELECT hash FROM file_hashes "
865 "WHERE algo = ? AND file = ? AND directory = ? AND product = ?",
866 DB_INT, this->algo, DB_INT, this->fid, DB_INT, this->did,
867 DB_INT, this->pid, DB_BLOB);
868 if (e)
869 {
870 while (e->enumerate(e, &hash))
871 {
872 if (this->fid != fid_old)
873 {
874 printf("%4d: %s%s%s\n", this->fid, this->dir,
875 slash(this->dir, this->file) ? "/" : "", this->file);
876 fid_old = this->fid;
877 }
878 printf(" %#B\n", &hash);
879 count++;
880 }
881 e->destroy(e);
882
883 printf("%d %N value%s found for product '%s'\n", count,
884 pts_meas_algorithm_names, this->algo,
885 (count == 1) ? "" : "s", this->product);
886 }
887 }
888 else if (this->pid)
889 {
890 e = this->db->query(this->db,
891 "SELECT f.id, f. f.path, fh.hash, fh.directory "
892 "FROM file_hashes AS fh "
893 "JOIN files AS f ON f.id = fh.file "
894 "WHERE fh.algo = ? AND fh.product = ? "
895 "ORDER BY fh.directory, f.path",
896 DB_INT, this->algo, DB_UINT, this->pid,
897 DB_INT, DB_TEXT, DB_BLOB, DB_INT);
898 if (e)
899 {
900 while (e->enumerate(e, &fid, &file, &hash, &did))
901 {
902 if (fid != fid_old || did != did_old)
903 {
904 if (did != did_old)
905 {
906 get_directory(this, did, &dir);
907 }
908 printf("%4d: %s%s%s\n", fid,
909 dir, slash(dir, file) ? "/" : "", file);
910 fid_old = fid;
911 did_old = did;
912 }
913 printf(" %#B\n", &hash);
914 count++;
915 }
916 e->destroy(e);
917
918 printf("%d %N value%s found for product '%s'\n", count,
919 pts_meas_algorithm_names, this->algo,
920 (count == 1) ? "" : "s", this->product);
921 }
922 }
923 else if (this->fid)
924 {
925 e = this->db->query(this->db,
926 "SELECT p.name, fh.hash, fh.directory "
927 "FROM file_hashes AS fh "
928 "JOIN products AS p ON p.id = fh.product "
929 "WHERE fh.algo = ? AND fh.file = ? AND fh.directory = ?"
930 "ORDER BY p.name",
931 DB_INT, this->algo, DB_UINT, this->fid, DB_UINT, this->did,
932 DB_TEXT, DB_BLOB, DB_INT);
933 if (e)
934 {
935 while (e->enumerate(e, &product, &hash, &did))
936 {
937 printf("%#B '%s'\n", &hash, product);
938 count++;
939 }
940 e->destroy(e);
941
942 printf("%d %N value%s found for file '%s%s%s'\n",
943 count, pts_meas_algorithm_names, this->algo,
944 (count == 1) ? "" : "s", this->dir,
945 slash(this->dir, this->file) ? "/" : "", this->file);
946 }
947 }
948 else
949 {
950 e = this->db->query(this->db,
951 "SELECT f.id, f.path, p.name, fh.hash, fh.directory "
952 "FROM file_hashes AS fh "
953 "JOIN files AS f ON f.id = fh.file "
954 "JOIN products AS p ON p.id = fh.product "
955 "WHERE fh.algo = ? "
956 "ORDER BY fh.directory, f.path, p.name",
957 DB_INT, this->algo,
958 DB_INT, DB_TEXT, DB_TEXT, DB_BLOB, DB_INT);
959 if (e)
960 {
961 while (e->enumerate(e, &fid, &file, &product, &hash, &did))
962 {
963 if (fid != fid_old || did != did_old)
964 {
965 if (did != did_old)
966 {
967 get_directory(this, did, &dir);
968 did_old = did;
969 }
970 printf("%4d: %s%s%s\n", fid,
971 dir, slash(dir, file) ? "/" : "", file);
972 fid_old = fid;
973 }
974 printf(" %#B '%s'\n", &hash, product);
975 count++;
976 }
977 e->destroy(e);
978
979 printf("%d %N value%s found\n", count, pts_meas_algorithm_names,
980 this->algo, (count == 1) ? "" : "s");
981 }
982 }
983 free(dir);
984 }
985
986 METHOD(attest_db_t, list_measurements, void,
987 private_attest_db_t *this)
988 {
989 enumerator_t *e;
990 chunk_t hash, keyid;
991 pts_comp_func_name_t *cfn;
992 char *owner;
993 int seq_no, pcr, vid, name, qualifier;
994 int cid, cid_old = 0, kid, kid_old = 0, count = 0;
995
996 if (this->kid && this->cid)
997 {
998 e = this->db->query(this->db,
999 "SELECT ch.seq_no, ch.pcr, ch.hash, k.owner "
1000 "FROM component_hashes AS ch "
1001 "JOIN keys AS k ON k.id = ch.key "
1002 "WHERE ch.algo = ? AND ch.key = ? AND ch.component = ? "
1003 "ORDER BY seq_no",
1004 DB_INT, this->algo, DB_UINT, this->kid, DB_UINT, this->cid,
1005 DB_INT, DB_INT, DB_BLOB, DB_TEXT);
1006 if (e)
1007 {
1008 while (e->enumerate(e, &seq_no, &pcr, &hash, &owner))
1009 {
1010 if (this->kid != kid_old)
1011 {
1012 printf("%4d: %#B '%s'\n", this->kid, &this->key, owner);
1013 kid_old = this->kid;
1014 }
1015 printf("%7d %02d %#B\n", seq_no, pcr, &hash);
1016 count++;
1017 }
1018 e->destroy(e);
1019
1020 printf("%d %N value%s found for component '%s'\n", count,
1021 pts_meas_algorithm_names, this->algo,
1022 (count == 1) ? "" : "s", print_cfn(this->cfn));
1023 }
1024 }
1025 else if (this->cid)
1026 {
1027 e = this->db->query(this->db,
1028 "SELECT ch.seq_no, ch.pcr, ch.hash, k.id, k.keyid, k.owner "
1029 "FROM component_hashes AS ch "
1030 "JOIN keys AS k ON k.id = ch.key "
1031 "WHERE ch.algo = ? AND ch.component = ? "
1032 "ORDER BY keyid, seq_no",
1033 DB_INT, this->algo, DB_UINT, this->cid,
1034 DB_INT, DB_INT, DB_BLOB, DB_INT, DB_BLOB, DB_TEXT);
1035 if (e)
1036 {
1037 while (e->enumerate(e, &seq_no, &pcr, &hash, &kid, &keyid, &owner))
1038 {
1039 if (kid != kid_old)
1040 {
1041 printf("%4d: %#B '%s'\n", kid, &keyid, owner);
1042 kid_old = kid;
1043 }
1044 printf("%7d %02d %#B\n", seq_no, pcr, &hash);
1045 count++;
1046 }
1047 e->destroy(e);
1048
1049 printf("%d %N value%s found for component '%s'\n", count,
1050 pts_meas_algorithm_names, this->algo,
1051 (count == 1) ? "" : "s", print_cfn(this->cfn));
1052 }
1053
1054 }
1055 else if (this->kid)
1056 {
1057 e = this->db->query(this->db,
1058 "SELECT ch.seq_no, ch.pcr, ch.hash, "
1059 "c.id, c.vendor_id, c.name, c.qualifier "
1060 "FROM component_hashes AS ch "
1061 "JOIN components AS c ON c.id = ch.component "
1062 "WHERE ch.algo = ? AND ch.key = ? "
1063 "ORDER BY vendor_id, name, qualifier, seq_no",
1064 DB_INT, this->algo, DB_UINT, this->kid, DB_INT, DB_INT, DB_BLOB,
1065 DB_INT, DB_INT, DB_INT, DB_INT);
1066 if (e)
1067 {
1068 while (e->enumerate(e, &seq_no, &pcr, &hash, &cid, &vid, &name,
1069 &qualifier))
1070 {
1071 if (cid != cid_old)
1072 {
1073 cfn = pts_comp_func_name_create(vid, name, qualifier);
1074 printf("%4d: %s\n", cid, print_cfn(cfn));
1075 cfn->destroy(cfn);
1076 cid_old = cid;
1077 }
1078 printf("%5d %02d %#B\n", seq_no, pcr, &hash);
1079 count++;
1080 }
1081 e->destroy(e);
1082
1083 printf("%d %N value%s found for key %#B '%s'\n", count,
1084 pts_meas_algorithm_names, this->algo,
1085 (count == 1) ? "" : "s", &this->key, this->owner);
1086 }
1087 }
1088 }
1089
1090 bool insert_file_hash(private_attest_db_t *this, pts_meas_algorithms_t algo,
1091 chunk_t measurement, int fid, int did, bool ima,
1092 int *hashes_added)
1093 {
1094 enumerator_t *e;
1095 chunk_t hash;
1096 char *label;
1097
1098 label = "could not be created";
1099
1100 e = this->db->query(this->db,
1101 "SELECT hash FROM file_hashes WHERE algo = ? "
1102 "AND file = ? AND directory = ? AND product = ? and key = 0",
1103 DB_INT, algo, DB_UINT, fid, DB_UINT, did, DB_UINT, this->pid, DB_BLOB);
1104 if (!e)
1105 {
1106 printf("file_hashes query failed\n");
1107 return FALSE;
1108 }
1109 if (e->enumerate(e, &hash))
1110 {
1111 label = chunk_equals(measurement, hash) ?
1112 "exists and equals" : "exists and differs";
1113 }
1114 else
1115 {
1116 if (this->db->execute(this->db, NULL,
1117 "INSERT INTO file_hashes "
1118 "(file, directory, product, key, algo, hash) "
1119 "VALUES (?, ?, ?, 0, ?, ?)",
1120 DB_UINT, fid, DB_UINT, did, DB_UINT, this->pid,
1121 DB_INT, algo, DB_BLOB, measurement) == 1)
1122 {
1123 label = "created";
1124 (*hashes_added)++;
1125 }
1126 }
1127 e->destroy(e);
1128
1129 printf(" %#B - %s%s\n", &measurement, ima ? "ima - " : "", label);
1130 return TRUE;
1131 }
1132
1133 METHOD(attest_db_t, add, bool,
1134 private_attest_db_t *this)
1135 {
1136 bool success = FALSE;
1137
1138 /* add key/component pair */
1139 if (this->kid && this->cid)
1140 {
1141 success = this->db->execute(this->db, NULL,
1142 "INSERT INTO key_component (key, component, seq_no) "
1143 "VALUES (?, ?, ?)",
1144 DB_UINT, this->kid, DB_UINT, this->cid,
1145 DB_UINT, this->seq_no) == 1;
1146
1147 printf("key/component pair (%d/%d) %sinserted into database at "
1148 "position %d\n", this->kid, this->cid,
1149 success ? "" : "could not be ", this->seq_no);
1150
1151 return success;
1152 }
1153
1154 /* add directory or file measurement for a given product */
1155 if ((this->did || this->fid) && this->pid)
1156 {
1157 char *pathname, *filename, *label;
1158 char ima_buffer[IMA_MAX_NAME_LEN + 1];
1159 chunk_t measurement, ima_template;
1160 pts_file_meas_t *measurements;
1161 hasher_t *hasher = NULL;
1162 bool ima = FALSE;
1163 int fid, did;
1164 int files_added = 0, hashes_added = 0, ima_hashes_added = 0;
1165 enumerator_t *enumerator, *e;
1166
1167 if (this->algo == PTS_MEAS_ALGO_SHA1_IMA)
1168 {
1169 ima = TRUE;
1170 this->algo = PTS_MEAS_ALGO_SHA1;
1171 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
1172 if (!hasher)
1173 {
1174 printf("could not create hasher\n");
1175 return FALSE;
1176 }
1177 }
1178
1179 pathname = this->did ? this->dir : this->file;
1180 measurements = pts_file_meas_create_from_path(0, pathname, this->did,
1181 this->relative, this->algo);
1182 if (!measurements)
1183 {
1184 printf("file measurement failed\n");
1185 hasher->destroy(hasher);
1186 return FALSE;
1187 }
1188 if (this->fid && this->relative)
1189 {
1190 set_directory(this, dirname(pathname), TRUE);
1191 }
1192 did = this->relative ? this->did : 0;
1193
1194 enumerator = measurements->create_enumerator(measurements);
1195 while (enumerator->enumerate(enumerator, &filename, &measurement))
1196 {
1197 /* retrieve or create filename */
1198 label = "could not be created";
1199
1200 e = this->db->query(this->db,
1201 "SELECT id FROM files WHERE path = ?",
1202 DB_TEXT, filename, DB_INT);
1203 if (!e)
1204 {
1205 printf("files query failed\n");
1206 break;
1207 }
1208 if (e->enumerate(e, &fid))
1209 {
1210 label = "exists";
1211 }
1212 else
1213 {
1214 if (this->db->execute(this->db, &fid,
1215 "INSERT INTO files (type, path) VALUES (0, ?)",
1216 DB_TEXT, filename) == 1)
1217 {
1218 label = "created";
1219 files_added++;
1220 }
1221 }
1222 e->destroy(e);
1223
1224 printf("%4d: %s - %s\n", fid, filename, label);
1225
1226 /* compute file measurement hash */
1227 if (!insert_file_hash(this, this->algo, measurement,
1228 fid, did, FALSE, &hashes_added))
1229 {
1230 break;
1231 }
1232
1233 if (!ima)
1234 {
1235 continue;
1236 }
1237
1238 /* compute IMA template hash */
1239 strncpy(ima_buffer, filename, IMA_MAX_NAME_LEN);
1240 ima_buffer[IMA_MAX_NAME_LEN] = '\0';
1241 ima_template = chunk_create(ima_buffer, sizeof(ima_buffer));
1242 if (!hasher->get_hash(hasher, measurement, NULL) ||
1243 !hasher->get_hash(hasher, ima_template, measurement.ptr))
1244 {
1245 printf("could not compute IMA template hash\n");
1246 break;
1247 }
1248 if (!insert_file_hash(this, PTS_MEAS_ALGO_SHA1_IMA, measurement,
1249 fid, did, TRUE, &ima_hashes_added))
1250 {
1251 break;
1252 }
1253 }
1254 enumerator->destroy(enumerator);
1255
1256 printf("%d measurements, added %d new files, %d new file hashes",
1257 measurements->get_file_count(measurements),
1258 files_added, hashes_added);
1259 if (ima)
1260 {
1261 printf(" , %d new ima hashes", ima_hashes_added);
1262 hasher->destroy(hasher);
1263 }
1264 printf("\n");
1265 measurements->destroy(measurements);
1266 success = TRUE;
1267 }
1268 return success;
1269 }
1270
1271 METHOD(attest_db_t, delete, bool,
1272 private_attest_db_t *this)
1273 {
1274 bool success;
1275
1276 /* delete a file measurement hash for a given product */
1277 if (this->algo && this->pid && this->fid)
1278 {
1279 success = this->db->execute(this->db, NULL,
1280 "DELETE FROM file_hashes "
1281 "WHERE algo = ? AND product = ? "
1282 "AND file = ? AND directory = ?",
1283 DB_UINT, this->algo, DB_UINT, this->pid,
1284 DB_UINT, this->fid, DB_UINT, this->did) > 0;
1285
1286 printf("%4d: %s%s%s\n", this->fid, this->dir, this->did ? "/":"",
1287 this->file);
1288 printf("%N value for product '%s' %sdeleted from database\n",
1289 pts_meas_algorithm_names, this->algo, this->product,
1290 success ? "" : "could not be ");
1291
1292 return success;
1293 }
1294
1295 /* delete product/file entries */
1296 if (this->pid && (this->fid || this->did))
1297 {
1298 success = this->db->execute(this->db, NULL,
1299 "DELETE FROM product_file "
1300 "WHERE product = ? AND file = ?",
1301 DB_UINT, this->pid,
1302 DB_UINT, this->fid ? this->fid : this->did) > 0;
1303
1304 printf("product/file pair (%d/%d) %sdeleted from database\n",
1305 this->pid, this->fid ? this->fid : this->did,
1306 success ? "" : "could not be ");
1307
1308 return success;
1309 }
1310
1311 /* delete key/component pair */
1312 if (this->kid && this->cid)
1313 {
1314 success = this->db->execute(this->db, NULL,
1315 "DELETE FROM key_component "
1316 "WHERE key = ? AND component = ?",
1317 DB_UINT, this->kid, DB_UINT, this->cid) > 0;
1318
1319 printf("key/component pair (%d/%d) %sdeleted from database\n",
1320 this->kid, this->cid, success ? "" : "could not be ");
1321 return success;
1322 }
1323
1324 if (this->cid)
1325 {
1326 success = this->db->execute(this->db, NULL,
1327 "DELETE FROM components WHERE id = ?",
1328 DB_UINT, this->cid) > 0;
1329
1330 printf("component '%s' %sdeleted from database\n", print_cfn(this->cfn),
1331 success ? "" : "could not be ");
1332 return success;
1333 }
1334
1335 if (this->did)
1336 {
1337 success = this->db->execute(this->db, NULL,
1338 "DELETE FROM files WHERE type = 1 AND id = ?",
1339 DB_UINT, this->did) > 0;
1340
1341 printf("directory '%s' %sdeleted from database\n", this->dir,
1342 success ? "" : "could not be ");
1343 return success;
1344 }
1345
1346 if (this->fid)
1347 {
1348 success = this->db->execute(this->db, NULL,
1349 "DELETE FROM files WHERE id = ?",
1350 DB_UINT, this->fid) > 0;
1351
1352 printf("file '%s' %sdeleted from database\n", this->file,
1353 success ? "" : "could not be ");
1354 return success;
1355 }
1356
1357 if (this->kid)
1358 {
1359 success = this->db->execute(this->db, NULL,
1360 "DELETE FROM keys WHERE id = ?",
1361 DB_UINT, this->kid) > 0;
1362
1363 printf("key %#B %sdeleted from database\n", &this->key,
1364 success ? "" : "could not be ");
1365 return success;
1366 }
1367 if (this->pid)
1368 {
1369 success = this->db->execute(this->db, NULL,
1370 "DELETE FROM products WHERE id = ?",
1371 DB_UINT, this->pid) > 0;
1372
1373 printf("product '%s' %sdeleted from database\n", this->product,
1374 success ? "" : "could not be ");
1375 return success;
1376 }
1377
1378 printf("empty delete command\n");
1379 return FALSE;
1380 }
1381
1382 METHOD(attest_db_t, destroy, void,
1383 private_attest_db_t *this)
1384 {
1385 DESTROY_IF(this->db);
1386 DESTROY_IF(this->cfn);
1387 free(this->product);
1388 free(this->file);
1389 free(this->dir);
1390 free(this->owner);
1391 free(this->key.ptr);
1392 free(this);
1393 }
1394
1395 /**
1396 * Described in header.
1397 */
1398 attest_db_t *attest_db_create(char *uri)
1399 {
1400 private_attest_db_t *this;
1401
1402 INIT(this,
1403 .public = {
1404 .set_component = _set_component,
1405 .set_cid = _set_cid,
1406 .set_directory = _set_directory,
1407 .set_did = _set_did,
1408 .set_file = _set_file,
1409 .set_fid = _set_fid,
1410 .set_key = _set_key,
1411 .set_kid = _set_kid,
1412 .set_product = _set_product,
1413 .set_pid = _set_pid,
1414 .set_algo = _set_algo,
1415 .set_relative = _set_relative,
1416 .set_sequence = _set_sequence,
1417 .set_owner = _set_owner,
1418 .list_products = _list_products,
1419 .list_files = _list_files,
1420 .list_components = _list_components,
1421 .list_keys = _list_keys,
1422 .list_hashes = _list_hashes,
1423 .list_measurements = _list_measurements,
1424 .add = _add,
1425 .delete = _delete,
1426 .destroy = _destroy,
1427 },
1428 .dir = strdup(""),
1429 .db = lib->db->create(lib->db, uri),
1430 );
1431
1432 if (!this->db)
1433 {
1434 fprintf(stderr, "opening database failed.\n");
1435 destroy(this);
1436 return NULL;
1437 }
1438
1439 return &this->public;
1440 }