fixed attest sql query in list_measurements()
[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, chunk_t 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 = key;
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 free(this->owner);
424 this->owner = strdup(owner);
425 this->key_set = TRUE;
426 }
427 e->destroy(e);
428 }
429 if (this->key_set)
430 {
431 return TRUE;
432 }
433
434 if (!create)
435 {
436 printf("key '%#B' not found in database\n", &this->key);
437 return FALSE;
438 }
439
440 /* Add a new database entry */
441 if (!this->owner)
442 {
443 this->owner = strdup("");
444 }
445 this->key_set = this->db->execute(this->db, &this->kid,
446 "INSERT INTO keys (keyid, owner) VALUES (?, ?)",
447 DB_BLOB, this->key, DB_TEXT, this->owner) == 1;
448
449 printf("key '%#B' %sinserted into database\n", &this->key,
450 this->key_set ? "" : "could not be ");
451
452 return this->key_set;
453
454 };
455
456 METHOD(attest_db_t, set_kid, bool,
457 private_attest_db_t *this, int kid)
458 {
459 enumerator_t *e;
460 chunk_t key;
461 char *owner;
462
463 if (this->key_set)
464 {
465 printf("key has already been set\n");
466 return FALSE;
467 }
468 this->kid = kid;
469
470 e = this->db->query(this->db, "SELECT keyid, owner FROM keys WHERE id = ?",
471 DB_INT, kid, DB_BLOB, DB_TEXT);
472 if (e)
473 {
474 if (e->enumerate(e, &key, &owner))
475 {
476 this->owner = strdup(owner);
477 this->key = chunk_clone(key);
478 this->key_set = TRUE;
479 }
480 else
481 {
482 printf("no key found with kid %d\n", kid);
483 }
484 e->destroy(e);
485 }
486 return this->key_set;
487
488 };
489
490 METHOD(attest_db_t, set_product, bool,
491 private_attest_db_t *this, char *product, bool create)
492 {
493 enumerator_t *e;
494
495 if (this->product_set)
496 {
497 printf("product has already been set\n");
498 return FALSE;
499 }
500 this->product = strdup(product);
501
502 e = this->db->query(this->db, "SELECT id FROM products WHERE name = ?",
503 DB_TEXT, product, DB_INT);
504 if (e)
505 {
506 if (e->enumerate(e, &this->pid))
507 {
508 this->product_set = TRUE;
509 }
510 e->destroy(e);
511 }
512 if (this->product_set)
513 {
514 return TRUE;
515 }
516
517 if (!create)
518 {
519 printf("product '%s' not found in database\n", product);
520 return FALSE;
521 }
522
523 /* Add a new database entry */
524 this->product_set = this->db->execute(this->db, &this->pid,
525 "INSERT INTO products (name) VALUES (?)",
526 DB_TEXT, product) == 1;
527
528 printf("product '%s' %sinserted into database\n", product,
529 this->product_set ? "" : "could not be ");
530
531 return this->product_set;
532 }
533
534 METHOD(attest_db_t, set_pid, bool,
535 private_attest_db_t *this, int pid)
536 {
537 enumerator_t *e;
538 char *product;
539
540 if (this->product_set)
541 {
542 printf("product has already been set\n");
543 return FALSE;
544 }
545 this->pid = pid;
546
547 e = this->db->query(this->db, "SELECT name FROM products WHERE id = ?",
548 DB_INT, pid, DB_TEXT);
549 if (e)
550 {
551 if (e->enumerate(e, &product))
552 {
553 this->product = strdup(product);
554 this->product_set = TRUE;
555 }
556 else
557 {
558 printf("no product found with pid %d in database\n", pid);
559 }
560 e->destroy(e);
561 }
562 return this->product_set;
563 }
564
565 METHOD(attest_db_t, set_algo, void,
566 private_attest_db_t *this, pts_meas_algorithms_t algo)
567 {
568 this->algo = algo;
569 }
570
571 METHOD(attest_db_t, set_owner, void,
572 private_attest_db_t *this, char *owner)
573 {
574 free(this->owner);
575 this->owner = strdup(owner);
576 }
577
578 METHOD(attest_db_t, list_components, void,
579 private_attest_db_t *this)
580 {
581 enumerator_t *e;
582 pts_comp_func_name_t *cfn;
583 int cid, vid, name, qualifier, count = 0;
584
585 if (this->kid)
586 {
587 e = this->db->query(this->db,
588 "SELECT c.id, c.vendor_id, c.name, c.qualifier "
589 "FROM components AS c "
590 "JOIN key_component AS kc ON c.id = kc.component "
591 "WHERE kc.key = ? ORDER BY c.vendor_id, c.name, c.qualifier",
592 DB_INT, this->kid, DB_INT, DB_INT, DB_INT, DB_INT);
593 }
594 else
595 {
596 e = this->db->query(this->db,
597 "SELECT id, vendor_id, name, qualifier FROM components "
598 "ORDER BY vendor_id, name, qualifier",
599 DB_INT, DB_INT, DB_INT, DB_INT);
600 }
601 if (e)
602 {
603 while (e->enumerate(e, &cid, &vid, &name, &qualifier))
604 {
605 cfn = pts_comp_func_name_create(vid, name, qualifier);
606 printf("%3d: %s\n", cid, print_cfn(cfn));
607 cfn->destroy(cfn);
608 count++;
609 }
610 e->destroy(e);
611
612 printf("%d component%s found", count, (count == 1) ? "" : "s");
613 if (this->key_set)
614 {
615 printf(" for key %#B", &this->key);
616 }
617 printf("\n");
618 }
619 }
620
621 METHOD(attest_db_t, list_keys, void,
622 private_attest_db_t *this)
623 {
624 enumerator_t *e;
625 chunk_t keyid;
626 char *owner;
627 int kid, count = 0;
628
629 if (this->cid)
630 {
631 e = this->db->query(this->db,
632 "SELECT k.id, k.keyid, k.owner FROM keys AS k "
633 "JOIN key_component AS kc ON k.id = kc.key "
634 "WHERE kc.component = ? ORDER BY k.keyid",
635 DB_INT, this->cid, DB_INT, DB_BLOB, DB_TEXT);
636 if (e)
637 {
638 while (e->enumerate(e, &kid, &keyid, &owner))
639 {
640 printf("%3d: %#B '%s'\n", kid, &keyid, owner);
641 count++;
642 }
643 e->destroy(e);
644 }
645 }
646 else
647 {
648 e = this->db->query(this->db, "SELECT id, keyid, owner FROM keys "
649 "ORDER BY keyid",
650 DB_INT, DB_BLOB, DB_TEXT);
651 if (e)
652 {
653 while (e->enumerate(e, &kid, &keyid, &owner))
654 {
655 printf("%3d: %#B '%s'\n", kid, &keyid, owner);
656 count++;
657 }
658 e->destroy(e);
659 }
660 }
661
662 printf("%d key%s found", count, (count == 1) ? "" : "s");
663 if (this->comp_set)
664 {
665 printf(" for component '%s'", print_cfn(this->cfn));
666 }
667 printf("\n");
668 }
669
670 METHOD(attest_db_t, list_files, void,
671 private_attest_db_t *this)
672 {
673 enumerator_t *e;
674 char *file, *file_type[] = { " ", "d", "r" };
675 int fid, type, meas, meta, count = 0;
676
677 if (this->pid)
678 {
679 e = this->db->query(this->db,
680 "SELECT f.id, f.type, f.path, pf.measurement, pf.metadata "
681 "FROM files AS f "
682 "JOIN product_file AS pf ON f.id = pf.file "
683 "WHERE pf.product = ? ORDER BY f.path",
684 DB_INT, this->pid, DB_INT, DB_INT, DB_TEXT, DB_INT, DB_INT);
685 if (e)
686 {
687 while (e->enumerate(e, &fid, &type, &file, &meas, &meta))
688 {
689 type = (type < 0 || type > 2) ? 0 : type;
690 printf("%3d: |%s%s| %s %s\n", fid, meas ? "M":" ", meta ? "T":" ",
691 file_type[type], file);
692 count++;
693 }
694 e->destroy(e);
695 }
696 }
697 else
698 {
699 e = this->db->query(this->db,
700 "SELECT id, type, path FROM files "
701 "ORDER BY path",
702 DB_INT, DB_INT, DB_TEXT);
703 if (e)
704 {
705 while (e->enumerate(e, &fid, &type, &file))
706 {
707 type = (type < 0 || type > 2) ? 0 : type;
708 printf("%3d: %s %s\n", fid, file_type[type], file);
709 count++;
710 }
711 e->destroy(e);
712 }
713 }
714
715 printf("%d file%s found", count, (count == 1) ? "" : "s");
716 if (this->product_set)
717 {
718 printf(" for product '%s'", this->product);
719 }
720 printf("\n");
721 }
722
723 METHOD(attest_db_t, list_products, void,
724 private_attest_db_t *this)
725 {
726 enumerator_t *e;
727 char *product;
728 int pid, meas, meta, count = 0;
729
730 if (this->fid)
731 {
732 e = this->db->query(this->db,
733 "SELECT p.id, p.name, pf.measurement, pf.metadata "
734 "FROM products AS p "
735 "JOIN product_file AS pf ON p.id = pf.product "
736 "WHERE pf.file = ? ORDER BY p.name",
737 DB_INT, this->fid, DB_INT, DB_TEXT, DB_INT, DB_INT);
738 if (e)
739 {
740 while (e->enumerate(e, &pid, &product, &meas, &meta))
741 {
742 printf("%3d: |%s%s| %s\n", pid, meas ? "M":" ", meta ? "T":" ",
743 product);
744 count++;
745 }
746 e->destroy(e);
747 }
748 }
749 else
750 {
751 e = this->db->query(this->db, "SELECT id, name FROM products "
752 "ORDER BY name",
753 DB_INT, DB_TEXT);
754 if (e)
755 {
756 while (e->enumerate(e, &pid, &product))
757 {
758 printf("%3d: %s\n", pid, product);
759 count++;
760 }
761 e->destroy(e);
762 }
763 }
764
765 printf("%d product%s found", count, (count == 1) ? "" : "s");
766 if (this->file_set)
767 {
768 printf(" for file '%s'", this->file);
769 }
770 printf("\n");
771 }
772
773 /**
774 * get the directory if there is one from the files tables
775 */
776 static void get_directory(private_attest_db_t *this, int did, char **directory)
777 {
778 enumerator_t *e;
779 char *dir;
780
781 free(*directory);
782 *directory = strdup("");
783
784 if (did)
785 {
786 e = this->db->query(this->db,
787 "SELECT path from files WHERE id = ?",
788 DB_INT, did, DB_TEXT);
789 if (e)
790 {
791 if (e->enumerate(e, &dir))
792 {
793 free(*directory);
794 *directory = strdup(dir);
795 }
796 e->destroy(e);
797 }
798 }
799 }
800
801 static bool slash(char *directory, char *file)
802 {
803 return *file != '/' && directory[max(0, strlen(directory)-1)] != '/';
804 }
805
806 METHOD(attest_db_t, list_hashes, void,
807 private_attest_db_t *this)
808 {
809 enumerator_t *e;
810 chunk_t hash;
811 char *file, *dir, *product;
812 int fid, fid_old = 0, did, did_old = 0, count = 0;
813
814 dir = strdup("");
815
816 if (this->pid && this->fid)
817 {
818 e = this->db->query(this->db,
819 "SELECT hash FROM file_hashes "
820 "WHERE algo = ? AND file = ? AND directory = ? AND product = ?",
821 DB_INT, this->algo, DB_INT, this->fid, DB_INT, this->did,
822 DB_INT, this->pid, DB_BLOB);
823 if (e)
824 {
825 while (e->enumerate(e, &hash))
826 {
827 if (this->fid != fid_old)
828 {
829 printf("%3d: %s%s%s\n", this->fid, this->dir,
830 slash(this->dir, this->file) ? "/" : "", this->file);
831 fid_old = this->fid;
832 }
833 printf(" %#B\n", &hash);
834 count++;
835 }
836 e->destroy(e);
837
838 printf("%d %N value%s found for product '%s'\n", count,
839 hash_algorithm_names, pts_meas_algo_to_hash(this->algo),
840 (count == 1) ? "" : "s", this->product);
841 }
842 }
843 else if (this->pid)
844 {
845 e = this->db->query(this->db,
846 "SELECT f.id, f. f.path, fh.hash, fh.directory "
847 "FROM file_hashes AS fh "
848 "JOIN files AS f ON f.id = fh.file "
849 "WHERE fh.algo = ? AND fh.product = ? "
850 "ORDER BY fh.directory, f.path",
851 DB_INT, this->algo, DB_INT, this->pid,
852 DB_INT, DB_TEXT, DB_BLOB, DB_INT);
853 if (e)
854 {
855 while (e->enumerate(e, &fid, &file, &hash, &did))
856 {
857 if (fid != fid_old || did != did_old)
858 {
859 if (did != did_old)
860 {
861 get_directory(this, did, &dir);
862 }
863 printf("%3d: %s%s%s\n", fid,
864 dir, slash(dir, file) ? "/" : "", file);
865 fid_old = fid;
866 did_old = did;
867 }
868 printf(" %#B\n", &hash);
869 count++;
870 }
871 e->destroy(e);
872
873 printf("%d %N value%s found for product '%s'\n", count,
874 hash_algorithm_names, pts_meas_algo_to_hash(this->algo),
875 (count == 1) ? "" : "s", this->product);
876 }
877 }
878 else if (this->fid)
879 {
880 e = this->db->query(this->db,
881 "SELECT p.name, fh.hash, fh.directory "
882 "FROM file_hashes AS fh "
883 "JOIN products AS p ON p.id = fh.product "
884 "WHERE fh.algo = ? AND fh.file = ? AND fh.directory = ?"
885 "ORDER BY p.name",
886 DB_INT, this->algo, DB_INT, this->fid, DB_INT, this->did,
887 DB_TEXT, DB_BLOB, DB_INT);
888 if (e)
889 {
890 while (e->enumerate(e, &product, &hash, &did))
891 {
892 printf("%#B '%s'\n", &hash, product);
893 count++;
894 }
895 e->destroy(e);
896
897 printf("%d %N value%s found for file '%s%s%s'\n",
898 count, hash_algorithm_names, pts_meas_algo_to_hash(this->algo),
899 (count == 1) ? "" : "s", this->dir,
900 slash(this->dir, this->file) ? "/" : "", this->file);
901 }
902 }
903 else
904 {
905 e = this->db->query(this->db,
906 "SELECT f.id, f.path, p.name, fh.hash, fh.directory "
907 "FROM file_hashes AS fh "
908 "JOIN files AS f ON f.id = fh.file "
909 "JOIN products AS p ON p.id = fh.product "
910 "WHERE fh.algo = ? "
911 "ORDER BY fh.directory, f.path, p.name",
912 DB_INT, this->algo,
913 DB_INT, DB_TEXT, DB_TEXT, DB_BLOB, DB_INT);
914 if (e)
915 {
916 while (e->enumerate(e, &fid, &file, &product, &hash, &did))
917 {
918 if (fid != fid_old || did != did_old)
919 {
920 if (did != did_old)
921 {
922 get_directory(this, did, &dir);
923 did_old = did;
924 }
925 printf("%3d: %s%s%s\n", fid,
926 dir, slash(dir, file) ? "/" : "", file);
927 fid_old = fid;
928 }
929 printf(" %#B '%s'\n", &hash, product);
930 count++;
931 }
932 e->destroy(e);
933
934 printf("%d %N value%s found\n", count, hash_algorithm_names,
935 pts_meas_algo_to_hash(this->algo), (count == 1) ? "" : "s");
936 }
937 }
938 free(dir);
939 }
940
941 METHOD(attest_db_t, list_measurements, void,
942 private_attest_db_t *this)
943 {
944 enumerator_t *e;
945 chunk_t hash, keyid;
946 pts_comp_func_name_t *cfn;
947 char *owner;
948 int seq_no, pcr, vid, name, qualifier;
949 int cid, cid_old = 0, kid, kid_old = 0, count = 0;
950
951 if (this->kid && this->cid)
952 {
953 e = this->db->query(this->db,
954 "SELECT ch.seq_no, ch.pcr, ch.hash, k.owner "
955 "FROM component_hashes AS ch "
956 "JOIN keys AS k ON k.id = ch.key "
957 "WHERE ch.algo = ? AND ch.key = ? AND ch.component = ? "
958 "ORDER BY seq_no",
959 DB_INT, this->algo, DB_INT, this->kid, DB_INT, this->cid,
960 DB_INT, DB_INT, DB_BLOB, DB_TEXT);
961 if (e)
962 {
963 while (e->enumerate(e, &seq_no, &pcr, &hash, &owner))
964 {
965 if (this->kid != kid_old)
966 {
967 printf("%3d: %#B '%s'\n", this->kid, &this->key, owner);
968 kid_old = this->kid;
969 }
970 printf("%5d %02d %#B\n", seq_no, pcr, &hash);
971 count++;
972 }
973 e->destroy(e);
974
975 printf("%d %N value%s found for component '%s'\n", count,
976 hash_algorithm_names, pts_meas_algo_to_hash(this->algo),
977 (count == 1) ? "" : "s", print_cfn(this->cfn));
978 }
979 }
980 else if (this->cid)
981 {
982 e = this->db->query(this->db,
983 "SELECT ch.seq_no, ch.pcr, ch.hash, k.id, k.keyid, k.owner "
984 "FROM component_hashes AS ch "
985 "JOIN keys AS k ON k.id = ch.key "
986 "WHERE ch.algo = ? AND ch.component = ? "
987 "ORDER BY keyid, seq_no",
988 DB_INT, this->algo, DB_INT, this->cid,
989 DB_INT, DB_INT, DB_BLOB, DB_INT, DB_BLOB, DB_TEXT);
990 if (e)
991 {
992 while (e->enumerate(e, &seq_no, &pcr, &hash, &kid, &keyid, &owner))
993 {
994 if (kid != kid_old)
995 {
996 printf("%3d: %#B '%s'\n", kid, &keyid, owner);
997 kid_old = kid;
998 }
999 printf("%5d %02d %#B\n", seq_no, pcr, &hash);
1000 count++;
1001 }
1002 e->destroy(e);
1003
1004 printf("%d %N value%s found for component '%s'\n", count,
1005 hash_algorithm_names, pts_meas_algo_to_hash(this->algo),
1006 (count == 1) ? "" : "s", print_cfn(this->cfn));
1007 }
1008
1009 }
1010 else if (this->kid)
1011 {
1012 e = this->db->query(this->db,
1013 "SELECT ch.seq_no, ch.pcr, ch.hash, "
1014 "c.id, c.vendor_id, c.name, c.qualifier "
1015 "FROM component_hashes AS ch "
1016 "JOIN components AS c ON c.id = ch.component "
1017 "WHERE ch.algo = ? AND ch.key = ? "
1018 "ORDER BY vendor_id, name, qualifier, seq_no",
1019 DB_INT, this->algo, DB_INT, this->kid, DB_INT, DB_INT, DB_BLOB,
1020 DB_INT, DB_INT, DB_INT, DB_INT);
1021 if (e)
1022 {
1023 while (e->enumerate(e, &seq_no, &pcr, &hash, &cid, &vid, &name,
1024 &qualifier))
1025 {
1026 if (cid != cid_old)
1027 {
1028 cfn = pts_comp_func_name_create(vid, name, qualifier);
1029 printf("%3d: %s\n", cid, print_cfn(cfn));
1030 cfn->destroy(cfn);
1031 cid_old = cid;
1032 }
1033 printf("%5d %02d %#B\n", seq_no, pcr, &hash);
1034 count++;
1035 }
1036 e->destroy(e);
1037
1038 printf("%d %N value%s found for key %#B '%s'\n", count,
1039 hash_algorithm_names, pts_meas_algo_to_hash(this->algo),
1040 (count == 1) ? "" : "s", &this->key, this->owner);
1041 }
1042 }
1043 }
1044
1045 METHOD(attest_db_t, add, bool,
1046 private_attest_db_t *this)
1047 {
1048 bool success = FALSE;
1049
1050 if (this->kid && this->cid)
1051 {
1052 success = this->db->execute(this->db, NULL,
1053 "INSERT INTO key_component (key, component) VALUES (?, ?)",
1054 DB_UINT, this->kid, DB_UINT, this->cid) == 1;
1055
1056 printf("key/component pair (%d/%d) %sinserted into database\n",
1057 this->kid, this->cid, success ? "" : "could not be ");
1058 }
1059 return success;
1060 }
1061
1062 METHOD(attest_db_t, delete, bool,
1063 private_attest_db_t *this)
1064 {
1065 bool success;
1066
1067 if (this->pid && (this->fid || this->did))
1068 {
1069 printf("deletion of product/file entries not supported yet\n");
1070 return FALSE;
1071 }
1072
1073 if (this->kid && this->cid)
1074 {
1075 success = this->db->execute(this->db, NULL,
1076 "DELETE FROM key_component "
1077 "WHERE key = ? AND component = ?",
1078 DB_UINT, this->kid, DB_UINT, this->cid) > 0;
1079
1080 printf("key/component pair (%d/%d) %sdeleted from database\n",
1081 this->kid, this->cid, success ? "" : "could not be ");
1082 return success;
1083 }
1084
1085 if (this->cid)
1086 {
1087 success = this->db->execute(this->db, NULL,
1088 "DELETE FROM components WHERE id = ?",
1089 DB_UINT, this->cid) > 0;
1090
1091 printf("component '%s' %sdeleted from database\n", print_cfn(this->cfn),
1092 success ? "" : "could not be ");
1093 return success;
1094 }
1095
1096 if (this->did)
1097 {
1098 success = this->db->execute(this->db, NULL,
1099 "DELETE FROM files WHERE type = 1 AND id = ?",
1100 DB_UINT, this->did) > 0;
1101
1102 printf("directory '%s' %sdeleted from database\n", this->dir,
1103 success ? "" : "could not be ");
1104 return success;
1105 }
1106
1107 if (this->fid)
1108 {
1109 success = this->db->execute(this->db, NULL,
1110 "DELETE FROM files WHERE id = ?",
1111 DB_UINT, this->fid) > 0;
1112
1113 printf("file '%s' %sdeleted from database\n", this->file,
1114 success ? "" : "could not be ");
1115 return success;
1116 }
1117
1118 if (this->kid)
1119 {
1120 success = this->db->execute(this->db, NULL,
1121 "DELETE FROM keys WHERE id = ?",
1122 DB_UINT, this->kid) > 0;
1123
1124 printf("key %#B %sdeleted from database\n", &this->key,
1125 success ? "" : "could not be ");
1126 return success;
1127 }
1128 if (this->pid)
1129 {
1130 success = this->db->execute(this->db, NULL,
1131 "DELETE FROM products WHERE id = ?",
1132 DB_UINT, this->pid) > 0;
1133
1134 printf("product '%s' %sdeleted from database\n", this->product,
1135 success ? "" : "could not be ");
1136 return success;
1137 }
1138
1139 printf("empty delete command\n");
1140 return FALSE;
1141 }
1142
1143 METHOD(attest_db_t, destroy, void,
1144 private_attest_db_t *this)
1145 {
1146 DESTROY_IF(this->db);
1147 DESTROY_IF(this->cfn);
1148 free(this->product);
1149 free(this->file);
1150 free(this->dir);
1151 free(this->owner);
1152 free(this->key.ptr);
1153 free(this);
1154 }
1155
1156 /**
1157 * Described in header.
1158 */
1159 attest_db_t *attest_db_create(char *uri)
1160 {
1161 private_attest_db_t *this;
1162
1163 INIT(this,
1164 .public = {
1165 .set_component = _set_component,
1166 .set_cid = _set_cid,
1167 .set_directory = _set_directory,
1168 .set_did = _set_did,
1169 .set_file = _set_file,
1170 .set_fid = _set_fid,
1171 .set_key = _set_key,
1172 .set_kid = _set_kid,
1173 .set_product = _set_product,
1174 .set_pid = _set_pid,
1175 .set_algo = _set_algo,
1176 .set_owner = _set_owner,
1177 .list_products = _list_products,
1178 .list_files = _list_files,
1179 .list_components = _list_components,
1180 .list_keys = _list_keys,
1181 .list_hashes = _list_hashes,
1182 .list_measurements = _list_measurements,
1183 .add = _add,
1184 .delete = _delete,
1185 .destroy = _destroy,
1186 },
1187 .dir = strdup(""),
1188 .algo = PTS_MEAS_ALGO_SHA256,
1189 .db = lib->db->create(lib->db, uri),
1190 );
1191
1192 if (!this->db)
1193 {
1194 fprintf(stderr, "opening database failed.\n");
1195 destroy(this);
1196 return NULL;
1197 }
1198
1199 return &this->public;
1200 }