Annotation of embedaddon/strongswan/src/libimcv/pts/pts.c, revision 1.1.1.2
1.1 misho 1: /*
2: * Copyright (C) 2011-2012 Sansar Choinyambuu
1.1.1.2 ! misho 3: * Copyright (C) 2012-2020 Andreas Steffen
1.1 misho 4: * HSR Hochschule fuer Technik Rapperswil
5: *
6: * This program is free software; you can redistribute it and/or modify it
7: * under the terms of the GNU General Public License as published by the
8: * Free Software Foundation; either version 2 of the License, or (at your
9: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10: *
11: * This program is distributed in the hope that it will be useful, but
12: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14: * for more details.
15: */
16:
17: #include "pts.h"
18:
19: #include <utils/debug.h>
20: #include <crypto/hashers/hasher.h>
21: #include <bio/bio_writer.h>
22: #include <bio/bio_reader.h>
23:
24: #include <tpm_tss_trousers.h>
25:
26: #include <sys/types.h>
27: #include <sys/stat.h>
28: #include <libgen.h>
29: #include <unistd.h>
1.1.1.2 ! misho 30: #include <dirent.h>
1.1 misho 31: #include <errno.h>
32:
1.1.1.2 ! misho 33:
1.1 misho 34: #ifndef TPM_TAG_QUOTE_INFO2
35: #define TPM_TAG_QUOTE_INFO2 0x0036
36: #endif
37: #ifndef TPM_LOC_ZERO
38: #define TPM_LOC_ZERO 0x01
39: #endif
40:
41: typedef struct private_pts_t private_pts_t;
42:
43: /**
44: * Private data of a pts_t object.
45: *
46: */
47: struct private_pts_t {
48:
49: /**
50: * Public pts_t interface.
51: */
52: pts_t public;
53:
54: /**
55: * PTS Protocol Capabilities
56: */
57: pts_proto_caps_flag_t proto_caps;
58:
59: /**
60: * PTS Measurement Algorithm
61: */
62: pts_meas_algorithms_t algorithm;
63:
64: /**
65: * DH Hash Algorithm
66: */
67: pts_meas_algorithms_t dh_hash_algorithm;
68:
69: /**
70: * PTS Diffie-Hellman Secret
71: */
72: diffie_hellman_t *dh;
73:
74: /**
75: * PTS Diffie-Hellman Initiator Nonce
76: */
77: chunk_t initiator_nonce;
78:
79: /**
80: * PTS Diffie-Hellman Responder Nonce
81: */
82: chunk_t responder_nonce;
83:
84: /**
85: * Secret assessment value to be used for TPM Quote as an external data
86: */
87: chunk_t secret;
88:
89: /**
90: * Primary key of platform entry in database
91: */
92: int platform_id;
93:
94: /**
1.1.1.2 ! misho 95: * List of directory symlinks received from IMC
! 96: */
! 97: pts_symlinks_t *symlinks;
! 98:
! 99: /**
1.1 misho 100: * TRUE if IMC-PTS, FALSE if IMV-PTS
101: */
102: bool is_imc;
103:
104: /**
1.1.1.2 ! misho 105: * IMC-PTS: own TPM / IMV-PTS: unused
1.1 misho 106: */
107: tpm_tss_t *tpm;
108:
109: /**
1.1.1.2 ! misho 110: * IMC-PTS: own TPM version / IMV-PTS: peer TPM version
! 111: */
! 112: tpm_version_t tpm_version;
! 113:
! 114: /**
! 115: * Contains a TPM Version Info struct
1.1 misho 116: */
117: chunk_t tpm_version_info;
118:
119: /**
120: * AIK object handle
121: */
122: uint32_t aik_handle;
123:
124: /**
125: * Contains an Attestation Identity Key Certificate
126: */
127: certificate_t *aik_cert;
128:
129: /**
130: * Primary key referencing AIK in database
131: */
132: int aik_id;
133:
134: /**
135: * Shadow PCR set
136: */
137: pts_pcr_t *pcrs;
138:
139: };
140:
141: METHOD(pts_t, get_proto_caps, pts_proto_caps_flag_t,
142: private_pts_t *this)
143: {
144: return this->proto_caps;
145: }
146:
147: METHOD(pts_t, set_proto_caps, void,
148: private_pts_t *this, pts_proto_caps_flag_t flags)
149: {
150: this->proto_caps = flags;
151: DBG2(DBG_PTS, "supported PTS protocol capabilities: %s%s%s%s%s",
152: flags & PTS_PROTO_CAPS_C ? "C" : ".",
153: flags & PTS_PROTO_CAPS_V ? "V" : ".",
154: flags & PTS_PROTO_CAPS_D ? "D" : ".",
155: flags & PTS_PROTO_CAPS_T ? "T" : ".",
156: flags & PTS_PROTO_CAPS_X ? "X" : ".");
157: }
158:
159: METHOD(pts_t, get_meas_algorithm, pts_meas_algorithms_t,
160: private_pts_t *this)
161: {
162: return this->algorithm;
163: }
164:
165: METHOD(pts_t, set_meas_algorithm, void,
166: private_pts_t *this, pts_meas_algorithms_t algorithm)
167: {
168: hash_algorithm_t hash_alg;
169:
170: hash_alg = pts_meas_algo_to_hash(algorithm);
171: DBG2(DBG_PTS, "selected PTS measurement algorithm is %N",
172: hash_algorithm_names, hash_alg);
173: if (hash_alg != HASH_UNKNOWN)
174: {
175: this->algorithm = algorithm;
176: }
177: }
178:
179: METHOD(pts_t, get_dh_hash_algorithm, pts_meas_algorithms_t,
180: private_pts_t *this)
181: {
182: return this->dh_hash_algorithm;
183: }
184:
185: METHOD(pts_t, set_dh_hash_algorithm, void,
186: private_pts_t *this, pts_meas_algorithms_t algorithm)
187: {
188: hash_algorithm_t hash_alg;
189:
190: hash_alg = pts_meas_algo_to_hash(algorithm);
191: DBG2(DBG_PTS, "selected DH hash algorithm is %N",
192: hash_algorithm_names, hash_alg);
193: if (hash_alg != HASH_UNKNOWN)
194: {
195: this->dh_hash_algorithm = algorithm;
196: }
197: }
198:
199: METHOD(pts_t, create_dh_nonce, bool,
200: private_pts_t *this, pts_dh_group_t group, int nonce_len)
201: {
202: diffie_hellman_group_t dh_group;
203: chunk_t *nonce;
204: rng_t *rng;
205:
206: dh_group = pts_dh_group_to_ike(group);
207: DBG2(DBG_PTS, "selected PTS DH group is %N",
208: diffie_hellman_group_names, dh_group);
209: DESTROY_IF(this->dh);
210: this->dh = lib->crypto->create_dh(lib->crypto, dh_group);
211:
212: rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
213: if (!rng)
214: {
215: DBG1(DBG_PTS, "no rng available");
216: return FALSE;
217: }
218: DBG2(DBG_PTS, "nonce length is %d", nonce_len);
219: nonce = this->is_imc ? &this->responder_nonce : &this->initiator_nonce;
220: chunk_free(nonce);
221: if (!rng->allocate_bytes(rng, nonce_len, nonce))
222: {
223: DBG1(DBG_PTS, "failed to allocate nonce");
224: rng->destroy(rng);
225: return FALSE;
226: }
227: rng->destroy(rng);
228: return TRUE;
229: }
230:
231: METHOD(pts_t, get_my_public_value, bool,
232: private_pts_t *this, chunk_t *value, chunk_t *nonce)
233: {
234: if (!this->dh->get_my_public_value(this->dh, value))
235: {
236: return FALSE;
237: }
238: *nonce = this->is_imc ? this->responder_nonce : this->initiator_nonce;
239: return TRUE;
240: }
241:
242: METHOD(pts_t, set_peer_public_value, bool,
243: private_pts_t *this, chunk_t value, chunk_t nonce)
244: {
245: if (!this->dh->set_other_public_value(this->dh, value))
246: {
247: return FALSE;
248: }
249:
250: nonce = chunk_clone(nonce);
251: if (this->is_imc)
252: {
253: this->initiator_nonce = nonce;
254: }
255: else
256: {
257: this->responder_nonce = nonce;
258: }
259: return TRUE;
260: }
261:
262: METHOD(pts_t, calculate_secret, bool,
263: private_pts_t *this)
264: {
265: hasher_t *hasher;
266: hash_algorithm_t hash_alg;
267: chunk_t shared_secret;
268:
269: /* Check presence of nonces */
270: if (!this->initiator_nonce.len || !this->responder_nonce.len)
271: {
272: DBG1(DBG_PTS, "initiator and/or responder nonce is not available");
273: return FALSE;
274: }
275: DBG3(DBG_PTS, "initiator nonce: %B", &this->initiator_nonce);
276: DBG3(DBG_PTS, "responder nonce: %B", &this->responder_nonce);
277:
278: /* Calculate the DH secret */
279: if (!this->dh->get_shared_secret(this->dh, &shared_secret))
280: {
281: DBG1(DBG_PTS, "shared DH secret computation failed");
282: return FALSE;
283: }
284: DBG3(DBG_PTS, "shared DH secret: %B", &shared_secret);
285:
286: /* Calculate the secret assessment value */
287: hash_alg = pts_meas_algo_to_hash(this->dh_hash_algorithm);
288: hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
289:
290: if (!hasher ||
291: !hasher->get_hash(hasher, chunk_from_chars('1'), NULL) ||
292: !hasher->get_hash(hasher, this->initiator_nonce, NULL) ||
293: !hasher->get_hash(hasher, this->responder_nonce, NULL) ||
294: !hasher->allocate_hash(hasher, shared_secret, &this->secret))
295: {
296: DESTROY_IF(hasher);
297: return FALSE;
298: }
299: hasher->destroy(hasher);
300: chunk_clear(&shared_secret);
301:
302: DBG3(DBG_PTS, "secret assessment value: %B", &this->secret);
1.1.1.2 ! misho 303:
1.1 misho 304: return TRUE;
305: }
306:
307: METHOD(pts_t, get_platform_id, int,
308: private_pts_t *this)
309: {
310: return this->platform_id;
311: }
312:
313: METHOD(pts_t, set_platform_id, void,
314: private_pts_t *this, int pid)
315: {
316: this->platform_id = pid;
317: }
318:
1.1.1.2 ! misho 319: METHOD(pts_t, extract_symlinks, pts_symlinks_t*,
! 320: private_pts_t *this, chunk_t pathname)
! 321: {
! 322: #ifndef WIN32
! 323: char path[BUF_LEN], real_path[BUF_LEN];
! 324: size_t path_len, real_path_len;
! 325: struct dirent *entry;
! 326: struct stat st;
! 327: DIR *dir;
! 328:
! 329: /* open directory and prepare pathnames */
! 330: snprintf(path, BUF_LEN-1, "%.*s", (int)pathname.len, pathname.ptr);
! 331: dir = opendir(path);
! 332: if (!dir)
! 333: {
! 334: DBG1(DBG_PTS, "opening directory '%s' failed: %s", path,
! 335: strerror(errno));
! 336: return NULL;
! 337: }
! 338: if (pathname.len == 1 && path[0] == '/')
! 339: {
! 340: path_len = 1;
! 341: }
! 342: else
! 343: {
! 344: path[pathname.len] = '/';
! 345: path_len = pathname.len + 1;
! 346: }
! 347: real_path[0] = '/';
! 348:
! 349: /* symlinks object is owned by pts object */
! 350: DESTROY_IF(this->symlinks);
! 351: this->symlinks = pts_symlinks_create();
! 352:
! 353: while (TRUE)
! 354: {
! 355:
! 356: entry = readdir(dir);
! 357: if (!entry)
! 358: {
! 359: /* no more entries -> exit */
! 360: break;
! 361: }
! 362: if (streq(entry->d_name, ".") || streq(entry->d_name, ".."))
! 363: {
! 364: continue;
! 365: }
! 366:
! 367: /* assemble absolute path */
! 368: snprintf(path + path_len, BUF_LEN - path_len, "%s", entry->d_name);
! 369:
! 370: /* only evaluate symlinks pointing to directories */
! 371: if (lstat(path, &st) == -1 || !S_ISLNK(st.st_mode) ||
! 372: stat(path, &st) == -1 || !S_ISDIR(st.st_mode))
! 373: {
! 374: continue;
! 375: }
! 376:
! 377: real_path_len = readlink(path, real_path + 1, BUF_LEN - 1);
! 378: if (real_path_len <= 0)
! 379: {
! 380: continue;
! 381: }
! 382: this->symlinks->add(this->symlinks, chunk_from_str(path),
! 383: chunk_create(real_path, 1 + real_path_len));
! 384: }
! 385: closedir(dir);
! 386: #endif
! 387:
! 388: return this->symlinks;
! 389: }
! 390:
! 391:
! 392: METHOD(pts_t, get_symlinks, pts_symlinks_t*,
! 393: private_pts_t *this)
! 394: {
! 395: return this->symlinks;
! 396: }
! 397:
! 398: METHOD(pts_t, set_symlinks, void,
! 399: private_pts_t *this, pts_symlinks_t *symlinks)
! 400: {
! 401: enumerator_t *enumerator;
! 402: chunk_t symlink, dir;
! 403:
! 404: DESTROY_IF(this->symlinks);
! 405: this->symlinks = symlinks->get_ref(symlinks);
! 406:
! 407: DBG2(DBG_PTS, "adding directory symlinks:");
! 408: enumerator = symlinks->create_enumerator(symlinks);
! 409: while (enumerator->enumerate(enumerator, &symlink, &dir))
! 410: {
! 411: DBG2(DBG_PTS, " %.*s -> %.*s", (int)symlink.len, symlink.ptr,
! 412: (int)dir.len, dir.ptr);
! 413: }
! 414: enumerator->destroy(enumerator);
! 415: }
! 416:
! 417: METHOD(pts_t, get_tpm, tpm_tss_t*,
! 418: private_pts_t *this)
! 419: {
! 420: return this->tpm;
! 421: }
! 422:
1.1 misho 423: METHOD(pts_t, get_tpm_version_info, bool,
424: private_pts_t *this, chunk_t *info)
425: {
1.1.1.2 ! misho 426: *info = this->tpm_version_info;
! 427:
1.1 misho 428: return info->len > 0;
429: }
430:
1.1.1.2 ! misho 431: #define TPM_VERSION_INFO_TAG_1_2 0x0030
! 432: #define TPM_VERSION_INFO_TAG_2_0 0x0200
! 433: #define TPM_VERSION_INFO_LABEL "Version Information: TPM"
! 434:
1.1 misho 435: METHOD(pts_t, set_tpm_version_info, void,
436: private_pts_t *this, chunk_t info)
437: {
1.1.1.2 ! misho 438: bio_reader_t *reader;
! 439: uint16_t tpm_version_info_tag;
! 440: chunk_t vendor;
! 441:
! 442: reader = bio_reader_create(info);
! 443: reader->read_uint16(reader, &tpm_version_info_tag);
! 444:
! 445: if (tpm_version_info_tag == TPM_VERSION_INFO_TAG_1_2)
! 446: {
! 447: uint8_t major, minor, rev_major, rev_minor, errata_rev;
! 448: uint16_t spec_level;
! 449:
! 450: this->tpm_version = TPM_VERSION_1_2;
! 451:
! 452: if (reader->read_uint8 (reader, &major) &&
! 453: reader->read_uint8 (reader, &minor) &&
! 454: reader->read_uint8 (reader, &rev_major) &&
! 455: reader->read_uint8 (reader, &rev_minor) &&
! 456: reader->read_uint16(reader, &spec_level) &&
! 457: reader->read_uint8 (reader, &errata_rev) &&
! 458: reader->read_data (reader, 4, &vendor))
! 459: {
! 460: DBG2(DBG_PTS, "%s 1.2 rev. %u.%u.%u.%u %.*s", TPM_VERSION_INFO_LABEL,
! 461: (uint32_t)major, (uint32_t)minor, (uint32_t)rev_major,
! 462: (uint32_t)rev_minor, (int)vendor.len, vendor.ptr);
! 463: }
! 464: else
! 465: {
! 466: DBG2(DBG_PTS, "%s 1.2", TPM_VERSION_INFO_LABEL);
! 467: }
! 468:
! 469: }
! 470: else if (tpm_version_info_tag == TPM_VERSION_INFO_TAG_2_0)
! 471: {
! 472: uint32_t revision, year;
! 473: uint8_t reserved, locality;
! 474:
! 475: this->tpm_version = TPM_VERSION_2_0;
! 476:
! 477: if (reader->read_uint8 (reader, &reserved) &&
! 478: reader->read_uint8 (reader, &locality) &&
! 479: reader->read_uint32(reader, &revision) &&
! 480: reader->read_uint32(reader, &year) &&
! 481: reader->read_data (reader, 4, &vendor))
! 482: {
! 483: DBG2(DBG_PTS, "%s 2.0 rev. %4.2f %u %.*s - startup locality: %u",
! 484: TPM_VERSION_INFO_LABEL, revision/100.0, year,
! 485: (int)vendor.len, vendor.ptr, (uint32_t)locality);
! 486: }
! 487: else
! 488: {
! 489: DBG2(DBG_PTS, "%s 2.0", TPM_VERSION_INFO_LABEL);
! 490: }
! 491: }
! 492: reader->destroy(reader);
! 493:
1.1 misho 494: this->tpm_version_info = chunk_clone(info);
495: }
496:
497: /**
498: * Load an AIK handle and an optional AIK certificate and
499: * in the case of a TPM 1.2 an AIK private key blob plus matching public key,
500: * the certificate having precedence over the public key if both are present
501: */
502: static void load_aik(private_pts_t *this)
503: {
504: char *handle_str, *cert_path, *key_path, *blob_path;
505: chunk_t aik_pubkey = chunk_empty;
506:
507: handle_str = lib->settings->get_str(lib->settings,
508: "%s.plugins.imc-attestation.aik_handle", NULL, lib->ns);
509: cert_path = lib->settings->get_str(lib->settings,
510: "%s.plugins.imc-attestation.aik_cert", NULL, lib->ns);
511: key_path = lib->settings->get_str(lib->settings,
512: "%s.plugins.imc-attestation.aik_pubkey", NULL, lib->ns);
513: blob_path = lib->settings->get_str(lib->settings,
514: "%s.plugins.imc-attestation.aik_blob", NULL, lib->ns);
515:
516: if (handle_str)
517: {
518: this->aik_handle = strtoll(handle_str, NULL, 16);
519: }
520: if (cert_path)
521: {
522: this->aik_cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
523: CERT_X509, BUILD_FROM_FILE,
524: cert_path, BUILD_END);
525: if (this->aik_cert)
526: {
527: DBG2(DBG_PTS, "loaded AIK certificate from '%s'", cert_path);
528: }
529: }
530:
531: if (this->tpm->get_version(this->tpm) == TPM_VERSION_1_2)
532: {
533: tpm_tss_trousers_t *tpm_12;
534: chunk_t aik_blob = chunk_empty;
535: chunk_t *map;
536:
537: /* get AIK private key blob */
538: if (blob_path)
539: {
540: map = chunk_map(blob_path, FALSE);
541: if (map)
542: {
543: DBG2(DBG_PTS, "loaded AIK Blob from '%s'", blob_path);
544: DBG3(DBG_PTS, "AIK Blob: %B", map);
545: aik_blob = chunk_clone(*map);
546: chunk_unmap(map);
547: }
548: else
549: {
550: DBG1(DBG_PTS, "unable to map AIK Blob file '%s': %s",
551: blob_path, strerror(errno));
552: }
553: }
554: else
555: {
556: DBG1(DBG_PTS, "AIK Blob is not available");
557: }
558:
559: /* get AIK public key if no AIK certificate is available */
560: if (!this->aik_cert)
561: {
562: if (key_path)
563: {
564: map = chunk_map(key_path, FALSE);
565: if (map)
566: {
567: DBG2(DBG_PTS, "loaded AIK public key from '%s'", key_path);
568: aik_pubkey = chunk_clone(*map);
569: chunk_unmap(map);
570: }
571: else
572: {
573: DBG1(DBG_PTS, "unable to map AIK public key file '%s': %s",
574: key_path, strerror(errno));
575: }
576: }
577: else
578: {
579: DBG1(DBG_PTS, "AIK public key is not available");
580: }
581: }
582:
583: /* Load AIK item into TPM 1.2 object */
584: tpm_12 = (tpm_tss_trousers_t *)this->tpm;
585: tpm_12->load_aik(tpm_12, aik_blob, aik_pubkey, this->aik_handle);
586: }
587:
588: /* if no signed X.509 AIK certificate is available use public key instead */
589: if (!this->aik_cert)
590: {
591: aik_pubkey = this->tpm->get_public(this->tpm, this->aik_handle);
592: if (aik_pubkey.len > 0)
593: {
594: this->aik_cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
595: CERT_TRUSTED_PUBKEY, BUILD_BLOB,
596: aik_pubkey, BUILD_END);
597: chunk_free(&aik_pubkey);
598: }
599: else
600: {
601: DBG1(DBG_PTS, "neither AIK certificate nor public key is available");
602: }
603: }
604: }
605:
606: METHOD(pts_t, get_aik, certificate_t*,
607: private_pts_t *this)
608: {
609: return this->aik_cert;
610: }
611:
612: METHOD(pts_t, set_aik, void,
613: private_pts_t *this, certificate_t *aik, int aik_id)
614: {
615: DESTROY_IF(this->aik_cert);
616: this->aik_cert = aik->get_ref(aik);
617: this->aik_id = aik_id;
618: }
619:
620: METHOD(pts_t, get_aik_id, int,
621: private_pts_t *this)
622: {
623: return this->aik_id;
624: }
625:
626: METHOD(pts_t, is_path_valid, bool,
627: private_pts_t *this, char *path, pts_error_code_t *error_code)
628: {
629: struct stat st;
630:
631: *error_code = 0;
632:
633: if (!stat(path, &st))
634: {
635: return TRUE;
636: }
637: else if (errno == ENOENT || errno == ENOTDIR)
638: {
639: DBG1(DBG_PTS, "file/directory does not exist %s", path);
640: *error_code = TCG_PTS_FILE_NOT_FOUND;
641: }
642: else if (errno == EFAULT)
643: {
644: DBG1(DBG_PTS, "bad address %s", path);
645: *error_code = TCG_PTS_INVALID_PATH;
646: }
647: else
648: {
649: DBG1(DBG_PTS, "error: %s occurred while validating path: %s",
650: strerror(errno), path);
651: return FALSE;
652: }
653:
654: return TRUE;
655: }
656:
657: /**
658: * Obtain statistical information describing a file
659: */
660: static bool file_metadata(char *pathname, pts_file_metadata_t **entry)
661: {
662: struct stat st;
663: pts_file_metadata_t *this;
664:
665: this = malloc_thing(pts_file_metadata_t);
666:
667: if (stat(pathname, &st))
668: {
669: DBG1(DBG_PTS, "unable to obtain statistics about '%s'", pathname);
670: free(this);
671: return FALSE;
672: }
673:
674: if (S_ISREG(st.st_mode))
675: {
676: this->type = PTS_FILE_REGULAR;
677: }
678: else if (S_ISDIR(st.st_mode))
679: {
680: this->type = PTS_FILE_DIRECTORY;
681: }
682: else if (S_ISCHR(st.st_mode))
683: {
684: this->type = PTS_FILE_CHAR_SPEC;
685: }
686: else if (S_ISBLK(st.st_mode))
687: {
688: this->type = PTS_FILE_BLOCK_SPEC;
689: }
690: else if (S_ISFIFO(st.st_mode))
691: {
692: this->type = PTS_FILE_FIFO;
693: }
694: #ifndef WIN32
695: else if (S_ISLNK(st.st_mode))
696: {
697: this->type = PTS_FILE_SYM_LINK;
698: }
699: else if (S_ISSOCK(st.st_mode))
700: {
701: this->type = PTS_FILE_SOCKET;
702: }
703: #endif /* WIN32 */
704: else
705: {
706: this->type = PTS_FILE_OTHER;
707: }
708:
709: this->filesize = st.st_size;
710: this->created = st.st_ctime;
711: this->modified = st.st_mtime;
712: this->accessed = st.st_atime;
713: this->owner = st.st_uid;
714: this->group = st.st_gid;
715:
716: *entry = this;
717: return TRUE;
718: }
719:
720: METHOD(pts_t, get_metadata, pts_file_meta_t*,
721: private_pts_t *this, char *pathname, bool is_directory)
722: {
723: pts_file_meta_t *metadata;
724: pts_file_metadata_t *entry;
725:
726: /* Create a metadata object */
727: metadata = pts_file_meta_create();
728:
729: if (is_directory)
730: {
731: enumerator_t *enumerator;
732: char *rel_name, *abs_name;
733: struct stat st;
734:
735: enumerator = enumerator_create_directory(pathname);
736: if (!enumerator)
737: {
738: DBG1(DBG_PTS," directory '%s' can not be opened, %s", pathname,
739: strerror(errno));
740: metadata->destroy(metadata);
741: return NULL;
742: }
743: while (enumerator->enumerate(enumerator, &rel_name, &abs_name, &st))
744: {
745: /* measure regular files only */
746: if (S_ISREG(st.st_mode) && *rel_name != '.')
747: {
748: if (!file_metadata(abs_name, &entry))
749: {
750: enumerator->destroy(enumerator);
751: metadata->destroy(metadata);
752: return NULL;
753: }
754: entry->filename = strdup(rel_name);
755: metadata->add(metadata, entry);
756: }
757: }
758: enumerator->destroy(enumerator);
759: }
760: else
761: {
762: if (!file_metadata(pathname, &entry))
763: {
764: metadata->destroy(metadata);
765: return NULL;
766: }
767: entry->filename = path_basename(pathname);
768: metadata->add(metadata, entry);
769: }
770:
771: return metadata;
772: }
773:
774: METHOD(pts_t, read_pcr, bool,
775: private_pts_t *this, uint32_t pcr_num, chunk_t *pcr_value,
776: hash_algorithm_t alg)
777: {
778: return this->tpm ? this->tpm->read_pcr(this->tpm, pcr_num, pcr_value, alg)
779: : FALSE;
780: }
781:
782: METHOD(pts_t, extend_pcr, bool,
783: private_pts_t *this, uint32_t pcr_num, chunk_t *pcr_value, chunk_t data,
784: hash_algorithm_t alg)
785: {
786: if (!this->tpm->extend_pcr(this->tpm, pcr_num, pcr_value, data, alg))
787: {
788: return FALSE;
789: }
790: DBG3(DBG_PTS, "PCR %d extended with: %#B", pcr_num, &data);
791: DBG3(DBG_PTS, "PCR %d after extension: %#B", pcr_num, pcr_value);
792:
793: return TRUE;
794: }
795:
796: METHOD(pts_t, quote, bool,
797: private_pts_t *this, tpm_quote_mode_t *quote_mode,
798: tpm_tss_quote_info_t **quote_info, chunk_t *quote_sig)
799: {
800: chunk_t pcr_value, pcr_computed;
1.1.1.2 ! misho 801: hash_algorithm_t hash_alg;
1.1 misho 802: uint32_t pcr, pcr_sel = 0;
803: enumerator_t *enumerator;
804:
1.1.1.2 ! misho 805: hash_alg = pts_meas_algo_to_hash(this->pcrs->get_pcr_algo(this->pcrs));
! 806:
1.1 misho 807: /* select PCRs */
808: DBG2(DBG_PTS, "PCR values hashed into PCR Composite:");
809: enumerator = this->pcrs->create_enumerator(this->pcrs);
810: while (enumerator->enumerate(enumerator, &pcr))
811: {
1.1.1.2 ! misho 812: if (this->tpm->read_pcr(this->tpm, pcr, &pcr_value, hash_alg))
1.1 misho 813: {
814: pcr_computed = this->pcrs->get(this->pcrs, pcr);
815: DBG2(DBG_PTS, "PCR %2d %#B %s", pcr, &pcr_value,
816: chunk_equals(pcr_value, pcr_computed) ? "ok" : "differs");
817: chunk_free(&pcr_value);
818: };
819:
820: /* add PCR to selection list */
821: pcr_sel |= (1 << pcr);
822: }
823: enumerator->destroy(enumerator);
824:
825: /* TPM Quote */
1.1.1.2 ! misho 826: return this->tpm->quote(this->tpm, this->aik_handle, pcr_sel, hash_alg,
1.1 misho 827: this->secret, quote_mode, quote_info, quote_sig);
828: }
829:
830: METHOD(pts_t, get_quote, bool,
831: private_pts_t *this, tpm_tss_quote_info_t *quote_info, chunk_t *quoted)
832: {
833: tpm_tss_pcr_composite_t *pcr_composite;
834: bool success;
835:
836: if (!this->pcrs->get_count(this->pcrs))
837: {
838: DBG1(DBG_PTS, "No extended PCR entries available, "
839: "unable to construct TPM Quote Info");
840: return FALSE;
841: }
842: if (!this->secret.ptr)
843: {
844: DBG1(DBG_PTS, "Secret assessment value unavailable, ",
845: "unable to construct TPM Quote Info");
846: return FALSE;
847: }
848: if (quote_info->get_quote_mode(quote_info) == TPM_QUOTE2_VERSION_INFO)
849: {
850: if (!this->tpm_version_info.ptr)
851: {
852: DBG1(DBG_PTS, "TPM Version Information unavailable, ",
853: "unable to construct TPM Quote Info2");
854: return FALSE;
855: }
856: quote_info->set_version_info(quote_info, this->tpm_version_info);
857: }
858: pcr_composite = this->pcrs->get_composite(this->pcrs);
859:
860: success = quote_info->get_quote(quote_info, this->secret,
861: pcr_composite, quoted);
862: chunk_free(&pcr_composite->pcr_select);
863: chunk_free(&pcr_composite->pcr_composite);
864: free(pcr_composite);
865:
866: return success;
867: }
868:
869: METHOD(pts_t, verify_quote_signature, bool,
870: private_pts_t *this, hash_algorithm_t digest_alg, chunk_t digest,
871: chunk_t signature)
872: {
873: public_key_t *aik_pubkey;
874: signature_scheme_t scheme;
875:
876: aik_pubkey = this->aik_cert->get_public_key(this->aik_cert);
877: if (!aik_pubkey)
878: {
879: DBG1(DBG_PTS, "failed to get public key from AIK certificate");
880: return FALSE;
881: }
882:
883: /* Determine signing scheme */
884: switch (aik_pubkey->get_type(aik_pubkey))
885: {
886: case KEY_RSA:
887: switch (digest_alg)
888: {
889: case HASH_SHA1:
890: scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
891: break;
892: case HASH_SHA256:
893: scheme = SIGN_RSA_EMSA_PKCS1_SHA2_256;
894: break;
895: case HASH_SHA384:
896: scheme = SIGN_RSA_EMSA_PKCS1_SHA2_384;
897: break;
898: case HASH_SHA512:
899: scheme = SIGN_RSA_EMSA_PKCS1_SHA2_512;
900: break;
901: case HASH_SHA3_256:
902: scheme = SIGN_RSA_EMSA_PKCS1_SHA3_256;
903: break;
904: case HASH_SHA3_384:
905: scheme = SIGN_RSA_EMSA_PKCS1_SHA3_384;
906: break;
907: case HASH_SHA3_512:
908: scheme = SIGN_RSA_EMSA_PKCS1_SHA3_512;
909: break;
910: default:
911: scheme = SIGN_UNKNOWN;
912: }
913: break;
914: case KEY_ECDSA:
915: switch (digest_alg)
916: {
917: case HASH_SHA256:
918: scheme = SIGN_ECDSA_256;
919: break;
920: case HASH_SHA384:
921: scheme = SIGN_ECDSA_384;
922: break;
923: case HASH_SHA512:
924: scheme = SIGN_ECDSA_521;
925: break;
926: default:
927: scheme = SIGN_UNKNOWN;
928: }
929: break;
930: default:
931: DBG1(DBG_PTS, "%N AIK key type not supported", key_type_names,
932: aik_pubkey->get_type(aik_pubkey));
933: return FALSE;
934: }
935:
936: if (!aik_pubkey->verify(aik_pubkey, scheme, NULL, digest, signature))
937: {
938: DBG1(DBG_PTS, "signature verification failed for TPM Quote Info");
939: DESTROY_IF(aik_pubkey);
940: return FALSE;
941: }
942:
943: aik_pubkey->destroy(aik_pubkey);
944: return TRUE;
945: }
946:
1.1.1.2 ! misho 947: /**
! 948: * Extracts the locality from a TPM 2.0 Version Info struct
! 949: */
! 950: static uint8_t get_tpm_locality(chunk_t tpm_version_info)
! 951: {
! 952: if (tpm_version_info.len < 4 ||
! 953: tpm_version_info.ptr[0] != 0x02 || tpm_version_info.ptr[1] != 0x00)
! 954: {
! 955: return 0;
! 956: }
! 957: else
! 958: {
! 959: return tpm_version_info.ptr[3];
! 960: }
! 961: }
! 962:
1.1 misho 963: METHOD(pts_t, get_pcrs, pts_pcr_t*,
964: private_pts_t *this)
965: {
1.1.1.2 ! misho 966: if (!this->pcrs)
! 967: {
! 968: this->pcrs = pts_pcr_create(this->tpm_version, this->algorithm,
! 969: get_tpm_locality(this->tpm_version_info));
! 970: }
1.1 misho 971: return this->pcrs;
972: }
973:
974: METHOD(pts_t, destroy, void,
975: private_pts_t *this)
976: {
977: DESTROY_IF(this->tpm);
978: DESTROY_IF(this->pcrs);
979: DESTROY_IF(this->aik_cert);
980: DESTROY_IF(this->dh);
1.1.1.2 ! misho 981: DESTROY_IF(this->symlinks);
1.1 misho 982: free(this->initiator_nonce.ptr);
983: free(this->responder_nonce.ptr);
984: free(this->secret.ptr);
985: free(this->tpm_version_info.ptr);
986: free(this);
987: }
988:
989: /**
990: * See header
991: */
992: pts_t *pts_create(bool is_imc)
993: {
994: private_pts_t *this;
995:
996: INIT(this,
997: .public = {
998: .get_proto_caps = _get_proto_caps,
999: .set_proto_caps = _set_proto_caps,
1000: .get_meas_algorithm = _get_meas_algorithm,
1001: .set_meas_algorithm = _set_meas_algorithm,
1002: .get_dh_hash_algorithm = _get_dh_hash_algorithm,
1003: .set_dh_hash_algorithm = _set_dh_hash_algorithm,
1004: .create_dh_nonce = _create_dh_nonce,
1005: .get_my_public_value = _get_my_public_value,
1006: .set_peer_public_value = _set_peer_public_value,
1007: .calculate_secret = _calculate_secret,
1008: .get_platform_id = _get_platform_id,
1009: .set_platform_id = _set_platform_id,
1.1.1.2 ! misho 1010: .extract_symlinks = _extract_symlinks,
! 1011: .get_symlinks = _get_symlinks,
! 1012: .set_symlinks = _set_symlinks,
! 1013: .get_tpm = _get_tpm,
1.1 misho 1014: .get_tpm_version_info = _get_tpm_version_info,
1015: .set_tpm_version_info = _set_tpm_version_info,
1016: .get_aik = _get_aik,
1017: .set_aik = _set_aik,
1018: .get_aik_id = _get_aik_id,
1019: .is_path_valid = _is_path_valid,
1020: .get_metadata = _get_metadata,
1021: .read_pcr = _read_pcr,
1022: .extend_pcr = _extend_pcr,
1023: .quote = _quote,
1024: .get_pcrs = _get_pcrs,
1025: .get_quote = _get_quote,
1026: .verify_quote_signature = _verify_quote_signature,
1027: .destroy = _destroy,
1028: },
1029: .is_imc = is_imc,
1030: .proto_caps = PTS_PROTO_CAPS_V,
1.1.1.2 ! misho 1031: .algorithm = PTS_MEAS_ALGO_SHA384,
! 1032: .dh_hash_algorithm = PTS_MEAS_ALGO_SHA384,
1.1 misho 1033: );
1034:
1035: if (is_imc)
1036: {
1037: this->tpm = tpm_tss_probe(TPM_VERSION_ANY);
1038: if (this->tpm)
1039: {
1040: this->proto_caps |= PTS_PROTO_CAPS_T | PTS_PROTO_CAPS_D;
1.1.1.2 ! misho 1041: this->tpm_version = this->tpm->get_version(this->tpm);
! 1042: this->tpm_version_info = chunk_clone(
! 1043: this->tpm->get_version_info(this->tpm));
1.1 misho 1044: load_aik(this);
1045: }
1046: }
1047: else
1048: {
1049: this->proto_caps |= PTS_PROTO_CAPS_T | PTS_PROTO_CAPS_D;
1.1.1.2 ! misho 1050: this->tpm_version = TPM_VERSION_2_0;
1.1 misho 1051: }
1052:
1053: return &this->public;
1054: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>