3d5e23301a42d93424c906c47c4160db596c4c19
[strongswan.git] / src / libpts / pts / pts.c
1 /*
2 * Copyright (C) 2011 Sansar Choinyambuu
3 * HSR Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "pts.h"
17
18 #include <debug.h>
19 #include <crypto/hashers/hasher.h>
20 #include <bio/bio_writer.h>
21 #include <bio/bio_reader.h>
22
23 #include <trousers/tss.h>
24 #include <trousers/trousers.h>
25
26 #include <sys/stat.h>
27 #include <sys/utsname.h>
28 #include <errno.h>
29
30 #include <openssl/rsa.h>
31 #include <openssl/evp.h>
32 #include <openssl/x509.h>
33
34 #define PTS_BUF_SIZE 4096
35
36 typedef struct private_pts_t private_pts_t;
37
38 /**
39 * Private data of a pts_t object.
40 *
41 */
42 struct private_pts_t {
43
44 /**
45 * Public pts_t interface.
46 */
47 pts_t public;
48
49 /**
50 * PTS Protocol Capabilities
51 */
52 pts_proto_caps_flag_t proto_caps;
53
54 /**
55 * PTS Measurement Algorithm
56 */
57 pts_meas_algorithms_t algorithm;
58
59 /**
60 * DH Hash Algorithm
61 */
62 pts_meas_algorithms_t dh_hash_algorithm;
63
64 /**
65 * PTS Diffie-Hellman Secret
66 */
67 diffie_hellman_t *dh;
68
69 /**
70 * PTS Diffie-Hellman Initiator Nonce
71 */
72 chunk_t initiator_nonce;
73
74 /**
75 * PTS Diffie-Hellman Responder Nonce
76 */
77 chunk_t responder_nonce;
78
79 /**
80 * Secret assessment value to be used for TPM Quote as an external data
81 */
82 chunk_t secret;
83
84 /**
85 * Platform and OS Info
86 */
87 char *platform_info;
88
89 /**
90 * TRUE if IMC-PTS, FALSE if IMV-PTS
91 */
92 bool is_imc;
93
94 /**
95 * Do we have an activated TPM
96 */
97 bool has_tpm;
98
99 /**
100 * Contains a TPM_CAP_VERSION_INFO struct
101 */
102 chunk_t tpm_version_info;
103
104 /**
105 * Contains TSS Blob structure for AIK
106 */
107 chunk_t aik_blob;
108
109 /**
110 * Contains a Attestation Identity Key or Certificate
111 */
112 certificate_t *aik;
113
114 /**
115 * List of extended PCR's with corresponding values
116 */
117 linked_list_t *pcrs;
118 };
119
120 METHOD(pts_t, get_proto_caps, pts_proto_caps_flag_t,
121 private_pts_t *this)
122 {
123 return this->proto_caps;
124 }
125
126 METHOD(pts_t, set_proto_caps, void,
127 private_pts_t *this, pts_proto_caps_flag_t flags)
128 {
129 this->proto_caps = flags;
130 DBG2(DBG_PTS, "supported PTS protocol capabilities: %s%s%s%s%s",
131 flags & PTS_PROTO_CAPS_C ? "C" : ".",
132 flags & PTS_PROTO_CAPS_V ? "V" : ".",
133 flags & PTS_PROTO_CAPS_D ? "D" : ".",
134 flags & PTS_PROTO_CAPS_T ? "T" : ".",
135 flags & PTS_PROTO_CAPS_X ? "X" : ".");
136 }
137
138 METHOD(pts_t, get_meas_algorithm, pts_meas_algorithms_t,
139 private_pts_t *this)
140 {
141 return this->algorithm;
142 }
143
144 METHOD(pts_t, set_meas_algorithm, void,
145 private_pts_t *this, pts_meas_algorithms_t algorithm)
146 {
147 hash_algorithm_t hash_alg;
148
149 hash_alg = pts_meas_algo_to_hash(algorithm);
150 DBG2(DBG_PTS, "selected PTS measurement algorithm is %N",
151 hash_algorithm_names, hash_alg);
152 if (hash_alg != HASH_UNKNOWN)
153 {
154 this->algorithm = algorithm;
155 }
156 }
157
158 METHOD(pts_t, get_dh_hash_algorithm, pts_meas_algorithms_t,
159 private_pts_t *this)
160 {
161 return this->dh_hash_algorithm;
162 }
163
164 METHOD(pts_t, set_dh_hash_algorithm, void,
165 private_pts_t *this, pts_meas_algorithms_t algorithm)
166 {
167 hash_algorithm_t hash_alg;
168
169 hash_alg = pts_meas_algo_to_hash(algorithm);
170 DBG2(DBG_PTS, "selected DH hash algorithm is %N",
171 hash_algorithm_names, hash_alg);
172 if (hash_alg != HASH_UNKNOWN)
173 {
174 this->dh_hash_algorithm = algorithm;
175 }
176 }
177
178
179 METHOD(pts_t, create_dh_nonce, bool,
180 private_pts_t *this, pts_dh_group_t group, int nonce_len)
181 {
182 diffie_hellman_group_t dh_group;
183 chunk_t *nonce;
184 rng_t *rng;
185
186 dh_group = pts_dh_group_to_ike(group);
187 DBG2(DBG_PTS, "selected PTS DH group is %N",
188 diffie_hellman_group_names, dh_group);
189 DESTROY_IF(this->dh);
190 this->dh = lib->crypto->create_dh(lib->crypto, dh_group);
191
192 rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
193 if (!rng)
194 {
195 DBG1(DBG_PTS, "no rng available");
196 return FALSE;
197 }
198 DBG2(DBG_PTS, "nonce length is %d", nonce_len);
199 nonce = this->is_imc ? &this->responder_nonce : &this->initiator_nonce;
200 chunk_free(nonce);
201 rng->allocate_bytes(rng, nonce_len, nonce);
202 rng->destroy(rng);
203
204 return TRUE;
205 }
206
207 METHOD(pts_t, get_my_public_value, void,
208 private_pts_t *this, chunk_t *value, chunk_t *nonce)
209 {
210 this->dh->get_my_public_value(this->dh, value);
211 *nonce = this->is_imc ? this->responder_nonce : this->initiator_nonce;
212 }
213
214 METHOD(pts_t, set_peer_public_value, void,
215 private_pts_t *this, chunk_t value, chunk_t nonce)
216 {
217 this->dh->set_other_public_value(this->dh, value);
218
219 nonce = chunk_clone(nonce);
220 if (this->is_imc)
221 {
222 this->initiator_nonce = nonce;
223 }
224 else
225 {
226 this->responder_nonce = nonce;
227 }
228 }
229
230 METHOD(pts_t, calculate_secret, bool,
231 private_pts_t *this)
232 {
233 hasher_t *hasher;
234 hash_algorithm_t hash_alg;
235 chunk_t shared_secret;
236
237 /* Check presence of nonces */
238 if (!this->initiator_nonce.len || !this->responder_nonce.len)
239 {
240 DBG1(DBG_PTS, "initiator and/or responder nonce is not available");
241 return FALSE;
242 }
243 DBG3(DBG_PTS, "initiator nonce: %B", &this->initiator_nonce);
244 DBG3(DBG_PTS, "responder nonce: %B", &this->responder_nonce);
245
246 /* Calculate the DH secret */
247 if (this->dh->get_shared_secret(this->dh, &shared_secret) != SUCCESS)
248 {
249 DBG1(DBG_PTS, "shared DH secret computation failed");
250 return FALSE;
251 }
252 DBG3(DBG_PTS, "shared DH secret: %B", &shared_secret);
253
254 /* Calculate the secret assessment value */
255 hash_alg = pts_meas_algo_to_hash(this->dh_hash_algorithm);
256 hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
257
258 hasher->allocate_hash(hasher, chunk_from_chars('1'), NULL);
259 hasher->allocate_hash(hasher, this->initiator_nonce, NULL);
260 hasher->allocate_hash(hasher, this->responder_nonce, NULL);
261 hasher->allocate_hash(hasher, shared_secret, &this->secret);
262 hasher->destroy(hasher);
263
264 /* The DH secret must be destroyed */
265 chunk_clear(&shared_secret);
266
267 /*
268 * Truncate the hash to 20 bytes to fit the ExternalData
269 * argument of the TPM Quote command
270 */
271 this->secret.len = min(this->secret.len, 20);
272 DBG3(DBG_PTS, "secret assessment value: %B", &this->secret);
273 return TRUE;
274 }
275
276 /**
277 * Print TPM 1.2 Version Info
278 */
279 static void print_tpm_version_info(private_pts_t *this)
280 {
281 TPM_CAP_VERSION_INFO versionInfo;
282 UINT64 offset = 0;
283 TSS_RESULT result;
284
285 result = Trspi_UnloadBlob_CAP_VERSION_INFO(&offset,
286 this->tpm_version_info.ptr, &versionInfo);
287 if (result != TSS_SUCCESS)
288 {
289 DBG1(DBG_PTS, "could not parse tpm version info: tss error 0x%x",
290 result);
291 }
292 else
293 {
294 DBG2(DBG_PTS, "TPM 1.2 Version Info: Chip Version: %hhu.%hhu.%hhu.%hhu,"
295 " Spec Level: %hu, Errata Rev: %hhu, Vendor ID: %.4s",
296 versionInfo.version.major, versionInfo.version.minor,
297 versionInfo.version.revMajor, versionInfo.version.revMinor,
298 versionInfo.specLevel, versionInfo.errataRev,
299 versionInfo.tpmVendorID);
300 }
301 }
302
303 METHOD(pts_t, get_platform_info, char*,
304 private_pts_t *this)
305 {
306 return this->platform_info;
307 }
308
309 METHOD(pts_t, set_platform_info, void,
310 private_pts_t *this, char *info)
311 {
312 free(this->platform_info);
313 this->platform_info = strdup(info);
314 }
315
316 METHOD(pts_t, get_tpm_version_info, bool,
317 private_pts_t *this, chunk_t *info)
318 {
319 if (!this->has_tpm)
320 {
321 return FALSE;
322 }
323 *info = this->tpm_version_info;
324 print_tpm_version_info(this);
325 return TRUE;
326 }
327
328 METHOD(pts_t, set_tpm_version_info, void,
329 private_pts_t *this, chunk_t info)
330 {
331 this->tpm_version_info = chunk_clone(info);
332 print_tpm_version_info(this);
333 }
334
335 /**
336 * Load an AIK Blob (TSS_TSPATTRIB_KEYBLOB_BLOB attribute)
337 */
338 static void load_aik_blob(private_pts_t *this)
339 {
340 char *blob_path;
341 FILE *fp;
342 u_int32_t aikBlobLen;
343
344 blob_path = lib->settings->get_str(lib->settings,
345 "libimcv.plugins.imc-attestation.aik_blob", NULL);
346
347 if (blob_path)
348 {
349 /* Read aik key blob from a file */
350 if ((fp = fopen(blob_path, "r")) == NULL)
351 {
352 DBG1(DBG_PTS, "unable to open AIK Blob file: %s", blob_path);
353 return;
354 }
355
356 fseek(fp, 0, SEEK_END);
357 aikBlobLen = ftell(fp);
358 fseek(fp, 0L, SEEK_SET);
359
360 this->aik_blob = chunk_alloc(aikBlobLen);
361 if (fread(this->aik_blob.ptr, 1, aikBlobLen, fp))
362 {
363 DBG2(DBG_PTS, "loaded AIK Blob from '%s'", blob_path);
364 DBG3(DBG_PTS, "AIK Blob: %B", &this->aik_blob);
365 }
366 else
367 {
368 DBG1(DBG_PTS, "unable to read AIK Blob file '%s'", blob_path);
369 }
370 fclose(fp);
371 return;
372 }
373
374 DBG1(DBG_PTS, "AIK Blob is not available");
375 }
376
377 /**
378 * Load an AIK certificate or public key
379 * the certificate having precedence over the public key if both are present
380 */
381 static void load_aik(private_pts_t *this)
382 {
383 char *cert_path, *key_path;
384
385 cert_path = lib->settings->get_str(lib->settings,
386 "libimcv.plugins.imc-attestation.aik_cert", NULL);
387 key_path = lib->settings->get_str(lib->settings,
388 "libimcv.plugins.imc-attestation.aik_key", NULL);
389
390 if (cert_path)
391 {
392 this->aik = lib->creds->create(lib->creds, CRED_CERTIFICATE,
393 CERT_X509, BUILD_FROM_FILE,
394 cert_path, BUILD_END);
395 if (this->aik)
396 {
397 DBG2(DBG_PTS, "loaded AIK certificate from '%s'", cert_path);
398 return;
399 }
400 }
401 if (key_path)
402 {
403 this->aik = lib->creds->create(lib->creds, CRED_CERTIFICATE,
404 CERT_TRUSTED_PUBKEY, BUILD_FROM_FILE,
405 key_path, BUILD_END);
406 if (this->aik)
407 {
408 DBG2(DBG_PTS, "loaded AIK public key from '%s'", key_path);
409 return;
410 }
411 }
412
413 DBG1(DBG_PTS, "neither AIK certificate nor public key is available");
414 }
415
416 METHOD(pts_t, get_aik, certificate_t*,
417 private_pts_t *this)
418 {
419 return this->aik;
420 }
421
422 METHOD(pts_t, set_aik, void,
423 private_pts_t *this, certificate_t *aik)
424 {
425 DESTROY_IF(this->aik);
426 this->aik = aik->get_ref(aik);
427 }
428
429 METHOD(pts_t, hash_file, bool,
430 private_pts_t *this, hasher_t *hasher, char *pathname, u_char *hash)
431 {
432 u_char buffer[PTS_BUF_SIZE];
433 FILE *file;
434 int bytes_read;
435
436 file = fopen(pathname, "rb");
437 if (!file)
438 {
439 DBG1(DBG_PTS," file '%s' can not be opened, %s", pathname,
440 strerror(errno));
441 return FALSE;
442 }
443 while (TRUE)
444 {
445 bytes_read = fread(buffer, 1, sizeof(buffer), file);
446 if (bytes_read > 0)
447 {
448 hasher->get_hash(hasher, chunk_create(buffer, bytes_read), NULL);
449 }
450 else
451 {
452 hasher->get_hash(hasher, chunk_empty, hash);
453 break;
454 }
455 }
456 fclose(file);
457
458 return TRUE;
459 }
460
461 /**
462 * Get the relative filename of a fully qualified file pathname
463 */
464 static char* get_filename(char *pathname)
465 {
466 char *pos, *filename;
467
468 pos = filename = pathname;
469 while (pos && *(++pos) != '\0')
470 {
471 filename = pos;
472 pos = strchr(filename, '/');
473 }
474 return filename;
475 }
476
477 METHOD(pts_t, is_path_valid, bool,
478 private_pts_t *this, char *path, pts_error_code_t *error_code)
479 {
480 struct stat st;
481
482 *error_code = 0;
483
484 if (!stat(path, &st))
485 {
486 return TRUE;
487 }
488 else if (errno == ENOENT || errno == ENOTDIR)
489 {
490 DBG1(DBG_PTS, "file/directory does not exist %s", path);
491 *error_code = TCG_PTS_FILE_NOT_FOUND;
492 }
493 else if (errno == EFAULT)
494 {
495 DBG1(DBG_PTS, "bad address %s", path);
496 *error_code = TCG_PTS_INVALID_PATH;
497 }
498 else
499 {
500 DBG1(DBG_PTS, "error: %s occured while validating path: %s",
501 strerror(errno), path);
502 return FALSE;
503 }
504
505 return TRUE;
506 }
507
508 METHOD(pts_t, do_measurements, pts_file_meas_t*,
509 private_pts_t *this, u_int16_t request_id, char *pathname, bool is_directory)
510 {
511 hasher_t *hasher;
512 hash_algorithm_t hash_alg;
513 u_char hash[HASH_SIZE_SHA384];
514 chunk_t measurement;
515 pts_file_meas_t *measurements;
516
517 /* Create a hasher */
518 hash_alg = pts_meas_algo_to_hash(this->algorithm);
519 hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
520 if (!hasher)
521 {
522 DBG1(DBG_PTS, "hasher %N not available", hash_algorithm_names, hash_alg);
523 return NULL;
524 }
525
526 /* Create a measurement object */
527 measurements = pts_file_meas_create(request_id);
528
529 /* Link the hash to the measurement and set the measurement length */
530 measurement = chunk_create(hash, hasher->get_hash_size(hasher));
531
532 if (is_directory)
533 {
534 enumerator_t *enumerator;
535 char *rel_name, *abs_name;
536 struct stat st;
537
538 enumerator = enumerator_create_directory(pathname);
539 if (!enumerator)
540 {
541 DBG1(DBG_PTS," directory '%s' can not be opened, %s", pathname,
542 strerror(errno));
543 hasher->destroy(hasher);
544 measurements->destroy(measurements);
545 return NULL;
546 }
547 while (enumerator->enumerate(enumerator, &rel_name, &abs_name, &st))
548 {
549 /* measure regular files only */
550 if (S_ISREG(st.st_mode) && *rel_name != '.')
551 {
552 if (!hash_file(this, hasher, abs_name, hash))
553 {
554 enumerator->destroy(enumerator);
555 hasher->destroy(hasher);
556 measurements->destroy(measurements);
557 return NULL;
558 }
559 DBG2(DBG_PTS, " %#B for '%s'", &measurement, rel_name);
560 measurements->add(measurements, rel_name, measurement);
561 }
562 }
563 enumerator->destroy(enumerator);
564 }
565 else
566 {
567 char *filename;
568
569 if (!hash_file(this, hasher, pathname, hash))
570 {
571 hasher->destroy(hasher);
572 measurements->destroy(measurements);
573 return NULL;
574 }
575 filename = get_filename(pathname);
576 DBG2(DBG_PTS, " %#B for '%s'", &measurement, filename);
577 measurements->add(measurements, filename, measurement);
578 }
579 hasher->destroy(hasher);
580
581 return measurements;
582 }
583
584 /**
585 * Obtain statistical information describing a file
586 */
587 static bool file_metadata(char *pathname, pts_file_metadata_t **entry)
588 {
589 struct stat st;
590 pts_file_metadata_t *this;
591
592 this = malloc_thing(pts_file_metadata_t);
593
594 if (stat(pathname, &st))
595 {
596 DBG1(DBG_PTS, "Unable to obtain statistics about '%s'", pathname);
597 return FALSE;
598 }
599
600 if (S_ISREG(st.st_mode))
601 {
602 this->type = PTS_FILE_REGULAR;
603 }
604 else if (S_ISDIR(st.st_mode))
605 {
606 this->type = PTS_FILE_DIRECTORY;
607 }
608 else if (S_ISCHR(st.st_mode))
609 {
610 this->type = PTS_FILE_CHAR_SPEC;
611 }
612 else if (S_ISBLK(st.st_mode))
613 {
614 this->type = PTS_FILE_BLOCK_SPEC;
615 }
616 else if (S_ISFIFO(st.st_mode))
617 {
618 this->type = PTS_FILE_FIFO;
619 }
620 else if (S_ISLNK(st.st_mode))
621 {
622 this->type = PTS_FILE_SYM_LINK;
623 }
624 else if (S_ISSOCK(st.st_mode))
625 {
626 this->type = PTS_FILE_SOCKET;
627 }
628 else
629 {
630 this->type = PTS_FILE_OTHER;
631 }
632
633 this->filesize = st.st_size;
634 this->created = st.st_ctime;
635 this->modified = st.st_mtime;
636 this->accessed = st.st_atime;
637 this->owner = st.st_uid;
638 this->group = st.st_gid;
639
640 *entry = this;
641 return TRUE;
642 }
643
644 METHOD(pts_t, get_metadata, pts_file_meta_t*,
645 private_pts_t *this, char *pathname, bool is_directory)
646 {
647 pts_file_meta_t *metadata;
648 pts_file_metadata_t *entry;
649
650 /* Create a metadata object */
651 metadata = pts_file_meta_create();
652
653 if (is_directory)
654 {
655 enumerator_t *enumerator;
656 char *rel_name, *abs_name;
657 struct stat st;
658
659 enumerator = enumerator_create_directory(pathname);
660 if (!enumerator)
661 {
662 DBG1(DBG_PTS," directory '%s' can not be opened, %s", pathname,
663 strerror(errno));
664 metadata->destroy(metadata);
665 return NULL;
666 }
667 while (enumerator->enumerate(enumerator, &rel_name, &abs_name, &st))
668 {
669 /* measure regular files only */
670 if (S_ISREG(st.st_mode) && *rel_name != '.')
671 {
672 if (!file_metadata(abs_name, &entry))
673 {
674 enumerator->destroy(enumerator);
675 metadata->destroy(metadata);
676 return NULL;
677 }
678 entry->filename = strdup(rel_name);
679 metadata->add(metadata, entry);
680 }
681 }
682 enumerator->destroy(enumerator);
683 }
684 else
685 {
686 if (!file_metadata(pathname, &entry))
687 {
688 metadata->destroy(metadata);
689 return NULL;
690 }
691 entry->filename = strdup(get_filename(pathname));
692 metadata->add(metadata, entry);
693 }
694
695 return metadata;
696 }
697
698 METHOD(pts_t, read_pcr, bool,
699 private_pts_t *this, u_int32_t pcr_num, chunk_t *output)
700 {
701 TSS_HCONTEXT hContext;
702 TSS_HTPM hTPM;
703 TSS_RESULT result;
704 u_int32_t pcr_length;
705 chunk_t pcr_value;
706
707 result = Tspi_Context_Create(&hContext);
708 if (result != TSS_SUCCESS)
709 {
710 DBG1(DBG_PTS, "TPM context could not be created: tss error 0x%x",
711 result);
712 return FALSE;
713 }
714
715 result = Tspi_Context_Connect(hContext, NULL);
716 if (result != TSS_SUCCESS)
717 {
718 goto err;
719 }
720 result = Tspi_Context_GetTpmObject (hContext, &hTPM);
721 if (result != TSS_SUCCESS)
722 {
723 goto err;
724 }
725 pcr_value = chunk_alloc(PCR_LEN);
726 result = Tspi_TPM_PcrRead(hTPM, pcr_num, &pcr_length, &pcr_value.ptr);
727 if (result != TSS_SUCCESS)
728 {
729 goto err;
730 }
731
732 *output = pcr_value;
733 *output = chunk_clone(*output);
734
735 chunk_clear(&pcr_value);
736 DBG3(DBG_PTS, "PCR %d value:%B", pcr_num, output);
737 Tspi_Context_Close(hContext);
738 return TRUE;
739
740 err:
741 chunk_clear(&pcr_value);
742 DBG1(DBG_PTS, "TPM not available: tss error 0x%x", result);
743 Tspi_Context_Close(hContext);
744 return FALSE;
745 }
746
747 METHOD(pts_t, extend_pcr, bool,
748 private_pts_t *this, u_int32_t pcr_num, chunk_t input, chunk_t *output)
749 {
750 TSS_HCONTEXT hContext;
751 TSS_HTPM hTPM;
752 TSS_RESULT result;
753 u_int32_t pcr_length;
754 chunk_t pcr_value;
755
756 result = Tspi_Context_Create(&hContext);
757 if (result != TSS_SUCCESS)
758 {
759 DBG1(DBG_PTS, "TPM context could not be created: tss error 0x%x",
760 result);
761 return FALSE;
762 }
763 result = Tspi_Context_Connect(hContext, NULL);
764 if (result != TSS_SUCCESS)
765 {
766 goto err;
767 }
768 result = Tspi_Context_GetTpmObject (hContext, &hTPM);
769 if (result != TSS_SUCCESS)
770 {
771 goto err;
772 }
773
774 pcr_value = chunk_alloc(PCR_LEN);
775 result = Tspi_TPM_PcrExtend(hTPM, pcr_num, PCR_LEN, input.ptr,
776 NULL, &pcr_length, &pcr_value.ptr);
777 if (result != TSS_SUCCESS)
778 {
779 goto err;
780 }
781
782 *output = pcr_value;
783 *output = chunk_clone(*output);
784
785 chunk_clear(&pcr_value);
786 Tspi_Context_Close(hContext);
787 DBG3(DBG_PTS, "PCR %d extended with: %B", pcr_num, &input);
788 DBG3(DBG_PTS, "PCR %d value after extend: %B", pcr_num, output);
789 return TRUE;
790
791 err:
792 chunk_clear(&pcr_value);
793 DBG1(DBG_PTS, "TPM not available: tss error 0x%x", result);
794 Tspi_Context_Close(hContext);
795 return FALSE;
796 }
797
798 METHOD(pts_t, quote_tpm, bool,
799 private_pts_t *this, u_int32_t *pcrs, u_int32_t num_of_pcrs,
800 chunk_t *pcr_composite, chunk_t *quote_signature)
801 {
802 TSS_HCONTEXT hContext;
803 TSS_HTPM hTPM;
804 TSS_HKEY hAIK;
805 TSS_HKEY hSRK;
806 TSS_HPOLICY srkUsagePolicy;
807 TSS_UUID SRK_UUID = TSS_UUID_SRK;
808 BYTE secret[] = TSS_WELL_KNOWN_SECRET;
809 TSS_HPCRS hPcrComposite;
810 TSS_VALIDATION valData;
811 u_int32_t i;
812 TSS_RESULT result;
813 chunk_t pcr_comp, quote_sign;
814
815 result = Tspi_Context_Create(&hContext);
816 if (result != TSS_SUCCESS)
817 {
818 DBG1(DBG_PTS, "TPM context could not be created: tss error 0x%x",
819 result);
820 return FALSE;
821 }
822 result = Tspi_Context_Connect(hContext, NULL);
823 if (result != TSS_SUCCESS)
824 {
825 goto err1;
826 }
827 result = Tspi_Context_GetTpmObject (hContext, &hTPM);
828 if (result != TSS_SUCCESS)
829 {
830 goto err1;
831 }
832
833 /* Retrieve SRK from TPM and set the authentication to well known secret*/
834 result = Tspi_Context_LoadKeyByUUID(hContext, TSS_PS_TYPE_SYSTEM,
835 SRK_UUID, &hSRK);
836 if (result != TSS_SUCCESS)
837 {
838 goto err1;
839 }
840
841 result = Tspi_GetPolicyObject(hSRK, TSS_POLICY_USAGE, &srkUsagePolicy);
842 if (result != TSS_SUCCESS)
843 {
844 goto err1;
845 }
846 result = Tspi_Policy_SetSecret(srkUsagePolicy, TSS_SECRET_MODE_SHA1,
847 20, secret);
848 if (result != TSS_SUCCESS)
849 {
850 goto err1;
851 }
852
853 result = Tspi_Context_LoadKeyByBlob (hContext, hSRK, this->aik_blob.len,
854 this->aik_blob.ptr, &hAIK);
855 if (result != TSS_SUCCESS)
856 {
857 goto err1;
858 }
859
860 /* Create PCR composite object */
861 result = Tspi_Context_CreateObject(hContext,
862 TSS_OBJECT_TYPE_PCRS, 0, &hPcrComposite);
863 if (result != TSS_SUCCESS)
864 {
865 goto err2;
866 }
867
868 /* Select PCR's */
869 for (i = 0; i < num_of_pcrs ; i++)
870 {
871 if (pcrs[i] < 0 || pcrs[i] >= MAX_NUM_PCR )
872 {
873 DBG1(DBG_PTS, "Invalid PCR number: %d", pcrs[i]);
874 goto err3;
875 }
876 result = Tspi_PcrComposite_SelectPcrIndex(hPcrComposite, pcrs[i]);
877 if (result != TSS_SUCCESS)
878 {
879 goto err3;
880 }
881 }
882
883 /* Set the Validation Data */
884 valData.ulExternalDataLength = this->secret.len;
885 valData.rgbExternalData = (BYTE *)this->secret.ptr;
886
887
888 /* TPM Quote */
889 result = Tspi_TPM_Quote(hTPM, hAIK, hPcrComposite, &valData);
890 if (result != TSS_SUCCESS)
891 {
892 goto err4;
893 }
894
895 /* Set output chunks */
896 pcr_comp = chunk_alloc(HASH_SIZE_SHA1);
897 memcpy(pcr_comp.ptr, valData.rgbData + 8, HASH_SIZE_SHA1);
898 *pcr_composite = pcr_comp;
899 *pcr_composite = chunk_clone(*pcr_composite);
900 DBG3(DBG_PTS, "Hash of PCR Composite: %B",pcr_composite);
901
902 chunk_t tmp = chunk_create(valData.rgbData, valData.ulDataLength);
903 DBG3(DBG_PTS, "TPM Quote Info: %B",&tmp);
904
905 quote_sign = chunk_alloc(valData.ulValidationDataLength);
906 memcpy(quote_sign.ptr, valData.rgbValidationData,
907 valData.ulValidationDataLength);
908 *quote_signature = quote_sign;
909 *quote_signature = chunk_clone(*quote_signature);
910 DBG3(DBG_PTS, "TOM Quote Signature: %B",quote_signature);
911
912 chunk_clear(&quote_sign);
913 Tspi_Context_FreeMemory(hContext, NULL);
914 Tspi_Context_CloseObject(hContext, hPcrComposite);
915 Tspi_Context_CloseObject(hContext, hAIK);
916 Tspi_Context_Close(hContext);
917 free(pcrs);
918 return TRUE;
919
920 /* Cleanup */
921 err4:
922 Tspi_Context_FreeMemory(hContext, NULL);
923
924 err3:
925 Tspi_Context_CloseObject(hContext, hPcrComposite);
926
927 err2:
928 Tspi_Context_CloseObject(hContext, hAIK);
929
930 err1:
931 Tspi_Context_Close(hContext);
932 free(pcrs);
933 DBG1(DBG_PTS, "TPM not available: tss error 0x%x", result);
934 return FALSE;
935 }
936
937 /**
938 * Comparison function for pcr_entry_t struct
939 */
940 static int pcr_entry_compare(const pcr_entry_t *a, const pcr_entry_t *b)
941 {
942 return (a->pcr_number - b->pcr_number);
943 }
944
945 static int pcr_entry_compare_qsort(const void *a, const void *b)
946 {
947 return pcr_entry_compare(*(const pcr_entry_t *const *)a
948 , *(const pcr_entry_t *const *)b);
949 }
950
951 METHOD(pts_t, add_pcr_entry, void,
952 private_pts_t *this, pcr_entry_t *new)
953 {
954 enumerator_t *e;
955 pcr_entry_t *entry;
956
957 if (!this->pcrs)
958 {
959 this->pcrs = linked_list_create();
960 }
961
962 e = this->pcrs->create_enumerator(this->pcrs);
963 while (e->enumerate(e, &entry))
964 {
965 if (entry->pcr_number == new->pcr_number)
966 {
967 DBG3(DBG_PTS, "updating already added PCR%d value",
968 entry->pcr_number);
969 this->pcrs->remove_at(this->pcrs, e);
970 free(entry);
971 break;
972 }
973 }
974 DESTROY_IF(e);
975 this->pcrs->insert_last(this->pcrs, new);
976 }
977
978 /**
979 * Get the maximum PCR index received in pcr_after_value field
980 */
981 static u_int32_t get_max_pcr_index(private_pts_t *this)
982 {
983 enumerator_t *e;
984 pcr_entry_t *pcr_entry;
985 u_int32_t ret = 0;
986
987 if (this->pcrs->get_count(this->pcrs) == 0)
988 {
989 return -1;
990 }
991
992 e = this->pcrs->create_enumerator(this->pcrs);
993 while (e->enumerate(e, &pcr_entry))
994 {
995 if (pcr_entry->pcr_number > ret)
996 {
997 ret = pcr_entry->pcr_number;
998 }
999 }
1000 e->destroy(e);
1001
1002 return ret;
1003 }
1004
1005 METHOD(pts_t, does_pcr_value_match, bool,
1006 private_pts_t *this, chunk_t pcr_after_value)
1007 {
1008 enumerator_t *e;
1009 pcr_entry_t *entry;
1010
1011 if (!this->pcrs)
1012 {
1013 this->pcrs = linked_list_create();
1014 }
1015
1016 e = this->pcrs->create_enumerator(this->pcrs);
1017 while (e->enumerate(e, &entry))
1018 {
1019 if (entry->pcr_number == new->pcr_number)
1020 {
1021 DBG4(DBG_PTS, "updating already added PCR%d value",
1022 entry->pcr_number);
1023 this->pcrs->remove_at(this->pcrs, e);
1024 free(entry);
1025 break;
1026 }
1027 }
1028 DESTROY_IF(e);
1029
1030 this->pcrs->insert_last(this->pcrs, new);
1031
1032 qsort(this->pcrs, this->pcrs->get_count(this->pcrs),
1033 sizeof(pcr_entry_t *), pcr_entry_compare_qsort);
1034 }
1035
1036 /**
1037 * 1. build a TCPA_PCR_COMPOSITE structure which contains (pcrCompositeBuf)
1038 * TCPA_PCR_SELECTION structure (bitmask length + bitmask)
1039 * UINT32 (network order) gives the number of bytes following (pcr entries * 20)
1040 * TCPA_PCRVALUE[] with the pcr values
1041 *
1042 * The first two bytes of the message represent the length
1043 * of the bitmask that follows. The bitmask represents the
1044 * requested PCRs to be quoted.
1045 *
1046 * TPM Main-Part 2 TPM Structures_v1.2 8.1
1047 * The bitmask is in big endian order"
1048 *
1049 * BYTE 1 BYTE 2 ...
1050 * Bit: 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 ...
1051 * Pcr: 7 6 5 4 3 2 1 0 15 14 13 12 11 10 9 8 ...
1052 *
1053 * 2. SHA1(pcrCompositeBuf)
1054 *
1055 * 3. build a TCPA_QUOTE_INFO structure which contains
1056 * 4 bytes of version
1057 * 4 bytes 'Q' 'U' 'O' 'T'
1058 * 20 byte SHA1 of TCPA_PCR_COMPOSITE
1059 * 20 byte nonce
1060 */
1061
1062 METHOD(pts_t, get_quote_info, bool,
1063 private_pts_t *this, pts_meas_algorithms_t composite_algo,
1064 chunk_t *out_pcr_composite, chunk_t *out_quote_info)
1065 {
1066 enumerator_t *e;
1067 pcr_entry_t *pcr_entry;
1068 chunk_t pcr_composite, hash_pcr_composite;
1069 u_int32_t pcr_composite_len, i, maximum_pcr_index, bitmask_len;
1070 bio_writer_t *writer;
1071 hasher_t *hasher;
1072
1073 maximum_pcr_index = get_max_pcr_index(this);
1074 if (maximum_pcr_index == -1)
1075 {
1076 DBG1(DBG_PTS, "PCR entries unavailable, unable to construct "
1077 "TPM Quote Info");
1078 return FALSE;
1079 }
1080
1081 bitmask_len = maximum_pcr_index/8 +1;
1082 u_int8_t mask_bytes[MAX_NUM_PCR/8] = {0};
1083
1084 pcr_composite_len = 2 + bitmask_len + 4 +
1085 this->pcrs->get_count(this->pcrs) * PCR_LEN;
1086
1087 writer = bio_writer_create(pcr_composite_len);
1088 /* Lenght of the bist mask field */
1089 writer->write_uint16(writer, bitmask_len);
1090 /* Bit mask indicating selected PCRs */
1091 e = this->pcrs->create_enumerator(this->pcrs);
1092 while (e->enumerate(e, &pcr_entry))
1093 {
1094 u_int32_t index = pcr_entry->pcr_number;
1095 mask_bytes[index / 8] |= (1 << (index % 8));
1096 }
1097 e->destroy(e);
1098
1099 for (i = 0; i< bitmask_len ; i++)
1100 {
1101 writer->write_uint8(writer, mask_bytes[i]);
1102 }
1103
1104 /* Lenght of the pcr entries */
1105 writer->write_uint32(writer, this->pcrs->get_count(this->pcrs) * PCR_LEN);
1106 /* Actual PCR values */
1107 e = this->pcrs->create_enumerator(this->pcrs);
1108 while (e->enumerate(e, &pcr_entry))
1109 {
1110 writer->write_data(writer, chunk_create(pcr_entry->pcr_value, PCR_LEN));
1111 }
1112 free(pcr_entry);
1113 e->destroy(e);
1114
1115 /* PCR Composite structure */
1116 pcr_composite = chunk_clone(writer->get_buf(writer));
1117 DBG3(DBG_PTS, "PCR Composite: %B", &pcr_composite);
1118 writer->destroy(writer);
1119
1120 writer = bio_writer_create(TPM_QUOTE_INFO_LEN);
1121 /* Version number */
1122 writer->write_uint8(writer, 1);
1123 writer->write_uint8(writer, 1);
1124 writer->write_uint8(writer, 0);
1125 writer->write_uint8(writer, 0);
1126
1127 /* Magic QUOT value, depends on TPM Ordinal */
1128 writer->write_uint8(writer, 'Q');
1129 writer->write_uint8(writer, 'U');
1130 writer->write_uint8(writer, 'O');
1131 writer->write_uint8(writer, 'T');
1132
1133 /* Output the TPM_PCR_COMPOSITE expected from IMC */
1134 if (composite_algo)
1135 {
1136 hash_algorithm_t algo;
1137
1138 algo = pts_meas_algo_to_hash(composite_algo);
1139 hasher = lib->crypto->create_hasher(lib->crypto, algo);
1140
1141 /* Hash the PCR Composite Structure */
1142 hasher->allocate_hash(hasher, pcr_composite, out_pcr_composite);
1143 DBG3(DBG_PTS, "Hash of calculated PCR Composite: %B", out_pcr_composite);
1144 hasher->destroy(hasher);
1145 }
1146 else
1147 {
1148 *out_pcr_composite = chunk_clone(pcr_composite);
1149 DBG3(DBG_PTS, "calculated PCR Composite: %B", out_pcr_composite);
1150 }
1151
1152 /* SHA1 hash of PCR Composite to construct TPM_QUOTE_INFO */
1153 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
1154 hasher->allocate_hash(hasher, pcr_composite, &hash_pcr_composite);
1155 hasher->destroy(hasher);
1156
1157 writer->write_data(writer, hash_pcr_composite);
1158 chunk_clear(&pcr_composite);
1159 chunk_clear(&hash_pcr_composite);
1160
1161 /* Hash the PCR Composite Structure */
1162 hasher->allocate_hash(hasher, pcr_composite, out_pcr_composite);
1163 DBG4(DBG_PTS, "Hash of calculated PCR Composite: %B", out_pcr_composite);
1164 hasher->destroy(hasher);
1165 }
1166 else
1167 {
1168 *out_pcr_composite = chunk_clone(pcr_composite);
1169 DBG4(DBG_PTS, "calculated PCR Composite: %B", out_pcr_composite);
1170 }
1171
1172 /* SHA1 hash of PCR Composite to construct TPM_QUOTE_INFO */
1173 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
1174 hasher->allocate_hash(hasher, pcr_composite, &hash_pcr_composite);
1175 hasher->destroy(hasher);
1176
1177 writer->write_data(writer, hash_pcr_composite);
1178 chunk_clear(&pcr_composite);
1179 chunk_clear(&hash_pcr_composite);
1180
1181 if (!this->secret.ptr)
1182 {
1183 DBG1(DBG_PTS, "Secret assessment value unavailable",
1184 "unable to construct TPM Quote Info");
1185 chunk_clear(out_pcr_composite);
1186 writer->destroy(writer);
1187 return FALSE;
1188 }
1189 /* Secret assessment value 20 bytes (nonce) */
1190 writer->write_data(writer, this->secret);
1191 /* TPM Quote Info */
1192 *out_quote_info = chunk_clone(writer->get_buf(writer));
1193 DBG3(DBG_PTS, "Calculated TPM Quote Info: %B", out_quote_info);
1194 writer->destroy(writer);
1195
1196 return TRUE;
1197 }
1198
1199 METHOD(pts_t, verify_quote_signature, bool,
1200 private_pts_t *this, chunk_t data, chunk_t signature)
1201 {
1202 public_key_t *aik_pub_key;
1203 chunk_t key_encoding;
1204 EVP_PKEY *pkey = NULL;
1205 RSA *rsa = NULL;
1206 unsigned char *p;
1207
1208 aik_pub_key = this->aik->get_public_key(this->aik);
1209 if (!aik_pub_key)
1210 {
1211 DBG1(DBG_PTS, "failed to get public key from AIK certificate");
1212 return FALSE;
1213 }
1214
1215 if (!aik_pub_key->verify(aik_pub_key, SIGN_RSA_EMSA_PKCS1_SHA1,
1216 data, signature))
1217 {
1218 DBG1(DBG_PTS, "signature verification failed for TPM Quote Info");
1219 DESTROY_IF(aik_pub_key);
1220 return FALSE;
1221 }
1222 */
1223
1224 if (!aik_pub_key->get_encoding(aik_pub_key,
1225 PUBKEY_SPKI_ASN1_DER, &key_encoding))
1226 {
1227 DBG1(DBG_PTS, "failed to get encoding of AIK public key");
1228 goto cleanup;
1229 }
1230
1231 p = key_encoding.ptr;
1232 pkey = d2i_PUBKEY(NULL, (const unsigned char**)&p, key_encoding.len);
1233 if (!pkey)
1234 {
1235 DBG1(DBG_PTS, "failed to get EVP_PKEY object from AIK public key");
1236 goto cleanup;
1237 }
1238
1239 rsa = EVP_PKEY_get1_RSA(pkey);
1240 if (!rsa)
1241 {
1242 DBG1(DBG_PTS, "failed to get RSA object from EVP_PKEY");
1243 goto cleanup;
1244 }
1245
1246 if (RSA_verify(NID_sha1, data.ptr, data.len,
1247 signature.ptr, signature.len, rsa) != 1)
1248 {
1249 DBG1(DBG_PTS, "signature verification failed for TPM Quote Info");
1250 goto cleanup;
1251 }
1252
1253 RSA_free(rsa);
1254 EVP_PKEY_free(pkey);
1255 if (key_encoding.ptr)
1256 {
1257 chunk_clear(&key_encoding);
1258 }
1259 aik_pub_key->destroy(aik_pub_key);
1260 return TRUE;
1261
1262 cleanup:
1263 if (rsa)
1264 {
1265 RSA_free(rsa);
1266 }
1267 if (pkey)
1268 {
1269 EVP_PKEY_free(pkey);
1270 }
1271 if (key_encoding.ptr)
1272 {
1273 chunk_clear(&key_encoding);
1274 }
1275 DESTROY_IF(aik_pub_key);
1276 return FALSE;
1277 }
1278
1279 METHOD(pts_t, destroy, void,
1280 private_pts_t *this)
1281 {
1282 DESTROY_IF(this->aik);
1283 DESTROY_IF(this->dh);
1284 DESTROY_IF(this->pcrs);
1285 free(this->initiator_nonce.ptr);
1286 free(this->responder_nonce.ptr);
1287 free(this->secret.ptr);
1288 free(this->platform_info);
1289 free(this->aik_blob.ptr);
1290 free(this->tpm_version_info.ptr);
1291 free(this);
1292 }
1293
1294 /**
1295 * Determine Linux distribution and hardware platform
1296 */
1297 static char* extract_platform_info(void)
1298 {
1299 FILE *file;
1300 char buf[BUF_LEN], *pos, *value = NULL;
1301 int i, len;
1302 struct utsname uninfo;
1303
1304 /* Linux/Unix distribution release info (from http://linuxmafia.com) */
1305 const char* releases[] = {
1306 "/etc/lsb-release", "/etc/debian_version",
1307 "/etc/SuSE-release", "/etc/novell-release",
1308 "/etc/sles-release", "/etc/redhat-release",
1309 "/etc/fedora-release", "/etc/gentoo-release",
1310 "/etc/slackware-version", "/etc/annvix-release",
1311 "/etc/arch-release", "/etc/arklinux-release",
1312 "/etc/aurox-release", "/etc/blackcat-release",
1313 "/etc/cobalt-release", "/etc/conectiva-release",
1314 "/etc/debian_release", "/etc/immunix-release",
1315 "/etc/lfs-release", "/etc/linuxppc-release",
1316 "/etc/mandrake-release", "/etc/mandriva-release",
1317 "/etc/mandrakelinux-release", "/etc/mklinux-release",
1318 "/etc/pld-release", "/etc/redhat_version",
1319 "/etc/slackware-release", "/etc/e-smith-release",
1320 "/etc/release", "/etc/sun-release",
1321 "/etc/tinysofa-release", "/etc/turbolinux-release",
1322 "/etc/ultrapenguin-release", "/etc/UnitedLinux-release",
1323 "/etc/va-release", "/etc/yellowdog-release"
1324 };
1325
1326 const char description[] = "DISTRIB_DESCRIPTION=\"";
1327
1328 for (i = 0; i < countof(releases); i++)
1329 {
1330 file = fopen(releases[i], "r");
1331 if (!file)
1332 {
1333 continue;
1334 }
1335 fseek(file, 0, SEEK_END);
1336 len = min(ftell(file), sizeof(buf)-1);
1337 rewind(file);
1338 buf[len] = '\0';
1339 if (fread(buf, 1, len, file) != len)
1340 {
1341 DBG1(DBG_PTS, "failed to read file '%s'", releases[i]);
1342 fclose(file);
1343 return NULL;
1344 }
1345 fclose(file);
1346
1347 if (i == 0) /* LSB release */
1348 {
1349 pos = strstr(buf, description);
1350 if (!pos)
1351 {
1352 DBG1(DBG_PTS, "failed to find begin of lsb-release "
1353 "DESCRIPTION field");
1354 return NULL;
1355 }
1356 value = pos + strlen(description);
1357 pos = strchr(value, '"');
1358 if (!pos)
1359 {
1360 DBG1(DBG_PTS, "failed to find end of lsb-release "
1361 "DESCRIPTION field");
1362 return NULL;
1363 }
1364 }
1365 else
1366 {
1367 value = buf;
1368 pos = strchr(value, '\n');
1369 if (!pos)
1370 {
1371 DBG1(DBG_PTS, "failed to find end of release string");
1372 return NULL;
1373 }
1374 }
1375 break;
1376 }
1377
1378 if (!value)
1379 {
1380 DBG1(DBG_PTS, "no distribution release file found");
1381 return NULL;
1382 }
1383
1384 if (uname(&uninfo) < 0)
1385 {
1386 DBG1(DBG_PTS, "could not retrieve machine architecture");
1387 return NULL;
1388 }
1389
1390 *pos++ = ' ';
1391 len = sizeof(buf)-1 + (pos - buf);
1392 strncpy(pos, uninfo.machine, len);
1393
1394 DBG1(DBG_PTS, "platform is '%s'", value);
1395 return strdup(value);
1396 }
1397
1398 /**
1399 * Check for a TPM by querying for TPM Version Info
1400 */
1401 static bool has_tpm(private_pts_t *this)
1402 {
1403 TSS_HCONTEXT hContext;
1404 TSS_HTPM hTPM;
1405 TSS_RESULT result;
1406 u_int32_t version_info_len;
1407
1408 result = Tspi_Context_Create(&hContext);
1409 if (result != TSS_SUCCESS)
1410 {
1411 DBG1(DBG_PTS, "TPM context could not be created: tss error 0x%x",
1412 result);
1413 return FALSE;
1414 }
1415 result = Tspi_Context_Connect(hContext, NULL);
1416 if (result != TSS_SUCCESS)
1417 {
1418 goto err;
1419 }
1420 result = Tspi_Context_GetTpmObject (hContext, &hTPM);
1421 if (result != TSS_SUCCESS)
1422 {
1423 goto err;
1424 }
1425 result = Tspi_TPM_GetCapability(hTPM, TSS_TPMCAP_VERSION_VAL, 0, NULL,
1426 &version_info_len,
1427 &this->tpm_version_info.ptr);
1428 this->tpm_version_info.len = version_info_len;
1429 if (result != TSS_SUCCESS)
1430 {
1431 goto err;
1432 }
1433 this->tpm_version_info = chunk_clone(this->tpm_version_info);
1434
1435 Tspi_Context_FreeMemory(hContext, NULL);
1436 Tspi_Context_Close(hContext);
1437 return TRUE;
1438
1439 err:
1440 DBG1(DBG_PTS, "TPM not available: tss error 0x%x", result);
1441 Tspi_Context_FreeMemory(hContext, NULL);
1442 Tspi_Context_Close(hContext);
1443 return FALSE;
1444 }
1445
1446 /**
1447 * See header
1448 */
1449 pts_t *pts_create(bool is_imc)
1450 {
1451 private_pts_t *this;
1452
1453 INIT(this,
1454 .public = {
1455 .get_proto_caps = _get_proto_caps,
1456 .set_proto_caps = _set_proto_caps,
1457 .get_meas_algorithm = _get_meas_algorithm,
1458 .set_meas_algorithm = _set_meas_algorithm,
1459 .get_dh_hash_algorithm = _get_dh_hash_algorithm,
1460 .set_dh_hash_algorithm = _set_dh_hash_algorithm,
1461 .create_dh_nonce = _create_dh_nonce,
1462 .get_my_public_value = _get_my_public_value,
1463 .set_peer_public_value = _set_peer_public_value,
1464 .calculate_secret = _calculate_secret,
1465 .get_platform_info = _get_platform_info,
1466 .set_platform_info = _set_platform_info,
1467 .get_tpm_version_info = _get_tpm_version_info,
1468 .set_tpm_version_info = _set_tpm_version_info,
1469 .get_aik = _get_aik,
1470 .set_aik = _set_aik,
1471 .is_path_valid = _is_path_valid,
1472 .hash_file = _hash_file,
1473 .do_measurements = _do_measurements,
1474 .get_metadata = _get_metadata,
1475 .read_pcr = _read_pcr,
1476 .extend_pcr = _extend_pcr,
1477 .quote_tpm = _quote_tpm,
1478 .add_pcr_entry = _add_pcr_entry,
1479 .get_quote_info = _get_quote_info,
1480 .verify_quote_signature = _verify_quote_signature,
1481 .destroy = _destroy,
1482 },
1483 .is_imc = is_imc,
1484 .proto_caps = PTS_PROTO_CAPS_V,
1485 .algorithm = PTS_MEAS_ALGO_SHA256,
1486 .dh_hash_algorithm = PTS_MEAS_ALGO_SHA256,
1487 );
1488
1489 if (is_imc)
1490 {
1491 this->platform_info = extract_platform_info();
1492
1493 if (has_tpm(this))
1494 {
1495 this->has_tpm = TRUE;
1496 this->proto_caps |= PTS_PROTO_CAPS_T | PTS_PROTO_CAPS_D;
1497 load_aik(this);
1498 load_aik_blob(this);
1499 }
1500 }
1501 else
1502 {
1503 this->proto_caps |= PTS_PROTO_CAPS_T | PTS_PROTO_CAPS_D;
1504 }
1505
1506 return &this->public;
1507 }