libimcv: No need to load AIK pubkey if AIK certificate is available
[strongswan.git] / src / libimcv / pts / pts.c
1 /*
2 * Copyright (C) 2011-2012 Sansar Choinyambuu
3 * Copyright (C) 2012-2016 Andreas Steffen
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.h>
25 #include <tpm_tss_trousers.h>
26
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <libgen.h>
30 #include <unistd.h>
31 #include <errno.h>
32
33 #ifndef TPM_TAG_QUOTE_INFO2
34 #define TPM_TAG_QUOTE_INFO2 0x0036
35 #endif
36 #ifndef TPM_LOC_ZERO
37 #define TPM_LOC_ZERO 0x01
38 #endif
39
40 typedef struct private_pts_t private_pts_t;
41
42 /**
43 * Private data of a pts_t object.
44 *
45 */
46 struct private_pts_t {
47
48 /**
49 * Public pts_t interface.
50 */
51 pts_t public;
52
53 /**
54 * PTS Protocol Capabilities
55 */
56 pts_proto_caps_flag_t proto_caps;
57
58 /**
59 * PTS Measurement Algorithm
60 */
61 pts_meas_algorithms_t algorithm;
62
63 /**
64 * DH Hash Algorithm
65 */
66 pts_meas_algorithms_t dh_hash_algorithm;
67
68 /**
69 * PTS Diffie-Hellman Secret
70 */
71 diffie_hellman_t *dh;
72
73 /**
74 * PTS Diffie-Hellman Initiator Nonce
75 */
76 chunk_t initiator_nonce;
77
78 /**
79 * PTS Diffie-Hellman Responder Nonce
80 */
81 chunk_t responder_nonce;
82
83 /**
84 * Secret assessment value to be used for TPM Quote as an external data
85 */
86 chunk_t secret;
87
88 /**
89 * Primary key of platform entry in database
90 */
91 int platform_id;
92
93 /**
94 * TRUE if IMC-PTS, FALSE if IMV-PTS
95 */
96 bool is_imc;
97
98 /**
99 * Active TPM
100 */
101 tpm_tss_t *tpm;
102
103 /**
104 * Contains a TPM_CAP_VERSION_INFO struct
105 */
106 chunk_t tpm_version_info;
107
108 /**
109 * AIK object handle
110 */
111 uint32_t aik_handle;
112
113 /**
114 * Contains an Attestation Identity Key Certificate
115 */
116 certificate_t *aik_cert;
117
118 /**
119 * Primary key referening AIK in database
120 */
121 int aik_id;
122
123 /**
124 * Shadow PCR set
125 */
126 pts_pcr_t *pcrs;
127
128 };
129
130 METHOD(pts_t, get_proto_caps, pts_proto_caps_flag_t,
131 private_pts_t *this)
132 {
133 return this->proto_caps;
134 }
135
136 METHOD(pts_t, set_proto_caps, void,
137 private_pts_t *this, pts_proto_caps_flag_t flags)
138 {
139 this->proto_caps = flags;
140 DBG2(DBG_PTS, "supported PTS protocol capabilities: %s%s%s%s%s",
141 flags & PTS_PROTO_CAPS_C ? "C" : ".",
142 flags & PTS_PROTO_CAPS_V ? "V" : ".",
143 flags & PTS_PROTO_CAPS_D ? "D" : ".",
144 flags & PTS_PROTO_CAPS_T ? "T" : ".",
145 flags & PTS_PROTO_CAPS_X ? "X" : ".");
146 }
147
148 METHOD(pts_t, get_meas_algorithm, pts_meas_algorithms_t,
149 private_pts_t *this)
150 {
151 return this->algorithm;
152 }
153
154 METHOD(pts_t, set_meas_algorithm, void,
155 private_pts_t *this, pts_meas_algorithms_t algorithm)
156 {
157 hash_algorithm_t hash_alg;
158
159 hash_alg = pts_meas_algo_to_hash(algorithm);
160 DBG2(DBG_PTS, "selected PTS measurement algorithm is %N",
161 hash_algorithm_names, hash_alg);
162 if (hash_alg != HASH_UNKNOWN)
163 {
164 this->algorithm = algorithm;
165 }
166 }
167
168 METHOD(pts_t, get_dh_hash_algorithm, pts_meas_algorithms_t,
169 private_pts_t *this)
170 {
171 return this->dh_hash_algorithm;
172 }
173
174 METHOD(pts_t, set_dh_hash_algorithm, void,
175 private_pts_t *this, pts_meas_algorithms_t algorithm)
176 {
177 hash_algorithm_t hash_alg;
178
179 hash_alg = pts_meas_algo_to_hash(algorithm);
180 DBG2(DBG_PTS, "selected DH hash algorithm is %N",
181 hash_algorithm_names, hash_alg);
182 if (hash_alg != HASH_UNKNOWN)
183 {
184 this->dh_hash_algorithm = algorithm;
185 }
186 }
187
188 METHOD(pts_t, create_dh_nonce, bool,
189 private_pts_t *this, pts_dh_group_t group, int nonce_len)
190 {
191 diffie_hellman_group_t dh_group;
192 chunk_t *nonce;
193 rng_t *rng;
194
195 dh_group = pts_dh_group_to_ike(group);
196 DBG2(DBG_PTS, "selected PTS DH group is %N",
197 diffie_hellman_group_names, dh_group);
198 DESTROY_IF(this->dh);
199 this->dh = lib->crypto->create_dh(lib->crypto, dh_group);
200
201 rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
202 if (!rng)
203 {
204 DBG1(DBG_PTS, "no rng available");
205 return FALSE;
206 }
207 DBG2(DBG_PTS, "nonce length is %d", nonce_len);
208 nonce = this->is_imc ? &this->responder_nonce : &this->initiator_nonce;
209 chunk_free(nonce);
210 if (!rng->allocate_bytes(rng, nonce_len, nonce))
211 {
212 DBG1(DBG_PTS, "failed to allocate nonce");
213 rng->destroy(rng);
214 return FALSE;
215 }
216 rng->destroy(rng);
217 return TRUE;
218 }
219
220 METHOD(pts_t, get_my_public_value, bool,
221 private_pts_t *this, chunk_t *value, chunk_t *nonce)
222 {
223 if (!this->dh->get_my_public_value(this->dh, value))
224 {
225 return FALSE;
226 }
227 *nonce = this->is_imc ? this->responder_nonce : this->initiator_nonce;
228 return TRUE;
229 }
230
231 METHOD(pts_t, set_peer_public_value, bool,
232 private_pts_t *this, chunk_t value, chunk_t nonce)
233 {
234 if (!this->dh->set_other_public_value(this->dh, value))
235 {
236 return FALSE;
237 }
238
239 nonce = chunk_clone(nonce);
240 if (this->is_imc)
241 {
242 this->initiator_nonce = nonce;
243 }
244 else
245 {
246 this->responder_nonce = nonce;
247 }
248 return TRUE;
249 }
250
251 METHOD(pts_t, calculate_secret, bool,
252 private_pts_t *this)
253 {
254 hasher_t *hasher;
255 hash_algorithm_t hash_alg;
256 chunk_t shared_secret;
257
258 /* Check presence of nonces */
259 if (!this->initiator_nonce.len || !this->responder_nonce.len)
260 {
261 DBG1(DBG_PTS, "initiator and/or responder nonce is not available");
262 return FALSE;
263 }
264 DBG3(DBG_PTS, "initiator nonce: %B", &this->initiator_nonce);
265 DBG3(DBG_PTS, "responder nonce: %B", &this->responder_nonce);
266
267 /* Calculate the DH secret */
268 if (!this->dh->get_shared_secret(this->dh, &shared_secret))
269 {
270 DBG1(DBG_PTS, "shared DH secret computation failed");
271 return FALSE;
272 }
273 DBG3(DBG_PTS, "shared DH secret: %B", &shared_secret);
274
275 /* Calculate the secret assessment value */
276 hash_alg = pts_meas_algo_to_hash(this->dh_hash_algorithm);
277 hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
278
279 if (!hasher ||
280 !hasher->get_hash(hasher, chunk_from_chars('1'), NULL) ||
281 !hasher->get_hash(hasher, this->initiator_nonce, NULL) ||
282 !hasher->get_hash(hasher, this->responder_nonce, NULL) ||
283 !hasher->allocate_hash(hasher, shared_secret, &this->secret))
284 {
285 DESTROY_IF(hasher);
286 return FALSE;
287 }
288 hasher->destroy(hasher);
289
290 /* The DH secret must be destroyed */
291 chunk_clear(&shared_secret);
292
293 /*
294 * Truncate the hash to 20 bytes to fit the ExternalData
295 * argument of the TPM Quote command
296 */
297 this->secret.len = min(this->secret.len, 20);
298 DBG3(DBG_PTS, "secret assessment value: %B", &this->secret);
299 return TRUE;
300 }
301
302 METHOD(pts_t, get_platform_id, int,
303 private_pts_t *this)
304 {
305 return this->platform_id;
306 }
307
308 METHOD(pts_t, set_platform_id, void,
309 private_pts_t *this, int pid)
310 {
311 this->platform_id = pid;
312 }
313
314 METHOD(pts_t, get_tpm_version_info, bool,
315 private_pts_t *this, chunk_t *info)
316 {
317 *info = this->tpm ? this->tpm->get_version_info(this->tpm) :
318 this->tpm_version_info;
319 return info->len > 0;
320 }
321
322 METHOD(pts_t, set_tpm_version_info, void,
323 private_pts_t *this, chunk_t info)
324 {
325 this->tpm_version_info = chunk_clone(info);
326 /* print_tpm_version_info(this); */
327 }
328
329 /**
330 * Load an AIK handle and an optional AIK certificate and
331 * in the case of a TPM 1.2 an AIK private key blob plus matching public key,
332 * the certificate having precedence over the public key if both are present
333 */
334 static void load_aik(private_pts_t *this)
335 {
336 char *handle_str, *cert_path, *key_path, *blob_path;
337 chunk_t aik_pubkey = chunk_empty;
338
339 handle_str = lib->settings->get_str(lib->settings,
340 "%s.plugins.imc-attestation.aik_handle", NULL, lib->ns);
341 cert_path = lib->settings->get_str(lib->settings,
342 "%s.plugins.imc-attestation.aik_cert", NULL, lib->ns);
343 key_path = lib->settings->get_str(lib->settings,
344 "%s.plugins.imc-attestation.aik_pubkey", NULL, lib->ns);
345 blob_path = lib->settings->get_str(lib->settings,
346 "%s.plugins.imc-attestation.aik_blob", NULL, lib->ns);
347
348 if (handle_str)
349 {
350 this->aik_handle = strtoll(handle_str, NULL, 16);
351 }
352 if (cert_path)
353 {
354 this->aik_cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
355 CERT_X509, BUILD_FROM_FILE,
356 cert_path, BUILD_END);
357 if (this->aik_cert)
358 {
359 DBG2(DBG_PTS, "loaded AIK certificate from '%s'", cert_path);
360 }
361 }
362
363 if (this->tpm->get_version(this->tpm) == TPM_VERSION_1_2)
364 {
365 tpm_tss_trousers_t *tpm_12;
366 chunk_t aik_blob = chunk_empty;
367 chunk_t *map;
368
369 /* get AIK private key blob */
370 if (blob_path)
371 {
372 map = chunk_map(blob_path, FALSE);
373 if (map)
374 {
375 DBG2(DBG_PTS, "loaded AIK Blob from '%s'", blob_path);
376 DBG3(DBG_PTS, "AIK Blob: %B", map);
377 aik_blob = chunk_clone(*map);
378 chunk_unmap(map);
379 }
380 else
381 {
382 DBG1(DBG_PTS, "unable to map AIK Blob file '%s': %s",
383 blob_path, strerror(errno));
384 }
385 }
386 else
387 {
388 DBG1(DBG_PTS, "AIK Blob is not available");
389 }
390
391 /* get AIK public key if no AIK certificate is available */
392 if (!this->aik_cert)
393 {
394 if (key_path)
395 {
396 map = chunk_map(key_path, FALSE);
397 if (map)
398 {
399 DBG2(DBG_PTS, "loaded AIK public key from '%s'", key_path);
400 aik_pubkey = chunk_clone(*map);
401 chunk_unmap(map);
402 }
403 else
404 {
405 DBG1(DBG_PTS, "unable to map AIK public key file '%s': %s",
406 key_path, strerror(errno));
407 }
408 }
409 else
410 {
411 DBG1(DBG_PTS, "AIK public key is not available");
412 }
413 }
414
415 /* Load AIK item into TPM 1.2 object */
416 tpm_12 = (tpm_tss_trousers_t *)this->tpm;
417 tpm_12->load_aik(tpm_12, aik_blob, aik_pubkey, this->aik_handle);
418 }
419
420 /* if no signed X.509 AIK certificate is available use public key instead */
421 if (!this->aik_cert)
422 {
423 aik_pubkey = this->tpm->get_public(this->tpm, this->aik_handle);
424 if (aik_pubkey.len > 0)
425 {
426 this->aik_cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
427 CERT_TRUSTED_PUBKEY, BUILD_BLOB,
428 aik_pubkey, BUILD_END);
429 chunk_free(&aik_pubkey);
430 }
431 else
432 {
433 DBG1(DBG_PTS, "neither AIK certificate nor public key is available");
434 }
435 }
436 }
437
438 METHOD(pts_t, get_aik, certificate_t*,
439 private_pts_t *this)
440 {
441 return this->aik_cert;
442 }
443
444 METHOD(pts_t, set_aik, void,
445 private_pts_t *this, certificate_t *aik, int aik_id)
446 {
447 DESTROY_IF(this->aik_cert);
448 this->aik_cert = aik->get_ref(aik);
449 this->aik_id = aik_id;
450 }
451
452 METHOD(pts_t, get_aik_id, int,
453 private_pts_t *this)
454 {
455 return this->aik_id;
456 }
457
458 METHOD(pts_t, is_path_valid, bool,
459 private_pts_t *this, char *path, pts_error_code_t *error_code)
460 {
461 struct stat st;
462
463 *error_code = 0;
464
465 if (!stat(path, &st))
466 {
467 return TRUE;
468 }
469 else if (errno == ENOENT || errno == ENOTDIR)
470 {
471 DBG1(DBG_PTS, "file/directory does not exist %s", path);
472 *error_code = TCG_PTS_FILE_NOT_FOUND;
473 }
474 else if (errno == EFAULT)
475 {
476 DBG1(DBG_PTS, "bad address %s", path);
477 *error_code = TCG_PTS_INVALID_PATH;
478 }
479 else
480 {
481 DBG1(DBG_PTS, "error: %s occurred while validating path: %s",
482 strerror(errno), path);
483 return FALSE;
484 }
485
486 return TRUE;
487 }
488
489 /**
490 * Obtain statistical information describing a file
491 */
492 static bool file_metadata(char *pathname, pts_file_metadata_t **entry)
493 {
494 struct stat st;
495 pts_file_metadata_t *this;
496
497 this = malloc_thing(pts_file_metadata_t);
498
499 if (stat(pathname, &st))
500 {
501 DBG1(DBG_PTS, "unable to obtain statistics about '%s'", pathname);
502 free(this);
503 return FALSE;
504 }
505
506 if (S_ISREG(st.st_mode))
507 {
508 this->type = PTS_FILE_REGULAR;
509 }
510 else if (S_ISDIR(st.st_mode))
511 {
512 this->type = PTS_FILE_DIRECTORY;
513 }
514 else if (S_ISCHR(st.st_mode))
515 {
516 this->type = PTS_FILE_CHAR_SPEC;
517 }
518 else if (S_ISBLK(st.st_mode))
519 {
520 this->type = PTS_FILE_BLOCK_SPEC;
521 }
522 else if (S_ISFIFO(st.st_mode))
523 {
524 this->type = PTS_FILE_FIFO;
525 }
526 #ifndef WIN32
527 else if (S_ISLNK(st.st_mode))
528 {
529 this->type = PTS_FILE_SYM_LINK;
530 }
531 else if (S_ISSOCK(st.st_mode))
532 {
533 this->type = PTS_FILE_SOCKET;
534 }
535 #endif /* WIN32 */
536 else
537 {
538 this->type = PTS_FILE_OTHER;
539 }
540
541 this->filesize = st.st_size;
542 this->created = st.st_ctime;
543 this->modified = st.st_mtime;
544 this->accessed = st.st_atime;
545 this->owner = st.st_uid;
546 this->group = st.st_gid;
547
548 *entry = this;
549 return TRUE;
550 }
551
552 METHOD(pts_t, get_metadata, pts_file_meta_t*,
553 private_pts_t *this, char *pathname, bool is_directory)
554 {
555 pts_file_meta_t *metadata;
556 pts_file_metadata_t *entry;
557
558 /* Create a metadata object */
559 metadata = pts_file_meta_create();
560
561 if (is_directory)
562 {
563 enumerator_t *enumerator;
564 char *rel_name, *abs_name;
565 struct stat st;
566
567 enumerator = enumerator_create_directory(pathname);
568 if (!enumerator)
569 {
570 DBG1(DBG_PTS," directory '%s' can not be opened, %s", pathname,
571 strerror(errno));
572 metadata->destroy(metadata);
573 return NULL;
574 }
575 while (enumerator->enumerate(enumerator, &rel_name, &abs_name, &st))
576 {
577 /* measure regular files only */
578 if (S_ISREG(st.st_mode) && *rel_name != '.')
579 {
580 if (!file_metadata(abs_name, &entry))
581 {
582 enumerator->destroy(enumerator);
583 metadata->destroy(metadata);
584 return NULL;
585 }
586 entry->filename = strdup(rel_name);
587 metadata->add(metadata, entry);
588 }
589 }
590 enumerator->destroy(enumerator);
591 }
592 else
593 {
594 if (!file_metadata(pathname, &entry))
595 {
596 metadata->destroy(metadata);
597 return NULL;
598 }
599 entry->filename = path_basename(pathname);
600 metadata->add(metadata, entry);
601 }
602
603 return metadata;
604 }
605
606 METHOD(pts_t, read_pcr, bool,
607 private_pts_t *this, uint32_t pcr_num, chunk_t *pcr_value,
608 hash_algorithm_t alg)
609 {
610 return this->tpm ? this->tpm->read_pcr(this->tpm, pcr_num, pcr_value, alg)
611 : FALSE;
612 }
613
614 METHOD(pts_t, extend_pcr, bool,
615 private_pts_t *this, uint32_t pcr_num, chunk_t *pcr_value, chunk_t data,
616 hash_algorithm_t alg)
617 {
618 if (!this->tpm->extend_pcr(this->tpm, pcr_num, pcr_value, data, alg))
619 {
620 return FALSE;
621 }
622 DBG3(DBG_PTS, "PCR %d extended with: %#B", pcr_num, &data);
623 DBG3(DBG_PTS, "PCR %d after extension: %#B", pcr_num, pcr_value);
624
625 return TRUE;
626 }
627
628 METHOD(pts_t, quote, bool,
629 private_pts_t *this, tpm_quote_mode_t *quote_mode,
630 tpm_tss_quote_info_t **quote_info, chunk_t *quote_sig)
631 {
632 chunk_t pcr_value, pcr_computed;
633 uint32_t pcr, pcr_sel = 0;
634 enumerator_t *enumerator;
635
636 /* select PCRs */
637 DBG2(DBG_PTS, "PCR values hashed into PCR Composite:");
638 enumerator = this->pcrs->create_enumerator(this->pcrs);
639 while (enumerator->enumerate(enumerator, &pcr))
640 {
641 if (this->tpm->read_pcr(this->tpm, pcr, &pcr_value, HASH_SHA1))
642 {
643 pcr_computed = this->pcrs->get(this->pcrs, pcr);
644 DBG2(DBG_PTS, "PCR %2d %#B %s", pcr, &pcr_value,
645 chunk_equals(pcr_value, pcr_computed) ? "ok" : "differs");
646 chunk_free(&pcr_value);
647 };
648
649 /* add PCR to selection list */
650 pcr_sel |= (1 << pcr);
651 }
652 enumerator->destroy(enumerator);
653
654 /* TPM Quote */
655 return this->tpm->quote(this->tpm, this->aik_handle, pcr_sel, HASH_SHA1,
656 this->secret, quote_mode, quote_info, quote_sig);
657 }
658
659 METHOD(pts_t, get_quote, bool,
660 private_pts_t *this, tpm_tss_quote_info_t *quote_info, chunk_t *quoted)
661 {
662 tpm_tss_pcr_composite_t *pcr_composite;
663 bool success;
664
665 if (!this->pcrs->get_count(this->pcrs))
666 {
667 DBG1(DBG_PTS, "No extended PCR entries available, "
668 "unable to construct TPM Quote Info");
669 return FALSE;
670 }
671 if (!this->secret.ptr)
672 {
673 DBG1(DBG_PTS, "Secret assessment value unavailable, ",
674 "unable to construct TPM Quote Info");
675 return FALSE;
676 }
677 if (quote_info->get_quote_mode(quote_info) == TPM_QUOTE2_VERSION_INFO)
678 {
679 if (!this->tpm_version_info.ptr)
680 {
681 DBG1(DBG_PTS, "TPM Version Information unavailable, ",
682 "unable to construct TPM Quote Info2");
683 return FALSE;
684 }
685 quote_info->set_version_info(quote_info, this->tpm_version_info);
686 }
687 pcr_composite = this->pcrs->get_composite(this->pcrs);
688
689 success = quote_info->get_quote(quote_info, this->secret,
690 pcr_composite, quoted);
691 chunk_free(&pcr_composite->pcr_select);
692 chunk_free(&pcr_composite->pcr_composite);
693 free(pcr_composite);
694
695 return success;
696 }
697
698 METHOD(pts_t, verify_quote_signature, bool,
699 private_pts_t *this, hash_algorithm_t digest_alg, chunk_t digest,
700 chunk_t signature)
701 {
702 public_key_t *aik_pubkey;
703 signature_scheme_t scheme;
704
705 aik_pubkey = this->aik_cert->get_public_key(this->aik_cert);
706 if (!aik_pubkey)
707 {
708 DBG1(DBG_PTS, "failed to get public key from AIK certificate");
709 return FALSE;
710 }
711
712 /* Determine signing scheme */
713 switch (aik_pubkey->get_type(aik_pubkey))
714 {
715 case KEY_RSA:
716 switch (digest_alg)
717 {
718 case HASH_SHA1:
719 scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
720 break;
721 case HASH_SHA256:
722 scheme = SIGN_RSA_EMSA_PKCS1_SHA256;
723 break;
724 case HASH_SHA384:
725 scheme = SIGN_RSA_EMSA_PKCS1_SHA384;
726 break;
727 case HASH_SHA512:
728 scheme = SIGN_RSA_EMSA_PKCS1_SHA512;
729 break;
730 default:
731 scheme = SIGN_UNKNOWN;
732 }
733 break;
734 case KEY_ECDSA:
735 switch (digest_alg)
736 {
737 case HASH_SHA256:
738 scheme = SIGN_ECDSA_256;
739 break;
740 case HASH_SHA384:
741 scheme = SIGN_ECDSA_384;
742 break;
743 case HASH_SHA512:
744 scheme = SIGN_ECDSA_521;
745 break;
746 default:
747 scheme = SIGN_UNKNOWN;
748 }
749 break;
750 default:
751 DBG1(DBG_PTS, "%N AIK key type not supported", key_type_names,
752 aik_pubkey->get_type(aik_pubkey));
753 return FALSE;
754 }
755
756 if (!aik_pubkey->verify(aik_pubkey, scheme, digest, signature))
757 {
758 DBG1(DBG_PTS, "signature verification failed for TPM Quote Info");
759 DESTROY_IF(aik_pubkey);
760 return FALSE;
761 }
762
763 aik_pubkey->destroy(aik_pubkey);
764 return TRUE;
765 }
766
767 METHOD(pts_t, get_pcrs, pts_pcr_t*,
768 private_pts_t *this)
769 {
770 return this->pcrs;
771 }
772
773 METHOD(pts_t, destroy, void,
774 private_pts_t *this)
775 {
776 DESTROY_IF(this->tpm);
777 DESTROY_IF(this->pcrs);
778 DESTROY_IF(this->aik_cert);
779 DESTROY_IF(this->dh);
780 free(this->initiator_nonce.ptr);
781 free(this->responder_nonce.ptr);
782 free(this->secret.ptr);
783 free(this->tpm_version_info.ptr);
784 free(this);
785 }
786
787 /**
788 * See header
789 */
790 pts_t *pts_create(bool is_imc)
791 {
792 private_pts_t *this;
793 pts_pcr_t *pcrs;
794
795 pcrs = pts_pcr_create();
796 if (!pcrs)
797 {
798 DBG1(DBG_PTS, "shadow PCR set could not be created");
799 return NULL;
800 }
801
802 INIT(this,
803 .public = {
804 .get_proto_caps = _get_proto_caps,
805 .set_proto_caps = _set_proto_caps,
806 .get_meas_algorithm = _get_meas_algorithm,
807 .set_meas_algorithm = _set_meas_algorithm,
808 .get_dh_hash_algorithm = _get_dh_hash_algorithm,
809 .set_dh_hash_algorithm = _set_dh_hash_algorithm,
810 .create_dh_nonce = _create_dh_nonce,
811 .get_my_public_value = _get_my_public_value,
812 .set_peer_public_value = _set_peer_public_value,
813 .calculate_secret = _calculate_secret,
814 .get_platform_id = _get_platform_id,
815 .set_platform_id = _set_platform_id,
816 .get_tpm_version_info = _get_tpm_version_info,
817 .set_tpm_version_info = _set_tpm_version_info,
818 .get_aik = _get_aik,
819 .set_aik = _set_aik,
820 .get_aik_id = _get_aik_id,
821 .is_path_valid = _is_path_valid,
822 .get_metadata = _get_metadata,
823 .read_pcr = _read_pcr,
824 .extend_pcr = _extend_pcr,
825 .quote = _quote,
826 .get_pcrs = _get_pcrs,
827 .get_quote = _get_quote,
828 .verify_quote_signature = _verify_quote_signature,
829 .destroy = _destroy,
830 },
831 .is_imc = is_imc,
832 .proto_caps = PTS_PROTO_CAPS_V,
833 .algorithm = PTS_MEAS_ALGO_SHA256,
834 .dh_hash_algorithm = PTS_MEAS_ALGO_SHA256,
835 .pcrs = pcrs,
836 );
837
838 if (is_imc)
839 {
840 this->tpm = tpm_tss_probe(TPM_VERSION_ANY);
841 if (this->tpm)
842 {
843 this->proto_caps |= PTS_PROTO_CAPS_T | PTS_PROTO_CAPS_D;
844 load_aik(this);
845 }
846 }
847 else
848 {
849 this->proto_caps |= PTS_PROTO_CAPS_T | PTS_PROTO_CAPS_D;
850 }
851
852 return &this->public;
853 }