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
;
802 u_int tstamp
, flags
= 0;
804 e
= this->db
->query(this->db
,
805 "SELECT d.id, d.value, i.time, i.count, i.count_update, "
806 "i.count_blacklist, i.flags, p.name FROM devices AS d "
807 "JOIN device_infos AS i ON d.id = i.device "
808 "JOIN products AS p ON p.id = i.product "
809 "ORDER BY d.value, i.time DESC",
810 DB_INT
, DB_BLOB
, DB_UINT
, DB_INT
, DB_INT
, DB_INT
, DB_UINT
, DB_TEXT
);
814 while (e
->enumerate(e
, &id
, &value
, &tstamp
, &count
, &count_update
,
815 &count_blacklist
, &flags
, &product
))
819 printf("%4d: %.*s\n", id
, value
.len
, value
.ptr
);
824 printf(" %T, %4d, %3d, %3d, %1u, '%s'\n", ×tamp
, TRUE
,
825 count
, count_update
, count_blacklist
, flags
, product
);
828 printf("%d device%s found\n", device_count
,
829 (device_count
== 1) ?
"" : "s");
833 METHOD(attest_db_t
, list_keys
, void,
834 private_attest_db_t
*this)
843 e
= this->db
->query(this->db
,
844 "SELECT k.id, k.keyid, k.owner FROM keys AS k "
845 "JOIN key_component AS kc ON k.id = kc.key "
846 "WHERE kc.component = ? ORDER BY k.keyid",
847 DB_UINT
, this->cid
, DB_INT
, DB_BLOB
, DB_TEXT
);
850 while (e
->enumerate(e
, &kid
, &keyid
, &owner
))
852 printf("%4d: %#B '%s'\n", kid
, &keyid
, owner
);
860 e
= this->db
->query(this->db
, "SELECT id, keyid, owner FROM keys "
862 DB_INT
, DB_BLOB
, DB_TEXT
);
865 while (e
->enumerate(e
, &kid
, &keyid
, &owner
))
867 printf("%4d: %#B '%s'\n", kid
, &keyid
, owner
);
874 printf("%d key%s found", count
, (count
== 1) ?
"" : "s");
877 printf(" for component '%s'", print_cfn(this->cfn
));
882 METHOD(attest_db_t
, list_files
, void,
883 private_attest_db_t
*this)
886 char *file
, *file_type
[] = { " ", "d", "r" };
887 int fid
, type
, meas
, meta
, count
= 0;
891 e
= this->db
->query(this->db
,
892 "SELECT f.id, f.type, f.path, pf.measurement, pf.metadata "
894 "JOIN product_file AS pf ON f.id = pf.file "
895 "WHERE pf.product = ? ORDER BY f.path",
896 DB_UINT
, this->pid
, DB_INT
, DB_INT
, DB_TEXT
, DB_INT
, DB_INT
);
899 while (e
->enumerate(e
, &fid
, &type
, &file
, &meas
, &meta
))
901 type
= (type
< 0 || type
> 2) ?
0 : type
;
902 printf("%4d: |%s%s| %s %s\n", fid
, meas ?
"M":" ", meta ?
"T":" ",
903 file_type
[type
], file
);
911 e
= this->db
->query(this->db
,
912 "SELECT id, type, path FROM files "
914 DB_INT
, DB_INT
, DB_TEXT
);
917 while (e
->enumerate(e
, &fid
, &type
, &file
))
919 type
= (type
< 0 || type
> 2) ?
0 : type
;
920 printf("%4d: %s %s\n", fid
, file_type
[type
], file
);
927 printf("%d file%s found", count
, (count
== 1) ?
"" : "s");
928 if (this->product_set
)
930 printf(" for product '%s'", this->product
);
935 METHOD(attest_db_t
, list_packages
, void,
936 private_attest_db_t
*this)
939 char *package
, *version
;
940 os_package_state_t security
;
941 int gid
, gid_old
= 0, spaces
, count
= 0;
946 e
= this->db
->query(this->db
,
947 "SELECT p.id, p.name, v.release, v.security, v.time "
948 "FROM packages AS p JOIN versions AS v ON v.package = p.id "
949 "WHERE v.product = ? ORDER BY p.name, v.release",
950 DB_INT
, this->pid
, DB_INT
, DB_TEXT
, DB_TEXT
, DB_INT
, DB_INT
);
953 while (e
->enumerate(e
, &gid
, &package
, &version
, &security
, &t
))
957 printf("%5d: %s,", gid
, package
);
962 spaces
= 8 + strlen(package
);
968 printf(" %T (%s)%N\n", &t
, TRUE
, version
,
969 os_package_state_names
, security
);
977 e
= this->db
->query(this->db
, "SELECT id, name FROM packages "
982 while (e
->enumerate(e
, &gid
, &package
))
984 printf("%4d: %s\n", gid
, package
);
991 printf("%d package%s found", count
, (count
== 1) ?
"" : "s");
992 if (this->product_set
)
994 printf(" for product '%s'", this->product
);
999 METHOD(attest_db_t
, list_products
, void,
1000 private_attest_db_t
*this)
1004 int pid
, meas
, meta
, count
= 0;
1008 e
= this->db
->query(this->db
,
1009 "SELECT p.id, p.name, pf.measurement, pf.metadata "
1010 "FROM products AS p "
1011 "JOIN product_file AS pf ON p.id = pf.product "
1012 "WHERE pf.file = ? ORDER BY p.name",
1013 DB_UINT
, this->fid
, DB_INT
, DB_TEXT
, DB_INT
, DB_INT
);
1016 while (e
->enumerate(e
, &pid
, &product
, &meas
, &meta
))
1018 printf("%4d: |%s%s| %s\n", pid
, meas ?
"M":" ", meta ?
"T":" ",
1027 e
= this->db
->query(this->db
, "SELECT id, name FROM products "
1032 while (e
->enumerate(e
, &pid
, &product
))
1034 printf("%4d: %s\n", pid
, product
);
1041 printf("%d product%s found", count
, (count
== 1) ?
"" : "s");
1044 printf(" for file '%s'", this->file
);
1050 * get the directory if there is one from the files tables
1052 static void get_directory(private_attest_db_t
*this, int did
, char **directory
)
1058 *directory
= strdup("");
1062 e
= this->db
->query(this->db
,
1063 "SELECT path from files WHERE id = ?",
1064 DB_UINT
, did
, DB_TEXT
);
1067 if (e
->enumerate(e
, &dir
))
1070 *directory
= strdup(dir
);
1077 static bool slash(char *directory
, char *file
)
1079 return *file
!= '/' && directory
[max(0, strlen(directory
)-1)] != '/';
1082 METHOD(attest_db_t
, list_hashes
, void,
1083 private_attest_db_t
*this)
1087 char *file
, *dir
, *product
;
1088 int fid
, fid_old
= 0, did
, did_old
= 0, count
= 0;
1092 if (this->pid
&& this->fid
& this->did
)
1094 e
= this->db
->query(this->db
,
1095 "SELECT hash FROM file_hashes "
1096 "WHERE algo = ? AND file = ? AND directory = ? AND product = ?",
1097 DB_INT
, this->algo
, DB_INT
, this->fid
, DB_INT
, this->did
,
1098 DB_INT
, this->pid
, DB_BLOB
);
1101 while (e
->enumerate(e
, &hash
))
1103 if (this->fid
!= fid_old
)
1105 printf("%4d: %s%s%s\n", this->fid
, this->dir
,
1106 slash(this->dir
, this->file
) ?
"/" : "", this->file
);
1107 fid_old
= this->fid
;
1109 printf(" %#B\n", &hash
);
1114 printf("%d %N value%s found for product '%s'\n", count
,
1115 pts_meas_algorithm_names
, this->algo
,
1116 (count
== 1) ?
"" : "s", this->product
);
1119 else if (this->pid
&& this->fid
)
1121 e
= this->db
->query(this->db
,
1122 "SELECT f.path, fh.hash FROM file_hashes AS fh "
1123 "JOIN files AS f ON f.id = fh.file "
1124 "WHERE algo = ? AND file = ? AND product = ?",
1125 DB_INT
, this->algo
, DB_INT
, this->fid
, DB_INT
, this->pid
,
1130 while (e
->enumerate(e
, &dir
, &hash
))
1132 printf("%4d: %s%s%s\n", this->fid
, dir
,
1133 slash(dir
, this->file
) ?
"/" : "", this->file
);
1134 printf(" %#B\n", &hash
);
1139 printf("%d %N value%s found for product '%s'\n", count
,
1140 pts_meas_algorithm_names
, this->algo
,
1141 (count
== 1) ?
"" : "s", this->product
);
1147 e
= this->db
->query(this->db
,
1148 "SELECT f.id, f. f.path, fh.hash, fh.directory "
1149 "FROM file_hashes AS fh "
1150 "JOIN files AS f ON f.id = fh.file "
1151 "WHERE fh.algo = ? AND fh.product = ? "
1152 "ORDER BY fh.directory, f.path",
1153 DB_INT
, this->algo
, DB_UINT
, this->pid
,
1154 DB_INT
, DB_TEXT
, DB_BLOB
, DB_INT
);
1157 while (e
->enumerate(e
, &fid
, &file
, &hash
, &did
))
1159 if (fid
!= fid_old
|| did
!= did_old
)
1163 get_directory(this, did
, &dir
);
1165 printf("%4d: %s%s%s\n", fid
,
1166 dir
, slash(dir
, file
) ?
"/" : "", file
);
1170 printf(" %#B\n", &hash
);
1175 printf("%d %N value%s found for product '%s'\n", count
,
1176 pts_meas_algorithm_names
, this->algo
,
1177 (count
== 1) ?
"" : "s", this->product
);
1182 e
= this->db
->query(this->db
,
1183 "SELECT p.name, fh.hash, fh.directory "
1184 "FROM file_hashes AS fh "
1185 "JOIN products AS p ON p.id = fh.product "
1186 "WHERE fh.algo = ? AND fh.file = ? AND fh.directory = ?"
1188 DB_INT
, this->algo
, DB_UINT
, this->fid
, DB_UINT
, this->did
,
1189 DB_TEXT
, DB_BLOB
, DB_INT
);
1192 while (e
->enumerate(e
, &product
, &hash
, &did
))
1194 printf("%#B '%s'\n", &hash
, product
);
1199 printf("%d %N value%s found for file '%s%s%s'\n",
1200 count
, pts_meas_algorithm_names
, this->algo
,
1201 (count
== 1) ?
"" : "s", this->dir
,
1202 slash(this->dir
, this->file
) ?
"/" : "", this->file
);
1207 e
= this->db
->query(this->db
,
1208 "SELECT f.id, f.path, p.name, fh.hash, fh.directory "
1209 "FROM file_hashes AS fh "
1210 "JOIN files AS f ON f.id = fh.file "
1211 "JOIN products AS p ON p.id = fh.product "
1212 "WHERE fh.algo = ? "
1213 "ORDER BY fh.directory, f.path, p.name",
1215 DB_INT
, DB_TEXT
, DB_TEXT
, DB_BLOB
, DB_INT
);
1218 while (e
->enumerate(e
, &fid
, &file
, &product
, &hash
, &did
))
1220 if (fid
!= fid_old
|| did
!= did_old
)
1224 get_directory(this, did
, &dir
);
1227 printf("%4d: %s%s%s\n", fid
,
1228 dir
, slash(dir
, file
) ?
"/" : "", file
);
1231 printf(" %#B '%s'\n", &hash
, product
);
1236 printf("%d %N value%s found\n", count
, pts_meas_algorithm_names
,
1237 this->algo
, (count
== 1) ?
"" : "s");
1243 METHOD(attest_db_t
, list_measurements
, void,
1244 private_attest_db_t
*this)
1247 chunk_t hash
, keyid
;
1248 pts_comp_func_name_t
*cfn
;
1250 int seq_no
, pcr
, vid
, name
, qualifier
;
1251 int cid
, cid_old
= 0, kid
, kid_old
= 0, count
= 0;
1253 if (this->kid
&& this->cid
)
1255 e
= this->db
->query(this->db
,
1256 "SELECT ch.seq_no, ch.pcr, ch.hash, k.owner "
1257 "FROM component_hashes AS ch "
1258 "JOIN keys AS k ON k.id = ch.key "
1259 "WHERE ch.algo = ? AND ch.key = ? AND ch.component = ? "
1261 DB_INT
, this->algo
, DB_UINT
, this->kid
, DB_UINT
, this->cid
,
1262 DB_INT
, DB_INT
, DB_BLOB
, DB_TEXT
);
1265 while (e
->enumerate(e
, &seq_no
, &pcr
, &hash
, &owner
))
1267 if (this->kid
!= kid_old
)
1269 printf("%4d: %#B '%s'\n", this->kid
, &this->key
, owner
);
1270 kid_old
= this->kid
;
1272 printf("%7d %02d %#B\n", seq_no
, pcr
, &hash
);
1277 printf("%d %N value%s found for component '%s'\n", count
,
1278 pts_meas_algorithm_names
, this->algo
,
1279 (count
== 1) ?
"" : "s", print_cfn(this->cfn
));
1284 e
= this->db
->query(this->db
,
1285 "SELECT ch.seq_no, ch.pcr, ch.hash, k.id, k.keyid, k.owner "
1286 "FROM component_hashes AS ch "
1287 "JOIN keys AS k ON k.id = ch.key "
1288 "WHERE ch.algo = ? AND ch.component = ? "
1289 "ORDER BY keyid, seq_no",
1290 DB_INT
, this->algo
, DB_UINT
, this->cid
,
1291 DB_INT
, DB_INT
, DB_BLOB
, DB_INT
, DB_BLOB
, DB_TEXT
);
1294 while (e
->enumerate(e
, &seq_no
, &pcr
, &hash
, &kid
, &keyid
, &owner
))
1298 printf("%4d: %#B '%s'\n", kid
, &keyid
, owner
);
1301 printf("%7d %02d %#B\n", seq_no
, pcr
, &hash
);
1306 printf("%d %N value%s found for component '%s'\n", count
,
1307 pts_meas_algorithm_names
, this->algo
,
1308 (count
== 1) ?
"" : "s", print_cfn(this->cfn
));
1314 e
= this->db
->query(this->db
,
1315 "SELECT ch.seq_no, ch.pcr, ch.hash, "
1316 "c.id, c.vendor_id, c.name, c.qualifier "
1317 "FROM component_hashes AS ch "
1318 "JOIN components AS c ON c.id = ch.component "
1319 "WHERE ch.algo = ? AND ch.key = ? "
1320 "ORDER BY vendor_id, name, qualifier, seq_no",
1321 DB_INT
, this->algo
, DB_UINT
, this->kid
, DB_INT
, DB_INT
, DB_BLOB
,
1322 DB_INT
, DB_INT
, DB_INT
, DB_INT
);
1325 while (e
->enumerate(e
, &seq_no
, &pcr
, &hash
, &cid
, &vid
, &name
,
1330 cfn
= pts_comp_func_name_create(vid
, name
, qualifier
);
1331 printf("%4d: %s\n", cid
, print_cfn(cfn
));
1335 printf("%5d %02d %#B\n", seq_no
, pcr
, &hash
);
1340 printf("%d %N value%s found for key %#B '%s'\n", count
,
1341 pts_meas_algorithm_names
, this->algo
,
1342 (count
== 1) ?
"" : "s", &this->key
, this->owner
);
1347 bool insert_file_hash(private_attest_db_t
*this, pts_meas_algorithms_t algo
,
1348 chunk_t measurement
, int fid
, int did
, bool ima
,
1349 int *hashes_added
, int *hashes_updated
)
1355 label
= "could not be created";
1357 e
= this->db
->query(this->db
,
1358 "SELECT hash FROM file_hashes WHERE algo = ? "
1359 "AND file = ? AND directory = ? AND product = ? and key = 0",
1360 DB_INT
, algo
, DB_UINT
, fid
, DB_UINT
, did
, DB_UINT
, this->pid
, DB_BLOB
);
1363 printf("file_hashes query failed\n");
1366 if (e
->enumerate(e
, &hash
))
1368 if (chunk_equals(measurement
, hash
))
1370 label
= "exists and equals";
1374 if (this->db
->execute(this->db
, NULL
,
1375 "UPDATE file_hashes SET hash = ? WHERE algo = ? "
1376 "AND file = ? AND directory = ? AND product = ? and key = 0",
1377 DB_BLOB
, measurement
, DB_INT
, algo
, DB_UINT
, fid
, DB_UINT
, did
,
1378 DB_UINT
, this->pid
) == 1)
1381 (*hashes_updated
)++;
1387 if (this->db
->execute(this->db
, NULL
,
1388 "INSERT INTO file_hashes "
1389 "(file, directory, product, key, algo, hash) "
1390 "VALUES (?, ?, ?, 0, ?, ?)",
1391 DB_UINT
, fid
, DB_UINT
, did
, DB_UINT
, this->pid
,
1392 DB_INT
, algo
, DB_BLOB
, measurement
) == 1)
1400 printf(" %#B - %s%s\n", &measurement
, ima ?
"ima - " : "", label
);
1404 METHOD(attest_db_t
, add
, bool,
1405 private_attest_db_t
*this)
1407 bool success
= FALSE
;
1409 /* add key/component pair */
1410 if (this->kid
&& this->cid
)
1412 success
= this->db
->execute(this->db
, NULL
,
1413 "INSERT INTO key_component (key, component, seq_no) "
1415 DB_UINT
, this->kid
, DB_UINT
, this->cid
,
1416 DB_UINT
, this->seq_no
) == 1;
1418 printf("key/component pair (%d/%d) %sinserted into database at "
1419 "position %d\n", this->kid
, this->cid
,
1420 success ?
"" : "could not be ", this->seq_no
);
1425 /* add directory or file measurement for a given product */
1426 if ((this->did
|| this->fid
) && this->pid
)
1428 char *pathname
, *filename
, *label
;
1429 char ima_buffer
[IMA_MAX_NAME_LEN
+ 1];
1430 chunk_t measurement
, ima_template
;
1431 pts_file_meas_t
*measurements
;
1432 hasher_t
*hasher
= NULL
;
1435 int files_added
= 0, hashes_added
= 0, hashes_updated
= 0;
1436 int ima_hashes_added
= 0, ima_hashes_updated
= 0;
1437 enumerator_t
*enumerator
, *e
;
1439 if (this->algo
== PTS_MEAS_ALGO_SHA1_IMA
)
1442 this->algo
= PTS_MEAS_ALGO_SHA1
;
1443 hasher
= lib
->crypto
->create_hasher(lib
->crypto
, HASH_SHA1
);
1446 printf("could not create hasher\n");
1451 pathname
= this->did ?
this->dir
: this->file
;
1452 measurements
= pts_file_meas_create_from_path(0, pathname
, this->did
,
1453 this->relative
, this->algo
);
1456 printf("file measurement failed\n");
1460 if (this->fid
&& this->relative
)
1462 set_directory(this, dirname(pathname
), TRUE
);
1464 did
= this->relative ?
this->did
: 0;
1466 enumerator
= measurements
->create_enumerator(measurements
);
1467 while (enumerator
->enumerate(enumerator
, &filename
, &measurement
))
1469 /* retrieve or create filename */
1470 label
= "could not be created";
1472 e
= this->db
->query(this->db
,
1473 "SELECT id FROM files WHERE path = ?",
1474 DB_TEXT
, filename
, DB_INT
);
1477 printf("files query failed\n");
1480 if (e
->enumerate(e
, &fid
))
1486 if (this->db
->execute(this->db
, &fid
,
1487 "INSERT INTO files (type, path) VALUES (0, ?)",
1488 DB_TEXT
, filename
) == 1)
1496 printf("%4d: %s - %s\n", fid
, filename
, label
);
1498 /* compute file measurement hash */
1499 if (!insert_file_hash(this, this->algo
, measurement
,
1501 &hashes_added
, &hashes_updated
))
1511 /* compute IMA template hash */
1512 strncpy(ima_buffer
, filename
, IMA_MAX_NAME_LEN
);
1513 ima_buffer
[IMA_MAX_NAME_LEN
] = '\0';
1514 ima_template
= chunk_create(ima_buffer
, sizeof(ima_buffer
));
1515 if (!hasher
->get_hash(hasher
, measurement
, NULL
) ||
1516 !hasher
->get_hash(hasher
, ima_template
, measurement
.ptr
))
1518 printf("could not compute IMA template hash\n");
1521 if (!insert_file_hash(this, PTS_MEAS_ALGO_SHA1_IMA
, measurement
,
1523 &ima_hashes_added
, &ima_hashes_updated
))
1528 enumerator
->destroy(enumerator
);
1530 printf("%d measurements, added %d new files, %d file hashes",
1531 measurements
->get_file_count(measurements
), files_added
,
1535 printf(", %d ima hashes", ima_hashes_added
, ima_hashes_updated
);
1536 hasher
->destroy(hasher
);
1538 printf(", updated %d file hashes", hashes_updated
);
1541 printf(", %d ima hashes", ima_hashes_updated
);
1544 measurements
->destroy(measurements
);
1548 /* insert package version */
1549 if (this->version_set
&& this->gid
&& this->pid
)
1551 time_t t
= time(NULL
);
1553 success
= this->db
->execute(this->db
, NULL
,
1554 "INSERT INTO versions "
1555 "(package, product, release, security, time) "
1556 "VALUES (?, ?, ?, ?, ?)",
1557 DB_UINT
, this->gid
, DB_UINT
, this->pid
, DB_TEXT
,
1558 this->version
, DB_UINT
, this->security
, DB_INT
, t
) == 1;
1560 printf("'%s' package %s (%s)%N %sinserted into database\n",
1561 this->product
, this->package
, this->version
,
1562 os_package_state_names
, this->security
,
1563 success ?
"" : "could not be ");
1568 METHOD(attest_db_t
, delete, bool,
1569 private_attest_db_t
*this)
1573 /* delete a file measurement hash for a given product */
1574 if (this->algo
&& this->pid
&& this->fid
)
1576 success
= this->db
->execute(this->db
, NULL
,
1577 "DELETE FROM file_hashes "
1578 "WHERE algo = ? AND product = ? "
1579 "AND file = ? AND directory = ?",
1580 DB_UINT
, this->algo
, DB_UINT
, this->pid
,
1581 DB_UINT
, this->fid
, DB_UINT
, this->did
) > 0;
1583 printf("%4d: %s%s%s\n", this->fid
, this->dir
, this->did ?
"/":"",
1585 printf("%N value for product '%s' %sdeleted from database\n",
1586 pts_meas_algorithm_names
, this->algo
, this->product
,
1587 success ?
"" : "could not be ");
1592 /* delete product/file entries */
1593 if (this->pid
&& (this->fid
|| this->did
))
1595 success
= this->db
->execute(this->db
, NULL
,
1596 "DELETE FROM product_file "
1597 "WHERE product = ? AND file = ?",
1599 DB_UINT
, this->fid ?
this->fid
: this->did
) > 0;
1601 printf("product/file pair (%d/%d) %sdeleted from database\n",
1602 this->pid
, this->fid ?
this->fid
: this->did
,
1603 success ?
"" : "could not be ");
1608 /* delete key/component pair */
1609 if (this->kid
&& this->cid
)
1611 success
= this->db
->execute(this->db
, NULL
,
1612 "DELETE FROM key_component "
1613 "WHERE key = ? AND component = ?",
1614 DB_UINT
, this->kid
, DB_UINT
, this->cid
) > 0;
1616 printf("key/component pair (%d/%d) %sdeleted from database\n",
1617 this->kid
, this->cid
, success ?
"" : "could not be ");
1623 success
= this->db
->execute(this->db
, NULL
,
1624 "DELETE FROM components WHERE id = ?",
1625 DB_UINT
, this->cid
) > 0;
1627 printf("component '%s' %sdeleted from database\n", print_cfn(this->cfn
),
1628 success ?
"" : "could not be ");
1634 success
= this->db
->execute(this->db
, NULL
,
1635 "DELETE FROM files WHERE type = 1 AND id = ?",
1636 DB_UINT
, this->did
) > 0;
1638 printf("directory '%s' %sdeleted from database\n", this->dir
,
1639 success ?
"" : "could not be ");
1645 success
= this->db
->execute(this->db
, NULL
,
1646 "DELETE FROM files WHERE id = ?",
1647 DB_UINT
, this->fid
) > 0;
1649 printf("file '%s' %sdeleted from database\n", this->file
,
1650 success ?
"" : "could not be ");
1656 success
= this->db
->execute(this->db
, NULL
,
1657 "DELETE FROM keys WHERE id = ?",
1658 DB_UINT
, this->kid
) > 0;
1660 printf("key %#B %sdeleted from database\n", &this->key
,
1661 success ?
"" : "could not be ");
1666 success
= this->db
->execute(this->db
, NULL
,
1667 "DELETE FROM products WHERE id = ?",
1668 DB_UINT
, this->pid
) > 0;
1670 printf("product '%s' %sdeleted from database\n", this->product
,
1671 success ?
"" : "could not be ");
1675 printf("empty delete command\n");
1679 METHOD(attest_db_t
, destroy
, void,
1680 private_attest_db_t
*this)
1682 DESTROY_IF(this->db
);
1683 DESTROY_IF(this->cfn
);
1684 free(this->package
);
1685 free(this->product
);
1686 free(this->version
);
1690 free(this->key
.ptr
);
1695 * Described in header.
1697 attest_db_t
*attest_db_create(char *uri
)
1699 private_attest_db_t
*this;
1703 .set_component
= _set_component
,
1704 .set_cid
= _set_cid
,
1705 .set_directory
= _set_directory
,
1706 .set_did
= _set_did
,
1707 .set_file
= _set_file
,
1708 .set_fid
= _set_fid
,
1709 .set_key
= _set_key
,
1710 .set_kid
= _set_kid
,
1711 .set_package
= _set_package
,
1712 .set_gid
= _set_gid
,
1713 .set_product
= _set_product
,
1714 .set_pid
= _set_pid
,
1715 .set_version
= _set_version
,
1716 .set_algo
= _set_algo
,
1717 .set_relative
= _set_relative
,
1718 .set_security
= _set_security
,
1719 .set_sequence
= _set_sequence
,
1720 .set_owner
= _set_owner
,
1721 .list_packages
= _list_packages
,
1722 .list_products
= _list_products
,
1723 .list_files
= _list_files
,
1724 .list_components
= _list_components
,
1725 .list_devices
= _list_devices
,
1726 .list_keys
= _list_keys
,
1727 .list_hashes
= _list_hashes
,
1728 .list_measurements
= _list_measurements
,
1731 .destroy
= _destroy
,
1734 .db
= lib
->db
->create(lib
->db
, uri
),
1739 fprintf(stderr
, "opening database failed.\n");
1744 return &this->public;