ae80a7ebab7f4fee49f97b8cfbfcce017f52ac0a
[strongswan.git] / src / libimcv / tcg / 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
21 #include <openssl/rsa.h>
22 #include <openssl/pem.h>
23 #include <curl/curl.h>
24 #include "fake_ek_cert.h"
25
26 #include <trousers/tss.h>
27 #include <trousers/trousers.h>
28
29 #include <sys/stat.h>
30 #include <errno.h>
31
32 #define PTS_BUF_SIZE 4096
33
34 /* Size of endorsement key in bytes */
35 #define EKSIZE (2048/8)
36 /* URL of Privacy CA */
37 #define CAURL "http://www.privacyca.com/"
38 #define CERTURL CAURL "api/pca/level%d?ResponseFormat=PEM"
39 #define REQURL CAURL "api/pca/level%d?ResponseFormat=Binary"
40
41 /* TPM has EK Certificate */
42 #define REALEK FALSE
43
44 typedef struct private_pts_t private_pts_t;
45
46 /**
47 * Private data of a pts_t object.
48 *
49 */
50 struct private_pts_t {
51
52 /**
53 * Public pts_t interface.
54 */
55 pts_t public;
56
57 /**
58 * PTS Protocol Capabilities
59 */
60 pts_proto_caps_flag_t proto_caps;
61
62 /**
63 * PTS Measurement Algorithm
64 */
65 pts_meas_algorithms_t algorithm;
66
67 /**
68 * Platform and OS Info
69 */
70 char *platform_info;
71
72 /**
73 * Do we have an activated TPM
74 */
75 bool has_tpm;
76
77 /**
78 * Contains a TPM_CAP_VERSION_INFO struct
79 */
80 chunk_t tpm_version_info;
81
82 /**
83 * Contains a Attestation Identity Key
84 */
85 chunk_t aik;
86
87 /**
88 * True if AIK is naked public key, not a certificate
89 */
90 bool is_naked_key;
91
92 };
93
94 METHOD(pts_t, get_proto_caps, pts_proto_caps_flag_t,
95 private_pts_t *this)
96 {
97 return this->proto_caps;
98 }
99
100 METHOD(pts_t, set_proto_caps, void,
101 private_pts_t *this, pts_proto_caps_flag_t flags)
102 {
103 this->proto_caps = flags;
104 DBG2(DBG_TNC, "supported PTS protocol capabilities: %s%s%s%s%s",
105 flags & PTS_PROTO_CAPS_C ? "C" : ".",
106 flags & PTS_PROTO_CAPS_V ? "V" : ".",
107 flags & PTS_PROTO_CAPS_D ? "D" : ".",
108 flags & PTS_PROTO_CAPS_T ? "T" : ".",
109 flags & PTS_PROTO_CAPS_X ? "X" : ".");
110 }
111
112 METHOD(pts_t, get_meas_algorithm, pts_meas_algorithms_t,
113 private_pts_t *this)
114 {
115 return this->algorithm;
116 }
117
118 METHOD(pts_t, set_meas_algorithm, void,
119 private_pts_t *this, pts_meas_algorithms_t algorithm)
120 {
121 hash_algorithm_t hash_alg;
122
123 hash_alg = pts_meas_to_hash_algorithm(algorithm);
124 DBG2(DBG_TNC, "selected PTS measurement algorithm is %N",
125 hash_algorithm_names, hash_alg);
126 if (hash_alg != HASH_UNKNOWN)
127 {
128 this->algorithm = algorithm;
129 }
130 }
131
132 /**
133 * Print TPM 1.2 Version Info
134 */
135 static void print_tpm_version_info(private_pts_t *this)
136 {
137 TPM_CAP_VERSION_INFO versionInfo;
138 UINT64 offset = 0;
139 TSS_RESULT result;
140
141 result = Trspi_UnloadBlob_CAP_VERSION_INFO(&offset,
142 this->tpm_version_info.ptr, &versionInfo);
143 if (result != TSS_SUCCESS)
144 {
145 DBG1(DBG_TNC, "could not parse tpm version info: tss error 0x%x",
146 result);
147 }
148 else
149 {
150 DBG2(DBG_TNC, "TPM 1.2 Version Info: Chip Version: %hhu.%hhu.%hhu.%hhu,"
151 " Spec Level: %hu, Errata Rev: %hhu, Vendor ID: %.4s",
152 versionInfo.version.major, versionInfo.version.minor,
153 versionInfo.version.revMajor, versionInfo.version.revMinor,
154 versionInfo.specLevel, versionInfo.errataRev,
155 versionInfo.tpmVendorID);
156 }
157 }
158
159 METHOD(pts_t, get_platform_info, char*,
160 private_pts_t *this)
161 {
162 return this->platform_info;
163 }
164
165 METHOD(pts_t, set_platform_info, void,
166 private_pts_t *this, char *info)
167 {
168 free(this->platform_info);
169 this->platform_info = strdup(info);
170 }
171
172 METHOD(pts_t, get_tpm_version_info, bool,
173 private_pts_t *this, chunk_t *info)
174 {
175 if (!this->has_tpm)
176 {
177 return FALSE;
178 }
179 *info = this->tpm_version_info;
180 print_tpm_version_info(this);
181 return TRUE;
182 }
183
184 METHOD(pts_t, set_tpm_version_info, void,
185 private_pts_t *this, chunk_t info)
186 {
187 this->tpm_version_info = chunk_clone(info);
188 print_tpm_version_info(this);
189 }
190
191 /**
192 * Create a fake endorsement key cert using system's actual EK
193 */
194
195 static TSS_RESULT makeEKCert(TSS_HCONTEXT hContext, TSS_HTPM hTPM, UINT32 *pCertLen, BYTE **pCert)
196 {
197 TSS_RESULT result;
198 TSS_HKEY hPubek;
199 UINT32 modulusLen;
200 BYTE *modulus;
201
202 result = Tspi_TPM_GetPubEndorsementKey (hTPM, TRUE, NULL, &hPubek);
203 if (result != TSS_SUCCESS)
204 {
205 DBG1(DBG_IMC, "Error in: Tspi_TPM_GetPubEndorsementKey");
206 return result;
207 }
208 result = Tspi_GetAttribData (hPubek, TSS_TSPATTRIB_RSAKEY_INFO,
209 TSS_TSPATTRIB_KEYINFO_RSA_MODULUS, &modulusLen, &modulus);
210 Tspi_Context_CloseObject (hContext, hPubek);
211 if (result != TSS_SUCCESS)
212 {
213 DBG1(DBG_IMC, "Error in: Tspi_Context_CloseObject");
214 return result;
215 }
216 if (modulusLen != 256)
217 {
218 DBG1(DBG_IMC, "Tspi_GetAttribData modulusLen != 256");
219 Tspi_Context_FreeMemory (hContext, modulus);
220 return result;
221 }
222 /* TODO define fakeEKCert
223 * pCertLen = sizeof(fakeEKCert);
224 *pCert = malloc (*pCertLen);
225 memcpy (*pCert, fakeEKCert, *pCertLen);
226 memcpy (*pCert + 0xc6, modulus, modulusLen);
227 */
228 Tspi_Context_FreeMemory (hContext, modulus);
229
230 return TSS_SUCCESS;
231 }
232
233 /**
234 * Read the level N CA from privacyca.com
235 * Assume Curl library has been initialized
236 */
237
238 static X509* readPCAcert (int level)
239 {
240 CURL *hCurl;
241 char url[128];
242 FILE *f_tmp = tmpfile();
243 X509 *x509;
244 int result;
245
246 hCurl = curl_easy_init ();
247 sprintf (url, CERTURL, level);
248 curl_easy_setopt (hCurl, CURLOPT_URL, url);
249 curl_easy_setopt(hCurl, CURLOPT_WRITEDATA, (BYTE **)f_tmp);
250
251 if ((result = curl_easy_perform(hCurl)))
252 {
253 DBG1(DBG_IMC, "Unable to connect to Privacy CA, curl library result code %d", result);
254 fclose(f_tmp);
255 return NULL;
256 }
257
258 rewind (f_tmp);
259 x509 = PEM_read_X509 (f_tmp, NULL, NULL, NULL);
260 fclose(f_tmp);
261
262 return x509;
263 }
264
265
266 /**
267 * Obtain an AIK, SRK and TPM Owner secret has to be both set to well known secret
268 * of 20 bytes of zero
269 */
270 static bool obtain_aik(private_pts_t *this)
271 {
272 TSS_HCONTEXT hContext;
273 TSS_HTPM hTPM;
274 TSS_HKEY hSRK;
275 TSS_HKEY hPCAKey;
276 TSS_HKEY hIdentKey;
277 TSS_HPOLICY hSrkPolicy;
278 TSS_HPOLICY hTPMPolicy;
279 TSS_UUID SRK_UUID = TSS_UUID_SRK;
280 BYTE secret[] = TSS_WELL_KNOWN_SECRET;
281 X509 *x509;
282 EVP_PKEY *pcaKey;
283 RSA *rsa = NULL;
284 CURL *hCurl;
285 struct curl_slist *slist = NULL;
286 BYTE n[16384/8];
287 int size_n;
288 FILE *f_tmp;
289 BYTE *rgbTCPAIdentityReq;
290 UINT32 ulTCPAIdentityReqLength;
291 UINT32 initFlags = TSS_KEY_TYPE_IDENTITY | TSS_KEY_SIZE_2048 |
292 TSS_KEY_VOLATILE | TSS_KEY_NOT_MIGRATABLE;
293 BYTE asymBuf[EKSIZE];
294 BYTE *symBuf;
295 BYTE *credBuf;
296 BYTE *tbuf;
297 UINT32 asymBufSize;
298 UINT32 symBufSize;
299 UINT32 credBufSize;
300 static int level = 0;
301 BYTE *ekCert = NULL;
302 UINT32 ekCertLen = 0;
303 char url[128];
304 int result;
305
306 this->aik = chunk_empty;
307 this->is_naked_key = false;
308
309 curl_global_init (CURL_GLOBAL_ALL);
310
311 DBG3(DBG_IMC, "Retrieving PCA certificate...");
312
313 /* TPM has EK Certificate */
314 if (REALEK)
315 {
316 level = 1;
317 }
318 x509 = readPCAcert (level);
319 if (x509 == NULL)
320 {
321 DBG1(DBG_IMC, "Error reading PCA key");
322 goto err;
323 }
324 pcaKey = X509_get_pubkey(x509);
325 rsa = EVP_PKEY_get1_RSA(pcaKey);
326 if (rsa == NULL)
327 {
328 DBG1(DBG_IMC, "Error reading RSA key from PCA");
329 goto err;
330 }
331 X509_free (x509);
332
333 result = Tspi_Context_Create(&hContext);
334 if (result != TSS_SUCCESS)
335 {
336 DBG1(DBG_IMC, "Error 0x%x on Tspi_Context_Create", result);
337 goto err;
338 }
339 result = Tspi_Context_Connect(hContext, NULL);
340 if (result != TSS_SUCCESS)
341 {
342 DBG1(DBG_IMC, "Error 0x%x on Tspi_Context_Connect", result);
343 goto err;
344 }
345 result = Tspi_Context_GetTpmObject (hContext, &hTPM);
346 if (result != TSS_SUCCESS)
347 {
348 DBG1(DBG_IMC, "Error 0x%x on Tspi_Context_GetTpmObject", result);
349 goto err;
350 }
351 result = Tspi_Context_LoadKeyByUUID(hContext,
352 TSS_PS_TYPE_SYSTEM, SRK_UUID, &hSRK);
353 if (result != TSS_SUCCESS)
354 {
355 DBG1(DBG_IMC, "Error 0x%x on Tspi_Context_LoadKeyByUUID for SRK", result);
356 goto err;
357 }
358 result = Tspi_GetPolicyObject(hSRK, TSS_POLICY_USAGE, &hSrkPolicy);
359 if (result != TSS_SUCCESS)
360 {
361 DBG1(DBG_IMC, "Error 0x%x on Tspi_GetPolicyObject for SRK", result);
362 goto err;
363 }
364 result = Tspi_Policy_SetSecret(hSrkPolicy, TSS_SECRET_MODE_SHA1, 20, secret);
365 if (result != TSS_SUCCESS)
366 {
367 DBG1(DBG_IMC, "Error 0x%x on Tspi_Policy_SetSecret for SRK", result);
368 goto err;
369 }
370 result = Tspi_GetPolicyObject(hTPM, TSS_POLICY_USAGE, &hTPMPolicy);
371 if (result != TSS_SUCCESS)
372 {
373 DBG1(DBG_IMC, "Error 0x%x on Tspi_GetPolicyObject for TPM", result);
374 goto err;
375 }
376 result = Tspi_Policy_SetSecret(hTPMPolicy, TSS_SECRET_MODE_SHA1, 20, secret);
377 if (result != TSS_SUCCESS)
378 {
379 DBG1(DBG_IMC, "Error 0x%x on Tspi_Policy_SetSecret for TPM", result);
380 goto err;
381 }
382
383 result = Tspi_Context_CreateObject(hContext,
384 TSS_OBJECT_TYPE_RSAKEY,
385 initFlags, &hIdentKey);
386 if (result != TSS_SUCCESS)
387 {
388 DBG1(DBG_IMC, "Error 0x%x on Tspi_Context_CreateObject for key", result);
389 goto err;
390 }
391
392 result = Tspi_Context_CreateObject(hContext,
393 TSS_OBJECT_TYPE_RSAKEY,
394 TSS_KEY_TYPE_LEGACY|TSS_KEY_SIZE_2048,
395 &hPCAKey);
396 if (result != TSS_SUCCESS)
397 {
398 DBG1(DBG_IMC, "Error 0x%x on Tspi_Context_CreateObject for PCA", result);
399 goto err;
400 }
401 if ((size_n = BN_bn2bin(rsa->n, n)) <= 0)
402 {
403 DBG1(DBG_IMC, "BN_bn2bin failed");
404 goto err;;
405 }
406 result = Tspi_SetAttribData (hPCAKey, TSS_TSPATTRIB_RSAKEY_INFO,
407 TSS_TSPATTRIB_KEYINFO_RSA_MODULUS, size_n, n);
408 if (result != TSS_SUCCESS)
409 {
410 DBG1(DBG_IMC, "Error 0x%x on Tspi_SetAttribData for PCA modulus", result);
411 goto err;
412 }
413 result = Tspi_SetAttribUint32(hPCAKey, TSS_TSPATTRIB_KEY_INFO,
414 TSS_TSPATTRIB_KEYINFO_ENCSCHEME,
415 TSS_ES_RSAESPKCSV15);
416 if (result != TSS_SUCCESS)
417 {
418 DBG1(DBG_IMC, "Error 0x%x on Tspi_SetAttribUint32 for PCA encscheme", result);
419 goto err;
420 }
421
422 if (!REALEK)
423 {
424 result = makeEKCert(hContext, hTPM, &ekCertLen, &ekCert);
425 if (result != TSS_SUCCESS)
426 {
427 DBG1(DBG_IMC, "Error 0x%x on makeEKCert", result);
428 goto err;
429 }
430
431 result = Tspi_SetAttribData(hTPM, TSS_TSPATTRIB_TPM_CREDENTIAL,
432 TSS_TPMATTRIB_EKCERT, ekCertLen, ekCert);
433 if (result != TSS_SUCCESS)
434 {
435 DBG1(DBG_IMC, "Error 0x%x on SetAttribData for EKCert", result);
436 goto err;
437 }
438 }
439
440 DBG3(DBG_IMC, "Generating attestation identity key...");
441 result = Tspi_TPM_CollateIdentityRequest(hTPM, hSRK, hPCAKey, 0,
442 NULL, hIdentKey, TSS_ALG_AES,
443 &ulTCPAIdentityReqLength,
444 &rgbTCPAIdentityReq);
445 if (result != TSS_SUCCESS)
446 {
447 DBG1(DBG_IMC, "Error 0x%x on Tspi_TPM_CollateIdentityRequest", result);
448 goto err;
449 }
450
451 DBG3(DBG_IMC, "Sending request to PrivacyCA.com...");
452
453 /* Send to server */
454 f_tmp = tmpfile();
455 hCurl = curl_easy_init ();
456 sprintf (url, REQURL, level);
457 curl_easy_setopt (hCurl, CURLOPT_URL, url);
458 curl_easy_setopt (hCurl, CURLOPT_POSTFIELDS, (void *)rgbTCPAIdentityReq);
459 curl_easy_setopt (hCurl, CURLOPT_POSTFIELDSIZE, ulTCPAIdentityReqLength);
460 curl_easy_setopt (hCurl, CURLOPT_WRITEDATA, (BYTE **)f_tmp);
461 slist = curl_slist_append (slist, "Pragma: no-cache");
462 slist = curl_slist_append (slist, "Content-Type: application/octet-stream");
463 slist = curl_slist_append (slist, "Content-Transfer-Encoding: binary");
464 curl_easy_setopt (hCurl, CURLOPT_HTTPHEADER, slist);
465 if ((result = curl_easy_perform(hCurl)))
466 {
467 DBG1(DBG_IMC, "Unable to connect to Privacy CA, curl library result code %d", result);
468 exit (result);
469 }
470 curl_slist_free_all(slist);
471
472 DBG3(DBG_IMC, "Processing response from PrivacyCA...");
473
474 fflush (f_tmp);
475 symBufSize = ftell(f_tmp);
476 symBuf = malloc(symBufSize);
477 rewind(f_tmp);
478 if (!fread (symBuf, 1, symBufSize, f_tmp))
479 {
480 DBG1(DBG_IMC, "Failed to read buffer");
481 goto err;
482 }
483
484 fclose (f_tmp);
485
486 asymBufSize = sizeof(asymBuf);
487 if (symBufSize <= asymBufSize)
488 {
489 DBG1(DBG_IMC, "Bad response from PrivacyCA.com: %s", symBuf);
490 goto err;
491 }
492
493 memcpy (asymBuf, symBuf, asymBufSize);
494 symBufSize -= asymBufSize;
495 symBuf += asymBufSize;
496
497 result = Tspi_Key_LoadKey (hIdentKey, hSRK);
498 if (result != TSS_SUCCESS)
499 {
500 DBG1(DBG_IMC, "Error 0x%x on Tspi_Key_LoadKey for AIK", result);
501 goto err;
502 }
503
504 result = Tspi_TPM_ActivateIdentity (hTPM, hIdentKey, asymBufSize, asymBuf,
505 symBufSize, symBuf,
506 &credBufSize, &credBuf);
507 if (result != TSS_SUCCESS)
508 {
509 DBG1(DBG_IMC, "Error 0x%x on Tspi_TPM_ActivateIdentity", result);
510 goto err;
511 }
512
513 /* Output credential in PEM format */
514 tbuf = credBuf;
515 x509 = d2i_X509(NULL, (const BYTE **)&tbuf, credBufSize);
516 if (x509 == NULL)
517 {
518 DBG1(DBG_IMC, "Unable to parse returned credential");
519 goto err;
520 }
521 if (tbuf-credBuf != credBufSize)
522 {
523 DBG1(DBG_IMC, "Note, not all data from privacy ca was parsed correctly");
524 }
525
526 if (x509)
527 {
528 BUF_MEM *mem_buf;
529 BIO* bp;
530 u_int32_t len;
531
532 bp = BIO_new(BIO_s_mem());
533 PEM_write_bio_X509(bp, x509);
534
535 len = BIO_get_mem_data(bp, &mem_buf);
536 char tmp[len+1];
537
538 memcpy(tmp, mem_buf, len);
539 tmp[len] = '\0';
540
541 DBG3(DBG_IMC,"X509 Certificate (PEM format):");
542 DBG3(DBG_IMC,"%s", tmp);
543 this->aik = chunk_create(tmp, len + 1);
544 this->aik = chunk_clone(this->aik);
545
546 X509_free (x509);
547
548 }
549 else
550 {
551 DBG1(DBG_IMC, "Neither AIK Key blob, nor AIK Certificate is available");
552 goto err;
553 }
554
555 DBG3(DBG_IMC, "Succeeded at obtaining AIK Certificate from Privacy CA!");
556 return TRUE;
557
558 err:
559 return FALSE;
560 }
561
562 METHOD(pts_t, get_aik, bool,
563 private_pts_t *this, chunk_t *aik, bool *is_naked_key)
564 {
565 if (obtain_aik(this) != TRUE )
566 {
567 return FALSE;
568 }
569
570 *aik = this->aik;
571 *is_naked_key = this->is_naked_key;
572
573 return TRUE;
574 }
575
576 METHOD(pts_t, set_aik, void,
577 private_pts_t *this, chunk_t aik, bool is_naked_key)
578 {
579 this->aik = chunk_clone(aik);
580 this->is_naked_key = is_naked_key;
581 }
582
583 /**
584 * Compute a hash over a file
585 */
586 static bool hash_file(hasher_t *hasher, char *pathname, u_char *hash)
587 {
588 u_char buffer[PTS_BUF_SIZE];
589 FILE *file;
590 int bytes_read;
591
592 file = fopen(pathname, "rb");
593 if (!file)
594 {
595 DBG1(DBG_IMC," file '%s' can not be opened, %s", pathname,
596 strerror(errno));
597 return FALSE;
598 }
599 while (TRUE)
600 {
601 bytes_read = fread(buffer, 1, sizeof(buffer), file);
602 if (bytes_read > 0)
603 {
604 hasher->get_hash(hasher, chunk_create(buffer, bytes_read), NULL);
605 }
606 else
607 {
608 hasher->get_hash(hasher, chunk_empty, hash);
609 break;
610 }
611 }
612 fclose(file);
613
614 return TRUE;
615 }
616
617 /**
618 * Get the relative filename of a fully qualified file pathname
619 */
620 static char* get_filename(char *pathname)
621 {
622 char *pos, *filename;
623
624 pos = filename = pathname;
625 while (pos && *(++pos) != '\0')
626 {
627 filename = pos;
628 pos = strchr(filename, '/');
629 }
630 return filename;
631 }
632
633 METHOD(pts_t, do_measurements, pts_file_meas_t*,
634 private_pts_t *this, u_int16_t request_id, char *pathname, bool is_directory)
635 {
636 hasher_t *hasher;
637 hash_algorithm_t hash_alg;
638 u_char hash[HASH_SIZE_SHA384];
639 chunk_t measurement;
640 pts_file_meas_t *measurements;
641
642 /* Create a hasher */
643 hash_alg = pts_meas_to_hash_algorithm(this->algorithm);
644 hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
645 if (!hasher)
646 {
647 DBG1(DBG_IMC, " hasher %N not available", hash_algorithm_names, hash_alg);
648 return NULL;
649 }
650
651 /* Create a measurement object */
652 measurements = pts_file_meas_create(request_id);
653
654 /* Link the hash to the measurement and set the measurement length */
655 measurement = chunk_create(hash, hasher->get_hash_size(hasher));
656
657 if (is_directory)
658 {
659 enumerator_t *enumerator;
660 char *rel_name, *abs_name;
661 struct stat st;
662
663 enumerator = enumerator_create_directory(pathname);
664 if (!enumerator)
665 {
666 DBG1(DBG_IMC," directory '%s' can not be opened, %s", pathname,
667 strerror(errno));
668 hasher->destroy(hasher);
669 measurements->destroy(measurements);
670 return NULL;
671 }
672 while (enumerator->enumerate(enumerator, &rel_name, &abs_name, &st))
673 {
674 /* measure regular files only */
675 if (S_ISREG(st.st_mode) && *rel_name != '.')
676 {
677 if (!hash_file(hasher, abs_name, hash))
678 {
679 enumerator->destroy(enumerator);
680 hasher->destroy(hasher);
681 measurements->destroy(measurements);
682 return NULL;
683 }
684 DBG2(DBG_IMC, " %#B for '%s'", &measurement, rel_name);
685 measurements->add(measurements, rel_name, measurement);
686 }
687 }
688 enumerator->destroy(enumerator);
689 }
690 else
691 {
692 char *filename;
693
694 if (!hash_file(hasher, pathname, hash))
695 {
696 hasher->destroy(hasher);
697 measurements->destroy(measurements);
698 return NULL;
699 }
700 filename = get_filename(pathname);
701 DBG2(DBG_IMC, " %#B for '%s'", &measurement, filename);
702 measurements->add(measurements, filename, measurement);
703 }
704 hasher->destroy(hasher);
705
706 return measurements;
707 }
708
709 METHOD(pts_t, destroy, void,
710 private_pts_t *this)
711 {
712 free(this->platform_info);
713 free(this->tpm_version_info.ptr);
714 free(this);
715 }
716
717 /**
718 * Check for a TPM by querying for TPM Version Info
719 */
720 static bool has_tpm(private_pts_t *this)
721 {
722 TSS_HCONTEXT hContext;
723 TSS_HTPM hTPM;
724 TSS_RESULT result;
725
726 result = Tspi_Context_Create(&hContext);
727 if (result != TSS_SUCCESS)
728 {
729 goto err;
730 }
731 result = Tspi_Context_Connect(hContext, NULL);
732 if (result != TSS_SUCCESS)
733 {
734 goto err;
735 }
736 result = Tspi_Context_GetTpmObject (hContext, &hTPM);
737 if (result != TSS_SUCCESS)
738 {
739 goto err;
740 }
741 result = Tspi_TPM_GetCapability(hTPM, TSS_TPMCAP_VERSION_VAL, 0, NULL,
742 &this->tpm_version_info.len,
743 &this->tpm_version_info.ptr);
744 if (result != TSS_SUCCESS)
745 {
746 goto err;
747 }
748 this->tpm_version_info = chunk_clone(this->tpm_version_info);
749 return TRUE;
750
751 err:
752 DBG1(DBG_TNC, "TPM not available: tss error 0x%x", result);
753 return FALSE;
754 }
755
756 /**
757 * See header
758 */
759 pts_t *pts_create(bool is_imc)
760 {
761 private_pts_t *this;
762
763 INIT(this,
764 .public = {
765 .get_proto_caps = _get_proto_caps,
766 .set_proto_caps = _set_proto_caps,
767 .get_meas_algorithm = _get_meas_algorithm,
768 .set_meas_algorithm = _set_meas_algorithm,
769 .get_platform_info = _get_platform_info,
770 .set_platform_info = _set_platform_info,
771 .get_tpm_version_info = _get_tpm_version_info,
772 .set_tpm_version_info = _set_tpm_version_info,
773 .get_aik = _get_aik,
774 .set_aik = _set_aik,
775 .do_measurements = _do_measurements,
776 .destroy = _destroy,
777 },
778 .proto_caps = PTS_PROTO_CAPS_V,
779 .algorithm = PTS_MEAS_ALGO_SHA256,
780 );
781
782 if (is_imc)
783 {
784 if (has_tpm(this))
785 {
786 this->has_tpm = TRUE;
787 this->proto_caps |= PTS_PROTO_CAPS_T;
788 }
789 }
790 else
791 {
792 this->proto_caps |= PTS_PROTO_CAPS_T | PTS_PROTO_CAPS_C;
793 }
794
795 return &this->public;
796 }
797