2 * Copyright (C) 2011-2012 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
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>.
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
16 #include "attest_db.h"
19 #include "pts/pts_meas_algo.h"
20 #include "pts/pts_file_meas.h"
21 #include "pts/components/pts_comp_func_name.h"
26 #define IMA_MAX_NAME_LEN 255
28 typedef struct private_attest_db_t private_attest_db_t
;
31 * Private data of an attest_db_t object.
33 struct private_attest_db_t
{
36 * Public members of attest_db_state_t
41 * Component Functional Name to be queried
43 pts_comp_func_name_t
*cfn
;
46 * Primary key of the Component Functional Name to be queried
51 * TRUE if Component Functional Name has been set
56 * Directory containing the Measurement file to be queried
61 * Primary key of the directory to be queried
66 * TRUE if directory has been set
71 * Measurement file to be queried
76 * Primary key of measurement file to be queried
81 * TRUE if file has been set
91 * Primary key of the AIK to be queried
96 * TRUE if AIK has been set
101 * Software package to be queried
106 * Primary key of software package to be queried
111 * TRUE if package has been set
116 * Software product to be queried
121 * Primary key of software product to be queried
126 * TRUE if product has been set
131 * Software package version to be queried
136 * TRUE if version has been set
141 * TRUE if relative filenames are to be used
146 * Package security state
148 os_package_state_t security
;
151 * Sequence number for ordering entries
156 * File measurement hash algorithm
158 pts_meas_algorithms_t algo
;
161 * Optional owner (user/host name)
166 * Attestation database
172 char* print_cfn(pts_comp_func_name_t
*cfn
)
174 static char buf
[BUF_LEN
];
176 int type
, vid
, name
, qualifier
, n
;
177 enum_name_t
*names
, *types
;
179 vid
= cfn
->get_vendor_id(cfn
),
180 name
= cfn
->get_name(cfn
);
181 qualifier
= cfn
->get_qualifier(cfn
);
182 n
= snprintf(buf
, BUF_LEN
, "0x%06x/0x%08x-0x%02x", vid
, name
, qualifier
);
184 names
= pts_components
->get_comp_func_names(pts_components
, vid
);
185 types
= pts_components
->get_qualifier_type_names(pts_components
, vid
);
186 type
= pts_components
->get_qualifier(pts_components
, cfn
, flags
);
189 n
= snprintf(buf
+ n
, BUF_LEN
- n
, " %N/%N [%s] %N",
190 pen_names
, vid
, names
, name
, flags
, types
, type
);
195 METHOD(attest_db_t
, set_component
, bool,
196 private_attest_db_t
*this, char *comp
, bool create
)
200 int vid
, name
, qualifier
;
201 pts_comp_func_name_t
*cfn
;
205 printf("component has already been set\n");
209 /* parse component string */
210 pos1
= strchr(comp
, '/');
211 pos2
= strchr(comp
, '-');
214 printf("component string must have the form \"vendor_id/name-qualifier\"\n");
218 name
= atoi(pos1
+ 1);
219 qualifier
= atoi(pos2
+ 1);
220 cfn
= pts_comp_func_name_create(vid
, name
, qualifier
);
222 e
= this->db
->query(this->db
,
223 "SELECT id FROM components "
224 "WHERE vendor_id = ? AND name = ? AND qualifier = ?",
225 DB_UINT
, vid
, DB_INT
, name
, DB_INT
, qualifier
, DB_INT
);
228 if (e
->enumerate(e
, &this->cid
))
230 this->comp_set
= TRUE
;
242 printf("component '%s' not found in database\n", print_cfn(cfn
));
247 /* Add a new database entry */
248 this->comp_set
= this->db
->execute(this->db
, &this->cid
,
249 "INSERT INTO components (vendor_id, name, qualifier) "
251 DB_INT
, vid
, DB_INT
, name
, DB_INT
, qualifier
) == 1;
253 printf("component '%s' %sinserted into database\n", print_cfn(cfn
),
254 this->comp_set ?
"" : "could not be ");
263 return this->comp_set
;
266 METHOD(attest_db_t
, set_cid
, bool,
267 private_attest_db_t
*this, int cid
)
270 int vid
, name
, qualifier
;
274 printf("component has already been set\n");
279 e
= this->db
->query(this->db
, "SELECT vendor_id, name, qualifier "
280 "FROM components WHERE id = ?",
281 DB_UINT
, cid
, DB_INT
, DB_INT
, DB_INT
);
284 if (e
->enumerate(e
, &vid
, &name
, &qualifier
))
286 this->cfn
= pts_comp_func_name_create(vid
, name
, qualifier
);
287 this->comp_set
= TRUE
;
291 printf("no component found with cid %d\n", cid
);
295 return this->comp_set
;
298 METHOD(attest_db_t
, set_directory
, bool,
299 private_attest_db_t
*this, char *dir
, bool create
)
306 printf("directory has already been set\n");
311 /* remove trailing '/' character */
313 if (len
&& dir
[len
-1] == '/')
317 this->dir
= strdup(dir
);
319 e
= this->db
->query(this->db
,
320 "SELECT id FROM files WHERE type = 1 AND path = ?",
321 DB_TEXT
, dir
, DB_INT
);
324 if (e
->enumerate(e
, &this->did
))
326 this->dir_set
= TRUE
;
337 printf("directory '%s' not found in database\n", dir
);
341 /* Add a new database entry */
342 this->dir_set
= this->db
->execute(this->db
, &this->did
,
343 "INSERT INTO files (type, path) VALUES (1, ?)",
346 printf("directory '%s' %sinserted into database\n", dir
,
347 this->dir_set ?
"" : "could not be ");
349 return this->dir_set
;
352 METHOD(attest_db_t
, set_did
, bool,
353 private_attest_db_t
*this, int did
)
360 printf("directory has already been set\n");
365 e
= this->db
->query(this->db
, "SELECT path FROM files WHERE id = ?",
366 DB_UINT
, did
, DB_TEXT
);
369 if (e
->enumerate(e
, &dir
))
372 this->dir
= strdup(dir
);
373 this->dir_set
= TRUE
;
377 printf("no directory found with did %d\n", did
);
381 return this->dir_set
;
384 METHOD(attest_db_t
, set_file
, bool,
385 private_attest_db_t
*this, char *file
, bool create
)
392 printf("file has already been set\n");
395 this->file
= strdup(file
);
396 filename
= this->relative ?
basename(file
) : file
;
398 e
= this->db
->query(this->db
, "SELECT id FROM files WHERE path = ?",
399 DB_TEXT
, filename
, DB_INT
);
402 if (e
->enumerate(e
, &this->fid
))
404 this->file_set
= TRUE
;
415 printf("file '%s' not found in database\n", file
);
419 /* Add a new database entry */
420 this->file_set
= this->db
->execute(this->db
, &this->fid
,
421 "INSERT INTO files (type, path) VALUES (0, ?)",
422 DB_TEXT
, filename
) == 1;
424 printf("file '%s' %sinserted into database\n", filename
,
425 this->file_set ?
"" : "could not be ");
427 return this->file_set
;
430 METHOD(attest_db_t
, set_fid
, bool,
431 private_attest_db_t
*this, int fid
)
438 printf("file has already been set\n");
443 e
= this->db
->query(this->db
, "SELECT path FROM files WHERE id = ?",
444 DB_UINT
, fid
, DB_TEXT
);
447 if (e
->enumerate(e
, &file
))
449 this->file
= strdup(file
);
450 this->file_set
= TRUE
;
454 printf("no file found with fid %d\n", fid
);
458 return this->file_set
;
461 METHOD(attest_db_t
, set_key
, bool,
462 private_attest_db_t
*this, chunk_t key
, bool create
)
469 printf("key has already been set\n");
474 e
= this->db
->query(this->db
, "SELECT id, owner FROM keys WHERE keyid= ?",
475 DB_BLOB
, this->key
, DB_INT
, DB_TEXT
);
478 if (e
->enumerate(e
, &this->kid
, &owner
))
481 this->owner
= strdup(owner
);
482 this->key_set
= TRUE
;
493 printf("key '%#B' not found in database\n", &this->key
);
497 /* Add a new database entry */
500 this->owner
= strdup("");
502 this->key_set
= this->db
->execute(this->db
, &this->kid
,
503 "INSERT INTO keys (keyid, owner) VALUES (?, ?)",
504 DB_BLOB
, this->key
, DB_TEXT
, this->owner
) == 1;
506 printf("key '%#B' %sinserted into database\n", &this->key
,
507 this->key_set ?
"" : "could not be ");
509 return this->key_set
;
513 METHOD(attest_db_t
, set_kid
, bool,
514 private_attest_db_t
*this, int kid
)
522 printf("key has already been set\n");
527 e
= this->db
->query(this->db
, "SELECT keyid, owner FROM keys WHERE id = ?",
528 DB_UINT
, kid
, DB_BLOB
, DB_TEXT
);
531 if (e
->enumerate(e
, &key
, &owner
))
533 this->owner
= strdup(owner
);
534 this->key
= chunk_clone(key
);
535 this->key_set
= TRUE
;
539 printf("no key found with kid %d\n", kid
);
543 return this->key_set
;
547 METHOD(attest_db_t
, set_product
, bool,
548 private_attest_db_t
*this, char *product
, bool create
)
552 if (this->product_set
)
554 printf("product has already been set\n");
557 this->product
= strdup(product
);
559 e
= this->db
->query(this->db
, "SELECT id FROM products WHERE name = ?",
560 DB_TEXT
, product
, DB_INT
);
563 if (e
->enumerate(e
, &this->pid
))
565 this->product_set
= TRUE
;
569 if (this->product_set
)
576 printf("product '%s' not found in database\n", product
);
580 /* Add a new database entry */
581 this->product_set
= this->db
->execute(this->db
, &this->pid
,
582 "INSERT INTO products (name) VALUES (?)",
583 DB_TEXT
, product
) == 1;
585 printf("product '%s' %sinserted into database\n", product
,
586 this->product_set ?
"" : "could not be ");
588 return this->product_set
;
591 METHOD(attest_db_t
, set_pid
, bool,
592 private_attest_db_t
*this, int pid
)
597 if (this->product_set
)
599 printf("product has already been set\n");
604 e
= this->db
->query(this->db
, "SELECT name FROM products WHERE id = ?",
605 DB_UINT
, pid
, DB_TEXT
);
608 if (e
->enumerate(e
, &product
))
610 this->product
= strdup(product
);
611 this->product_set
= TRUE
;
615 printf("no product found with pid %d in database\n", pid
);
619 return this->product_set
;
622 METHOD(attest_db_t
, set_package
, bool,
623 private_attest_db_t
*this, char *package
, bool create
)
627 if (this->package_set
)
629 printf("package has already been set\n");
632 this->package
= strdup(package
);
634 e
= this->db
->query(this->db
, "SELECT id FROM packages WHERE name = ?",
635 DB_TEXT
, package
, DB_INT
);
638 if (e
->enumerate(e
, &this->gid
))
640 this->package_set
= TRUE
;
644 if (this->package_set
)
651 printf("package '%s' not found in database\n", package
);
655 /* Add a new database entry */
656 this->package_set
= this->db
->execute(this->db
, &this->gid
,
657 "INSERT INTO packages (name) VALUES (?)",
658 DB_TEXT
, package
) == 1;
660 printf("package '%s' %sinserted into database\n", package
,
661 this->package_set ?
"" : "could not be ");
663 return this->package_set
;
666 METHOD(attest_db_t
, set_gid
, bool,
667 private_attest_db_t
*this, int gid
)
672 if (this->package_set
)
674 printf("package has already been set\n");
679 e
= this->db
->query(this->db
, "SELECT name FROM packages WHERE id = ?",
680 DB_UINT
, gid
, DB_TEXT
);
683 if (e
->enumerate(e
, &package
))
685 this->package
= strdup(package
);
686 this->package_set
= TRUE
;
690 printf("no package found with gid %d in database\n", gid
);
694 return this->package_set
;
697 METHOD(attest_db_t
, set_version
, bool,
698 private_attest_db_t
*this, char *version
)
700 if (this->version_set
)
702 printf("version has already been set\n");
705 this->version
= strdup(version
);
706 this->version_set
= TRUE
;
712 METHOD(attest_db_t
, set_algo
, void,
713 private_attest_db_t
*this, pts_meas_algorithms_t algo
)
718 METHOD(attest_db_t
, set_relative
, void,
719 private_attest_db_t
*this)
721 this->relative
= TRUE
;
724 METHOD(attest_db_t
, set_security
, void,
725 private_attest_db_t
*this, os_package_state_t security
)
727 this->security
= security
;
730 METHOD(attest_db_t
, set_sequence
, void,
731 private_attest_db_t
*this, int seq_no
)
733 this->seq_no
= seq_no
;
736 METHOD(attest_db_t
, set_owner
, void,
737 private_attest_db_t
*this, char *owner
)
740 this->owner
= strdup(owner
);
743 METHOD(attest_db_t
, list_components
, void,
744 private_attest_db_t
*this)
747 pts_comp_func_name_t
*cfn
;
748 int seq_no
, cid
, vid
, name
, qualifier
, count
= 0;
752 e
= this->db
->query(this->db
,
753 "SELECT kc.seq_no, c.id, c.vendor_id, c.name, c.qualifier "
754 "FROM components AS c "
755 "JOIN key_component AS kc ON c.id = kc.component "
756 "WHERE kc.key = ? ORDER BY kc.seq_no",
757 DB_UINT
, this->kid
, DB_INT
, DB_INT
, DB_INT
, DB_INT
, DB_INT
);
760 while (e
->enumerate(e
, &cid
, &seq_no
, &vid
, &name
, &qualifier
))
762 cfn
= pts_comp_func_name_create(vid
, name
, qualifier
);
763 printf("%4d: #%-2d %s\n", seq_no
, cid
, print_cfn(cfn
));
768 printf("%d component%s found for key %#B\n", count
,
769 (count
== 1) ?
"" : "s", &this->key
);
774 e
= this->db
->query(this->db
,
775 "SELECT id, vendor_id, name, qualifier FROM components "
776 "ORDER BY vendor_id, name, qualifier",
777 DB_INT
, DB_INT
, DB_INT
, DB_INT
);
780 while (e
->enumerate(e
, &cid
, &vid
, &name
, &qualifier
))
782 cfn
= pts_comp_func_name_create(vid
, name
, qualifier
);
783 printf("%4d: %s\n", cid
, print_cfn(cfn
));
788 printf("%d component%s found\n", count
, (count
== 1) ?
"" : "s");
793 METHOD(attest_db_t
, list_devices
, void,
794 private_attest_db_t
*this)
800 int id
, last_id
= 0, device_count
= 0;
801 int count
, count_update
, count_blacklist
;
803 e
= this->db
->query(this->db
,
804 "SELECT d.id, d.value, i.time, i.count, i.count_update, "
805 "i.count_blacklist, p.name FROM devices AS d "
806 "JOIN device_infos AS i ON d.id = i.device "
807 "JOIN products AS p ON p.id = i.product "
808 "ORDER BY d.value, i.time DESC",
809 DB_INT
, DB_BLOB
, DB_UINT
, DB_INT
, DB_INT
, DB_INT
, DB_TEXT
);
813 while (e
->enumerate(e
, &id
, &value
, ×tamp
, &count
, &count_update
,
814 &count_blacklist
, &product
))
818 printf("%4d: %.*s\n", id
, value
.len
, value
.ptr
);
822 printf(" %T, %4d, %3d, %3d, '%s'\n", ×tamp
, TRUE
,
823 count
, count_update
, count_blacklist
, product
);
826 printf("%d device%s found\n", device_count
,
827 (device_count
== 1) ?
"" : "s");
831 METHOD(attest_db_t
, list_keys
, void,
832 private_attest_db_t
*this)
841 e
= this->db
->query(this->db
,
842 "SELECT k.id, k.keyid, k.owner FROM keys AS k "
843 "JOIN key_component AS kc ON k.id = kc.key "
844 "WHERE kc.component = ? ORDER BY k.keyid",
845 DB_UINT
, this->cid
, DB_INT
, DB_BLOB
, DB_TEXT
);
848 while (e
->enumerate(e
, &kid
, &keyid
, &owner
))
850 printf("%4d: %#B '%s'\n", kid
, &keyid
, owner
);
858 e
= this->db
->query(this->db
, "SELECT id, keyid, owner FROM keys "
860 DB_INT
, DB_BLOB
, DB_TEXT
);
863 while (e
->enumerate(e
, &kid
, &keyid
, &owner
))
865 printf("%4d: %#B '%s'\n", kid
, &keyid
, owner
);
872 printf("%d key%s found", count
, (count
== 1) ?
"" : "s");
875 printf(" for component '%s'", print_cfn(this->cfn
));
880 METHOD(attest_db_t
, list_files
, void,
881 private_attest_db_t
*this)
884 char *file
, *file_type
[] = { " ", "d", "r" };
885 int fid
, type
, meas
, meta
, count
= 0;
889 e
= this->db
->query(this->db
,
890 "SELECT f.id, f.type, f.path, pf.measurement, pf.metadata "
892 "JOIN product_file AS pf ON f.id = pf.file "
893 "WHERE pf.product = ? ORDER BY f.path",
894 DB_UINT
, this->pid
, DB_INT
, DB_INT
, DB_TEXT
, DB_INT
, DB_INT
);
897 while (e
->enumerate(e
, &fid
, &type
, &file
, &meas
, &meta
))
899 type
= (type
< 0 || type
> 2) ?
0 : type
;
900 printf("%4d: |%s%s| %s %s\n", fid
, meas ?
"M":" ", meta ?
"T":" ",
901 file_type
[type
], file
);
909 e
= this->db
->query(this->db
,
910 "SELECT id, type, path FROM files "
912 DB_INT
, DB_INT
, DB_TEXT
);
915 while (e
->enumerate(e
, &fid
, &type
, &file
))
917 type
= (type
< 0 || type
> 2) ?
0 : type
;
918 printf("%4d: %s %s\n", fid
, file_type
[type
], file
);
925 printf("%d file%s found", count
, (count
== 1) ?
"" : "s");
926 if (this->product_set
)
928 printf(" for product '%s'", this->product
);
933 METHOD(attest_db_t
, list_packages
, void,
934 private_attest_db_t
*this)
937 char *package
, *version
;
938 os_package_state_t security
;
939 int gid
, gid_old
= 0, spaces
, count
= 0;
944 e
= this->db
->query(this->db
,
945 "SELECT p.id, p.name, v.release, v.security, v.time "
946 "FROM packages AS p JOIN versions AS v ON v.package = p.id "
947 "WHERE v.product = ? ORDER BY p.name, v.release",
948 DB_INT
, this->pid
, DB_INT
, DB_TEXT
, DB_TEXT
, DB_INT
, DB_INT
);
951 while (e
->enumerate(e
, &gid
, &package
, &version
, &security
, &t
))
955 printf("%5d: %s,", gid
, package
);
960 spaces
= 8 + strlen(package
);
966 printf(" %T (%s)%N\n", &t
, TRUE
, version
,
967 os_package_state_names
, security
);
975 e
= this->db
->query(this->db
, "SELECT id, name FROM packages "
980 while (e
->enumerate(e
, &gid
, &package
))
982 printf("%4d: %s\n", gid
, package
);
989 printf("%d package%s found", count
, (count
== 1) ?
"" : "s");
990 if (this->product_set
)
992 printf(" for product '%s'", this->product
);
997 METHOD(attest_db_t
, list_products
, void,
998 private_attest_db_t
*this)
1002 int pid
, meas
, meta
, count
= 0;
1006 e
= this->db
->query(this->db
,
1007 "SELECT p.id, p.name, pf.measurement, pf.metadata "
1008 "FROM products AS p "
1009 "JOIN product_file AS pf ON p.id = pf.product "
1010 "WHERE pf.file = ? ORDER BY p.name",
1011 DB_UINT
, this->fid
, DB_INT
, DB_TEXT
, DB_INT
, DB_INT
);
1014 while (e
->enumerate(e
, &pid
, &product
, &meas
, &meta
))
1016 printf("%4d: |%s%s| %s\n", pid
, meas ?
"M":" ", meta ?
"T":" ",
1025 e
= this->db
->query(this->db
, "SELECT id, name FROM products "
1030 while (e
->enumerate(e
, &pid
, &product
))
1032 printf("%4d: %s\n", pid
, product
);
1039 printf("%d product%s found", count
, (count
== 1) ?
"" : "s");
1042 printf(" for file '%s'", this->file
);
1048 * get the directory if there is one from the files tables
1050 static void get_directory(private_attest_db_t
*this, int did
, char **directory
)
1056 *directory
= strdup("");
1060 e
= this->db
->query(this->db
,
1061 "SELECT path from files WHERE id = ?",
1062 DB_UINT
, did
, DB_TEXT
);
1065 if (e
->enumerate(e
, &dir
))
1068 *directory
= strdup(dir
);
1075 static bool slash(char *directory
, char *file
)
1077 return *file
!= '/' && directory
[max(0, strlen(directory
)-1)] != '/';
1080 METHOD(attest_db_t
, list_hashes
, void,
1081 private_attest_db_t
*this)
1085 char *file
, *dir
, *product
;
1086 int fid
, fid_old
= 0, did
, did_old
= 0, count
= 0;
1090 if (this->pid
&& this->fid
& this->did
)
1092 e
= this->db
->query(this->db
,
1093 "SELECT hash FROM file_hashes "
1094 "WHERE algo = ? AND file = ? AND directory = ? AND product = ?",
1095 DB_INT
, this->algo
, DB_INT
, this->fid
, DB_INT
, this->did
,
1096 DB_INT
, this->pid
, DB_BLOB
);
1099 while (e
->enumerate(e
, &hash
))
1101 if (this->fid
!= fid_old
)
1103 printf("%4d: %s%s%s\n", this->fid
, this->dir
,
1104 slash(this->dir
, this->file
) ?
"/" : "", this->file
);
1105 fid_old
= this->fid
;
1107 printf(" %#B\n", &hash
);
1112 printf("%d %N value%s found for product '%s'\n", count
,
1113 pts_meas_algorithm_names
, this->algo
,
1114 (count
== 1) ?
"" : "s", this->product
);
1117 else if (this->pid
&& this->fid
)
1119 e
= this->db
->query(this->db
,
1120 "SELECT f.path, fh.hash FROM file_hashes AS fh "
1121 "JOIN files AS f ON f.id = fh.file "
1122 "WHERE algo = ? AND file = ? AND product = ?",
1123 DB_INT
, this->algo
, DB_INT
, this->fid
, DB_INT
, this->pid
,
1128 while (e
->enumerate(e
, &dir
, &hash
))
1130 printf("%4d: %s%s%s\n", this->fid
, dir
,
1131 slash(dir
, this->file
) ?
"/" : "", this->file
);
1132 printf(" %#B\n", &hash
);
1137 printf("%d %N value%s found for product '%s'\n", count
,
1138 pts_meas_algorithm_names
, this->algo
,
1139 (count
== 1) ?
"" : "s", this->product
);
1145 e
= this->db
->query(this->db
,
1146 "SELECT f.id, f. f.path, fh.hash, fh.directory "
1147 "FROM file_hashes AS fh "
1148 "JOIN files AS f ON f.id = fh.file "
1149 "WHERE fh.algo = ? AND fh.product = ? "
1150 "ORDER BY fh.directory, f.path",
1151 DB_INT
, this->algo
, DB_UINT
, this->pid
,
1152 DB_INT
, DB_TEXT
, DB_BLOB
, DB_INT
);
1155 while (e
->enumerate(e
, &fid
, &file
, &hash
, &did
))
1157 if (fid
!= fid_old
|| did
!= did_old
)
1161 get_directory(this, did
, &dir
);
1163 printf("%4d: %s%s%s\n", fid
,
1164 dir
, slash(dir
, file
) ?
"/" : "", file
);
1168 printf(" %#B\n", &hash
);
1173 printf("%d %N value%s found for product '%s'\n", count
,
1174 pts_meas_algorithm_names
, this->algo
,
1175 (count
== 1) ?
"" : "s", this->product
);
1180 e
= this->db
->query(this->db
,
1181 "SELECT p.name, fh.hash, fh.directory "
1182 "FROM file_hashes AS fh "
1183 "JOIN products AS p ON p.id = fh.product "
1184 "WHERE fh.algo = ? AND fh.file = ? AND fh.directory = ?"
1186 DB_INT
, this->algo
, DB_UINT
, this->fid
, DB_UINT
, this->did
,
1187 DB_TEXT
, DB_BLOB
, DB_INT
);
1190 while (e
->enumerate(e
, &product
, &hash
, &did
))
1192 printf("%#B '%s'\n", &hash
, product
);
1197 printf("%d %N value%s found for file '%s%s%s'\n",
1198 count
, pts_meas_algorithm_names
, this->algo
,
1199 (count
== 1) ?
"" : "s", this->dir
,
1200 slash(this->dir
, this->file
) ?
"/" : "", this->file
);
1205 e
= this->db
->query(this->db
,
1206 "SELECT f.id, f.path, p.name, fh.hash, fh.directory "
1207 "FROM file_hashes AS fh "
1208 "JOIN files AS f ON f.id = fh.file "
1209 "JOIN products AS p ON p.id = fh.product "
1210 "WHERE fh.algo = ? "
1211 "ORDER BY fh.directory, f.path, p.name",
1213 DB_INT
, DB_TEXT
, DB_TEXT
, DB_BLOB
, DB_INT
);
1216 while (e
->enumerate(e
, &fid
, &file
, &product
, &hash
, &did
))
1218 if (fid
!= fid_old
|| did
!= did_old
)
1222 get_directory(this, did
, &dir
);
1225 printf("%4d: %s%s%s\n", fid
,
1226 dir
, slash(dir
, file
) ?
"/" : "", file
);
1229 printf(" %#B '%s'\n", &hash
, product
);
1234 printf("%d %N value%s found\n", count
, pts_meas_algorithm_names
,
1235 this->algo
, (count
== 1) ?
"" : "s");
1241 METHOD(attest_db_t
, list_measurements
, void,
1242 private_attest_db_t
*this)
1245 chunk_t hash
, keyid
;
1246 pts_comp_func_name_t
*cfn
;
1248 int seq_no
, pcr
, vid
, name
, qualifier
;
1249 int cid
, cid_old
= 0, kid
, kid_old
= 0, count
= 0;
1251 if (this->kid
&& this->cid
)
1253 e
= this->db
->query(this->db
,
1254 "SELECT ch.seq_no, ch.pcr, ch.hash, k.owner "
1255 "FROM component_hashes AS ch "
1256 "JOIN keys AS k ON k.id = ch.key "
1257 "WHERE ch.algo = ? AND ch.key = ? AND ch.component = ? "
1259 DB_INT
, this->algo
, DB_UINT
, this->kid
, DB_UINT
, this->cid
,
1260 DB_INT
, DB_INT
, DB_BLOB
, DB_TEXT
);
1263 while (e
->enumerate(e
, &seq_no
, &pcr
, &hash
, &owner
))
1265 if (this->kid
!= kid_old
)
1267 printf("%4d: %#B '%s'\n", this->kid
, &this->key
, owner
);
1268 kid_old
= this->kid
;
1270 printf("%7d %02d %#B\n", seq_no
, pcr
, &hash
);
1275 printf("%d %N value%s found for component '%s'\n", count
,
1276 pts_meas_algorithm_names
, this->algo
,
1277 (count
== 1) ?
"" : "s", print_cfn(this->cfn
));
1282 e
= this->db
->query(this->db
,
1283 "SELECT ch.seq_no, ch.pcr, ch.hash, k.id, k.keyid, k.owner "
1284 "FROM component_hashes AS ch "
1285 "JOIN keys AS k ON k.id = ch.key "
1286 "WHERE ch.algo = ? AND ch.component = ? "
1287 "ORDER BY keyid, seq_no",
1288 DB_INT
, this->algo
, DB_UINT
, this->cid
,
1289 DB_INT
, DB_INT
, DB_BLOB
, DB_INT
, DB_BLOB
, DB_TEXT
);
1292 while (e
->enumerate(e
, &seq_no
, &pcr
, &hash
, &kid
, &keyid
, &owner
))
1296 printf("%4d: %#B '%s'\n", kid
, &keyid
, owner
);
1299 printf("%7d %02d %#B\n", seq_no
, pcr
, &hash
);
1304 printf("%d %N value%s found for component '%s'\n", count
,
1305 pts_meas_algorithm_names
, this->algo
,
1306 (count
== 1) ?
"" : "s", print_cfn(this->cfn
));
1312 e
= this->db
->query(this->db
,
1313 "SELECT ch.seq_no, ch.pcr, ch.hash, "
1314 "c.id, c.vendor_id, c.name, c.qualifier "
1315 "FROM component_hashes AS ch "
1316 "JOIN components AS c ON c.id = ch.component "
1317 "WHERE ch.algo = ? AND ch.key = ? "
1318 "ORDER BY vendor_id, name, qualifier, seq_no",
1319 DB_INT
, this->algo
, DB_UINT
, this->kid
, DB_INT
, DB_INT
, DB_BLOB
,
1320 DB_INT
, DB_INT
, DB_INT
, DB_INT
);
1323 while (e
->enumerate(e
, &seq_no
, &pcr
, &hash
, &cid
, &vid
, &name
,
1328 cfn
= pts_comp_func_name_create(vid
, name
, qualifier
);
1329 printf("%4d: %s\n", cid
, print_cfn(cfn
));
1333 printf("%5d %02d %#B\n", seq_no
, pcr
, &hash
);
1338 printf("%d %N value%s found for key %#B '%s'\n", count
,
1339 pts_meas_algorithm_names
, this->algo
,
1340 (count
== 1) ?
"" : "s", &this->key
, this->owner
);
1345 bool insert_file_hash(private_attest_db_t
*this, pts_meas_algorithms_t algo
,
1346 chunk_t measurement
, int fid
, int did
, bool ima
,
1353 label
= "could not be created";
1355 e
= this->db
->query(this->db
,
1356 "SELECT hash FROM file_hashes WHERE algo = ? "
1357 "AND file = ? AND directory = ? AND product = ? and key = 0",
1358 DB_INT
, algo
, DB_UINT
, fid
, DB_UINT
, did
, DB_UINT
, this->pid
, DB_BLOB
);
1361 printf("file_hashes query failed\n");
1364 if (e
->enumerate(e
, &hash
))
1366 label
= chunk_equals(measurement
, hash
) ?
1367 "exists and equals" : "exists and differs";
1371 if (this->db
->execute(this->db
, NULL
,
1372 "INSERT INTO file_hashes "
1373 "(file, directory, product, key, algo, hash) "
1374 "VALUES (?, ?, ?, 0, ?, ?)",
1375 DB_UINT
, fid
, DB_UINT
, did
, DB_UINT
, this->pid
,
1376 DB_INT
, algo
, DB_BLOB
, measurement
) == 1)
1384 printf(" %#B - %s%s\n", &measurement
, ima ?
"ima - " : "", label
);
1388 METHOD(attest_db_t
, add
, bool,
1389 private_attest_db_t
*this)
1391 bool success
= FALSE
;
1393 /* add key/component pair */
1394 if (this->kid
&& this->cid
)
1396 success
= this->db
->execute(this->db
, NULL
,
1397 "INSERT INTO key_component (key, component, seq_no) "
1399 DB_UINT
, this->kid
, DB_UINT
, this->cid
,
1400 DB_UINT
, this->seq_no
) == 1;
1402 printf("key/component pair (%d/%d) %sinserted into database at "
1403 "position %d\n", this->kid
, this->cid
,
1404 success ?
"" : "could not be ", this->seq_no
);
1409 /* add directory or file measurement for a given product */
1410 if ((this->did
|| this->fid
) && this->pid
)
1412 char *pathname
, *filename
, *label
;
1413 char ima_buffer
[IMA_MAX_NAME_LEN
+ 1];
1414 chunk_t measurement
, ima_template
;
1415 pts_file_meas_t
*measurements
;
1416 hasher_t
*hasher
= NULL
;
1419 int files_added
= 0, hashes_added
= 0, ima_hashes_added
= 0;
1420 enumerator_t
*enumerator
, *e
;
1422 if (this->algo
== PTS_MEAS_ALGO_SHA1_IMA
)
1425 this->algo
= PTS_MEAS_ALGO_SHA1
;
1426 hasher
= lib
->crypto
->create_hasher(lib
->crypto
, HASH_SHA1
);
1429 printf("could not create hasher\n");
1434 pathname
= this->did ?
this->dir
: this->file
;
1435 measurements
= pts_file_meas_create_from_path(0, pathname
, this->did
,
1436 this->relative
, this->algo
);
1439 printf("file measurement failed\n");
1443 if (this->fid
&& this->relative
)
1445 set_directory(this, dirname(pathname
), TRUE
);
1447 did
= this->relative ?
this->did
: 0;
1449 enumerator
= measurements
->create_enumerator(measurements
);
1450 while (enumerator
->enumerate(enumerator
, &filename
, &measurement
))
1452 /* retrieve or create filename */
1453 label
= "could not be created";
1455 e
= this->db
->query(this->db
,
1456 "SELECT id FROM files WHERE path = ?",
1457 DB_TEXT
, filename
, DB_INT
);
1460 printf("files query failed\n");
1463 if (e
->enumerate(e
, &fid
))
1469 if (this->db
->execute(this->db
, &fid
,
1470 "INSERT INTO files (type, path) VALUES (0, ?)",
1471 DB_TEXT
, filename
) == 1)
1479 printf("%4d: %s - %s\n", fid
, filename
, label
);
1481 /* compute file measurement hash */
1482 if (!insert_file_hash(this, this->algo
, measurement
,
1483 fid
, did
, FALSE
, &hashes_added
))
1493 /* compute IMA template hash */
1494 strncpy(ima_buffer
, filename
, IMA_MAX_NAME_LEN
);
1495 ima_buffer
[IMA_MAX_NAME_LEN
] = '\0';
1496 ima_template
= chunk_create(ima_buffer
, sizeof(ima_buffer
));
1497 if (!hasher
->get_hash(hasher
, measurement
, NULL
) ||
1498 !hasher
->get_hash(hasher
, ima_template
, measurement
.ptr
))
1500 printf("could not compute IMA template hash\n");
1503 if (!insert_file_hash(this, PTS_MEAS_ALGO_SHA1_IMA
, measurement
,
1504 fid
, did
, TRUE
, &ima_hashes_added
))
1509 enumerator
->destroy(enumerator
);
1511 printf("%d measurements, added %d new files, %d new file hashes",
1512 measurements
->get_file_count(measurements
),
1513 files_added
, hashes_added
);
1516 printf(" , %d new ima hashes", ima_hashes_added
);
1517 hasher
->destroy(hasher
);
1520 measurements
->destroy(measurements
);
1524 /* insert package version */
1525 if (this->version_set
&& this->gid
&& this->pid
)
1527 time_t t
= time(NULL
);
1529 success
= this->db
->execute(this->db
, NULL
,
1530 "INSERT INTO versions "
1531 "(package, product, release, security, time) "
1532 "VALUES (?, ?, ?, ?, ?)",
1533 DB_UINT
, this->gid
, DB_UINT
, this->pid
, DB_TEXT
,
1534 this->version
, DB_UINT
, this->security
, DB_INT
, t
) == 1;
1536 printf("'%s' package %s (%s)%N %sinserted into database\n",
1537 this->product
, this->package
, this->version
,
1538 os_package_state_names
, this->security
,
1539 success ?
"" : "could not be ");
1544 METHOD(attest_db_t
, delete, bool,
1545 private_attest_db_t
*this)
1549 /* delete a file measurement hash for a given product */
1550 if (this->algo
&& this->pid
&& this->fid
)
1552 success
= this->db
->execute(this->db
, NULL
,
1553 "DELETE FROM file_hashes "
1554 "WHERE algo = ? AND product = ? "
1555 "AND file = ? AND directory = ?",
1556 DB_UINT
, this->algo
, DB_UINT
, this->pid
,
1557 DB_UINT
, this->fid
, DB_UINT
, this->did
) > 0;
1559 printf("%4d: %s%s%s\n", this->fid
, this->dir
, this->did ?
"/":"",
1561 printf("%N value for product '%s' %sdeleted from database\n",
1562 pts_meas_algorithm_names
, this->algo
, this->product
,
1563 success ?
"" : "could not be ");
1568 /* delete product/file entries */
1569 if (this->pid
&& (this->fid
|| this->did
))
1571 success
= this->db
->execute(this->db
, NULL
,
1572 "DELETE FROM product_file "
1573 "WHERE product = ? AND file = ?",
1575 DB_UINT
, this->fid ?
this->fid
: this->did
) > 0;
1577 printf("product/file pair (%d/%d) %sdeleted from database\n",
1578 this->pid
, this->fid ?
this->fid
: this->did
,
1579 success ?
"" : "could not be ");
1584 /* delete key/component pair */
1585 if (this->kid
&& this->cid
)
1587 success
= this->db
->execute(this->db
, NULL
,
1588 "DELETE FROM key_component "
1589 "WHERE key = ? AND component = ?",
1590 DB_UINT
, this->kid
, DB_UINT
, this->cid
) > 0;
1592 printf("key/component pair (%d/%d) %sdeleted from database\n",
1593 this->kid
, this->cid
, success ?
"" : "could not be ");
1599 success
= this->db
->execute(this->db
, NULL
,
1600 "DELETE FROM components WHERE id = ?",
1601 DB_UINT
, this->cid
) > 0;
1603 printf("component '%s' %sdeleted from database\n", print_cfn(this->cfn
),
1604 success ?
"" : "could not be ");
1610 success
= this->db
->execute(this->db
, NULL
,
1611 "DELETE FROM files WHERE type = 1 AND id = ?",
1612 DB_UINT
, this->did
) > 0;
1614 printf("directory '%s' %sdeleted from database\n", this->dir
,
1615 success ?
"" : "could not be ");
1621 success
= this->db
->execute(this->db
, NULL
,
1622 "DELETE FROM files WHERE id = ?",
1623 DB_UINT
, this->fid
) > 0;
1625 printf("file '%s' %sdeleted from database\n", this->file
,
1626 success ?
"" : "could not be ");
1632 success
= this->db
->execute(this->db
, NULL
,
1633 "DELETE FROM keys WHERE id = ?",
1634 DB_UINT
, this->kid
) > 0;
1636 printf("key %#B %sdeleted from database\n", &this->key
,
1637 success ?
"" : "could not be ");
1642 success
= this->db
->execute(this->db
, NULL
,
1643 "DELETE FROM products WHERE id = ?",
1644 DB_UINT
, this->pid
) > 0;
1646 printf("product '%s' %sdeleted from database\n", this->product
,
1647 success ?
"" : "could not be ");
1651 printf("empty delete command\n");
1655 METHOD(attest_db_t
, destroy
, void,
1656 private_attest_db_t
*this)
1658 DESTROY_IF(this->db
);
1659 DESTROY_IF(this->cfn
);
1660 free(this->package
);
1661 free(this->product
);
1662 free(this->version
);
1666 free(this->key
.ptr
);
1671 * Described in header.
1673 attest_db_t
*attest_db_create(char *uri
)
1675 private_attest_db_t
*this;
1679 .set_component
= _set_component
,
1680 .set_cid
= _set_cid
,
1681 .set_directory
= _set_directory
,
1682 .set_did
= _set_did
,
1683 .set_file
= _set_file
,
1684 .set_fid
= _set_fid
,
1685 .set_key
= _set_key
,
1686 .set_kid
= _set_kid
,
1687 .set_package
= _set_package
,
1688 .set_gid
= _set_gid
,
1689 .set_product
= _set_product
,
1690 .set_pid
= _set_pid
,
1691 .set_version
= _set_version
,
1692 .set_algo
= _set_algo
,
1693 .set_relative
= _set_relative
,
1694 .set_security
= _set_security
,
1695 .set_sequence
= _set_sequence
,
1696 .set_owner
= _set_owner
,
1697 .list_packages
= _list_packages
,
1698 .list_products
= _list_products
,
1699 .list_files
= _list_files
,
1700 .list_components
= _list_components
,
1701 .list_devices
= _list_devices
,
1702 .list_keys
= _list_keys
,
1703 .list_hashes
= _list_hashes
,
1704 .list_measurements
= _list_measurements
,
1707 .destroy
= _destroy
,
1710 .db
= lib
->db
->create(lib
->db
, uri
),
1715 fprintf(stderr
, "opening database failed.\n");
1720 return &this->public;