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