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