Included fake_ek_cert header back
[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 DBG1(DBG_IMC, "Tspi_GetAttribData modulusLen != 256");
218 Tspi_Context_FreeMemory (hContext, modulus);
219 return result;
220 }
221 /* TODO define fakeEKCert
222 *pCertLen = sizeof(fakeEKCert);
223 *pCert = malloc (*pCertLen);
224 memcpy (*pCert, fakeEKCert, *pCertLen);
225 memcpy (*pCert + 0xc6, modulus, modulusLen);
226 */
227 Tspi_Context_FreeMemory (hContext, modulus);
228
229 return TSS_SUCCESS;
230 }
231
232 /**
233 * Read the level N CA from privacyca.com
234 * Assume Curl library has been initialized
235 */
236
237 static X509* readPCAcert (int level)
238 {
239 CURL *hCurl;
240 char url[128];
241 FILE *f_tmp = tmpfile();
242 X509 *x509;
243 int result;
244
245 hCurl = curl_easy_init ();
246 sprintf (url, CERTURL, level);
247 curl_easy_setopt (hCurl, CURLOPT_URL, url);
248 curl_easy_setopt(hCurl, CURLOPT_WRITEDATA, (BYTE **)f_tmp);
249
250 if ((result = curl_easy_perform(hCurl))) {
251 DBG1(DBG_IMC, "Unable to connect to Privacy CA, curl library result code %d", result);
252 fclose(f_tmp);
253 return NULL;
254 }
255
256 rewind (f_tmp);
257 x509 = PEM_read_X509 (f_tmp, NULL, NULL, NULL);
258 fclose(f_tmp);
259
260 return x509;
261 }
262
263
264 /**
265 * Obtain an AIK, SRK and TPM Owner secret has to be both set to well known secret
266 * of 20 bytes of zero
267 */
268 static bool obtain_aik(private_pts_t *this)
269 {
270 TSS_HCONTEXT hContext;
271 TSS_HTPM hTPM;
272 TSS_HKEY hSRK;
273 TSS_HKEY hPCAKey;
274 TSS_HKEY hIdentKey;
275 TSS_HPOLICY hSrkPolicy;
276 TSS_HPOLICY hTPMPolicy;
277 TSS_UUID SRK_UUID = TSS_UUID_SRK;
278 BYTE secret[] = TSS_WELL_KNOWN_SECRET;
279 X509 *x509;
280 EVP_PKEY *pcaKey;
281 RSA *rsa = NULL;
282 CURL *hCurl;
283 struct curl_slist *slist = NULL;
284 BYTE n[16384/8];
285 int size_n;
286 FILE *f_tmp;
287 BYTE *rgbTCPAIdentityReq;
288 UINT32 ulTCPAIdentityReqLength;
289 UINT32 initFlags = TSS_KEY_TYPE_IDENTITY | TSS_KEY_SIZE_2048 |
290 TSS_KEY_VOLATILE | TSS_KEY_NOT_MIGRATABLE;
291 BYTE asymBuf[EKSIZE];
292 BYTE *symBuf;
293 BYTE *credBuf;
294 BYTE *tbuf;
295 UINT32 asymBufSize;
296 UINT32 symBufSize;
297 UINT32 credBufSize;
298 static int level = 0;
299 BYTE *ekCert = NULL;
300 UINT32 ekCertLen;
301 char url[128];
302 int result;
303
304 this->aik = chunk_empty;
305 this->is_naked_key = false;
306
307 curl_global_init (CURL_GLOBAL_ALL);
308
309 DBG3(DBG_IMC, "Retrieving PCA certificate...");
310
311 /* TPM has EK Certificate */
312 if(REALEK)
313 {
314 level = 1;
315 }
316 x509 = readPCAcert (level);
317 if (x509 == NULL) {
318 DBG1(DBG_IMC, "Error reading PCA key");
319 goto err;
320 }
321 pcaKey = X509_get_pubkey(x509);
322 rsa = EVP_PKEY_get1_RSA(pcaKey);
323 if (rsa == NULL) {
324 DBG1(DBG_IMC, "Error reading RSA key from PCA");
325 goto err;
326 }
327 X509_free (x509);
328
329 result = Tspi_Context_Create(&hContext);
330 if (result != TSS_SUCCESS) {
331 DBG1(DBG_IMC, "Error 0x%x on Tspi_Context_Create", result);
332 goto err;
333 }
334 result = Tspi_Context_Connect(hContext, NULL);
335 if (result != TSS_SUCCESS) {
336 DBG1(DBG_IMC, "Error 0x%x on Tspi_Context_Connect", result);
337 goto err;
338 }
339 result = Tspi_Context_GetTpmObject (hContext, &hTPM);
340 if (result != TSS_SUCCESS) {
341 DBG1(DBG_IMC, "Error 0x%x on Tspi_Context_GetTpmObject", result);
342 goto err;
343 }
344 result = Tspi_Context_LoadKeyByUUID(hContext,
345 TSS_PS_TYPE_SYSTEM, SRK_UUID, &hSRK);
346 if (result != TSS_SUCCESS) {
347 DBG1(DBG_IMC, "Error 0x%x on Tspi_Context_LoadKeyByUUID for SRK", result);
348 goto err;
349 }
350 result = Tspi_GetPolicyObject(hSRK, TSS_POLICY_USAGE, &hSrkPolicy);
351 if (result != TSS_SUCCESS) {
352 DBG1(DBG_IMC, "Error 0x%x on Tspi_GetPolicyObject for SRK", result);
353 goto err;
354 }
355 result = Tspi_Policy_SetSecret(hSrkPolicy, TSS_SECRET_MODE_SHA1, 20, secret);
356 if (result != TSS_SUCCESS) {
357 DBG1(DBG_IMC, "Error 0x%x on Tspi_Policy_SetSecret for SRK", result);
358 goto err;
359 }
360 result = Tspi_GetPolicyObject(hTPM, TSS_POLICY_USAGE, &hTPMPolicy);
361 if (result != TSS_SUCCESS) {
362 DBG1(DBG_IMC, "Error 0x%x on Tspi_GetPolicyObject for TPM", result);
363 goto err;
364 }
365 result = Tspi_Policy_SetSecret(hTPMPolicy, TSS_SECRET_MODE_SHA1, 20, secret);
366 if (result != TSS_SUCCESS) {
367 DBG1(DBG_IMC, "Error 0x%x on Tspi_Policy_SetSecret for TPM", result);
368 goto err;
369 }
370
371 result = Tspi_Context_CreateObject(hContext,
372 TSS_OBJECT_TYPE_RSAKEY,
373 initFlags, &hIdentKey);
374 if (result != TSS_SUCCESS) {
375 DBG1(DBG_IMC, "Error 0x%x on Tspi_Context_CreateObject for key", result);
376 goto err;
377 }
378
379 result = Tspi_Context_CreateObject(hContext,
380 TSS_OBJECT_TYPE_RSAKEY,
381 TSS_KEY_TYPE_LEGACY|TSS_KEY_SIZE_2048,
382 &hPCAKey);
383 if (result != TSS_SUCCESS) {
384 DBG1(DBG_IMC, "Error 0x%x on Tspi_Context_CreateObject for PCA\n", result);
385 goto err;
386 }
387 if ((size_n = BN_bn2bin(rsa->n, n)) <= 0) {
388 printf("BN_bn2bin failed\n");
389 goto err;;
390 }
391 result = Tspi_SetAttribData (hPCAKey, TSS_TSPATTRIB_RSAKEY_INFO,
392 TSS_TSPATTRIB_KEYINFO_RSA_MODULUS, size_n, n);
393 if (result != TSS_SUCCESS) {
394 DBG1(DBG_IMC, "Error 0x%x on Tspi_SetAttribData for PCA modulus", result);
395 goto err;
396 }
397 result = Tspi_SetAttribUint32(hPCAKey, TSS_TSPATTRIB_KEY_INFO,
398 TSS_TSPATTRIB_KEYINFO_ENCSCHEME,
399 TSS_ES_RSAESPKCSV15);
400 if (result != TSS_SUCCESS) {
401 DBG1(DBG_IMC, "Error 0x%x on Tspi_SetAttribUint32 for PCA encscheme", result);
402 goto err;
403 }
404
405 if(!REALEK)
406 {
407 result = makeEKCert(hContext, hTPM, &ekCertLen, &ekCert);
408 if (result != TSS_SUCCESS) {
409 DBG1(DBG_IMC, "Error 0x%x on makeEKCert\n", result);
410 goto err;
411 }
412
413 result = Tspi_SetAttribData(hTPM, TSS_TSPATTRIB_TPM_CREDENTIAL,
414 TSS_TPMATTRIB_EKCERT, ekCertLen, ekCert);
415 if (result != TSS_SUCCESS) {
416 DBG1(DBG_IMC, "Error 0x%x on SetAttribData for EKCert", result);
417 goto err;
418 }
419 }
420
421 DBG3(DBG_IMC, "Generating attestation identity key...");
422 result = Tspi_TPM_CollateIdentityRequest(hTPM, hSRK, hPCAKey, 0,
423 NULL, hIdentKey, TSS_ALG_AES,
424 &ulTCPAIdentityReqLength,
425 &rgbTCPAIdentityReq);
426 if (result != TSS_SUCCESS){
427 DBG1(DBG_IMC, "Error 0x%x on Tspi_TPM_CollateIdentityRequest", result);
428 goto err;
429 }
430
431 DBG3(DBG_IMC, "Sending request to PrivacyCA.com...");
432
433 /* Send to server */
434 f_tmp = tmpfile();
435 hCurl = curl_easy_init ();
436 sprintf (url, REQURL, level);
437 curl_easy_setopt (hCurl, CURLOPT_URL, url);
438 curl_easy_setopt (hCurl, CURLOPT_POSTFIELDS, (void *)rgbTCPAIdentityReq);
439 curl_easy_setopt (hCurl, CURLOPT_POSTFIELDSIZE, ulTCPAIdentityReqLength);
440 curl_easy_setopt (hCurl, CURLOPT_WRITEDATA, (BYTE **)f_tmp);
441 slist = curl_slist_append (slist, "Pragma: no-cache");
442 slist = curl_slist_append (slist, "Content-Type: application/octet-stream");
443 slist = curl_slist_append (slist, "Content-Transfer-Encoding: binary");
444 curl_easy_setopt (hCurl, CURLOPT_HTTPHEADER, slist);
445 if ((result = curl_easy_perform(hCurl))) {
446 DBG1(DBG_IMC, "Unable to connect to Privacy CA, curl library result code %d", result);
447 exit (result);
448 }
449 curl_slist_free_all(slist);
450
451 DBG3(DBG_IMC, "Processing response from PrivacyCA...");
452
453 fflush (f_tmp);
454 symBufSize = ftell(f_tmp);
455 symBuf = malloc(symBufSize);
456 rewind(f_tmp);
457 if(!fread (symBuf, 1, symBufSize, f_tmp))
458 {
459 DBG1(DBG_IMC, "Failed to read buffer");
460 goto err;
461 }
462
463 fclose (f_tmp);
464
465 asymBufSize = sizeof(asymBuf);
466 if (symBufSize <= asymBufSize)
467 {
468 DBG1(DBG_IMC, "Bad response from PrivacyCA.com: %s", symBuf);
469 goto err;
470 }
471
472 memcpy (asymBuf, symBuf, asymBufSize);
473 symBufSize -= asymBufSize;
474 symBuf += asymBufSize;
475
476 result = Tspi_Key_LoadKey (hIdentKey, hSRK);
477 if (result != TSS_SUCCESS) {
478 DBG1(DBG_IMC, "Error 0x%x on Tspi_Key_LoadKey for AIK", result);
479 goto err;
480 }
481
482 result = Tspi_TPM_ActivateIdentity (hTPM, hIdentKey, asymBufSize, asymBuf,
483 symBufSize, symBuf,
484 &credBufSize, &credBuf);
485 if (result != TSS_SUCCESS) {
486 DBG1(DBG_IMC, "Error 0x%x on Tspi_TPM_ActivateIdentity", result);
487 goto err;
488 }
489
490 /* Output credential in PEM format */
491 tbuf = credBuf;
492 x509 = d2i_X509(NULL, (const BYTE **)&tbuf, credBufSize);
493 if (x509 == NULL) {
494 DBG1(DBG_IMC, "Unable to parse returned credential");
495 goto err;
496 }
497 if (tbuf-credBuf != credBufSize) {
498 DBG1(DBG_IMC, "Note, not all data from privacy ca was parsed correctly");
499 }
500
501 if(x509)
502 {
503 BUF_MEM *mem_buf;
504 BIO* bp;
505 u_int32_t len;
506
507 bp = BIO_new(BIO_s_mem());
508 PEM_write_bio_X509(bp, x509);
509
510 len = BIO_get_mem_data(bp, &mem_buf);
511 char tmp[len+1];
512
513 memcpy(tmp, mem_buf, len);
514 tmp[len] = '\0';
515
516 DBG3(DBG_IMC,"X509 Certificate (PEM format):\n%s\n", tmp);
517 this->aik = chunk_create(tmp, len + 1);
518 this->aik = chunk_clone(this->aik);
519
520 X509_free (x509);
521
522 }
523 else
524 {
525 DBG1(DBG_IMC, "Neither AIK Key blob, nor AIK Certificate is available");
526 goto err;
527 }
528
529 DBG3(DBG_IMC, "Succeeded at obtaining AIK Certificate from Privacy CA!");
530 return TRUE;
531
532 err:
533 return FALSE;
534 }
535
536 METHOD(pts_t, get_aik, bool,
537 private_pts_t *this, chunk_t *aik, bool *is_naked_key)
538 {
539 if(obtain_aik(this) != TRUE )
540 {
541 return FALSE;
542 }
543
544 *aik = this->aik;
545 *is_naked_key = this->is_naked_key;
546
547 return TRUE;
548 }
549
550 METHOD(pts_t, set_aik, void,
551 private_pts_t *this, chunk_t aik, bool is_naked_key)
552 {
553 this->aik = chunk_clone(aik);
554 this->is_naked_key = is_naked_key;
555 }
556
557 /**
558 * Compute a hash over a file
559 */
560 static bool hash_file(hasher_t *hasher, char *pathname, u_char *hash)
561 {
562 u_char buffer[PTS_BUF_SIZE];
563 FILE *file;
564 int bytes_read;
565
566 file = fopen(pathname, "rb");
567 if (!file)
568 {
569 DBG1(DBG_IMC," file '%s' can not be opened, %s", pathname,
570 strerror(errno));
571 return FALSE;
572 }
573 while (TRUE)
574 {
575 bytes_read = fread(buffer, 1, sizeof(buffer), file);
576 if (bytes_read > 0)
577 {
578 hasher->get_hash(hasher, chunk_create(buffer, bytes_read), NULL);
579 }
580 else
581 {
582 hasher->get_hash(hasher, chunk_empty, hash);
583 break;
584 }
585 }
586 fclose(file);
587
588 return TRUE;
589 }
590
591 /**
592 * Get the relative filename of a fully qualified file pathname
593 */
594 static char* get_filename(char *pathname)
595 {
596 char *pos, *filename;
597
598 pos = filename = pathname;
599 while (pos && *(++pos) != '\0')
600 {
601 filename = pos;
602 pos = strchr(filename, '/');
603 }
604 return filename;
605 }
606
607 METHOD(pts_t, do_measurements, pts_file_meas_t*,
608 private_pts_t *this, u_int16_t request_id, char *pathname, bool is_directory)
609 {
610 hasher_t *hasher;
611 hash_algorithm_t hash_alg;
612 u_char hash[HASH_SIZE_SHA384];
613 chunk_t measurement;
614 pts_file_meas_t *measurements;
615
616 /* Create a hasher */
617 hash_alg = pts_meas_to_hash_algorithm(this->algorithm);
618 hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
619 if (!hasher)
620 {
621 DBG1(DBG_IMC, " hasher %N not available", hash_algorithm_names, hash_alg);
622 return NULL;
623 }
624
625 /* Create a measurement object */
626 measurements = pts_file_meas_create(request_id);
627
628 /* Link the hash to the measurement and set the measurement length */
629 measurement = chunk_create(hash, hasher->get_hash_size(hasher));
630
631 if (is_directory)
632 {
633 enumerator_t *enumerator;
634 char *rel_name, *abs_name;
635 struct stat st;
636
637 enumerator = enumerator_create_directory(pathname);
638 if (!enumerator)
639 {
640 DBG1(DBG_IMC," directory '%s' can not be opened, %s", pathname,
641 strerror(errno));
642 hasher->destroy(hasher);
643 measurements->destroy(measurements);
644 return NULL;
645 }
646 while (enumerator->enumerate(enumerator, &rel_name, &abs_name, &st))
647 {
648 /* measure regular files only */
649 if (S_ISREG(st.st_mode) && *rel_name != '.')
650 {
651 if (!hash_file(hasher, abs_name, hash))
652 {
653 enumerator->destroy(enumerator);
654 hasher->destroy(hasher);
655 measurements->destroy(measurements);
656 return NULL;
657 }
658 DBG2(DBG_IMC, " %#B for '%s'", &measurement, rel_name);
659 measurements->add(measurements, rel_name, measurement);
660 }
661 }
662 enumerator->destroy(enumerator);
663 }
664 else
665 {
666 char *filename;
667
668 if (!hash_file(hasher, pathname, hash))
669 {
670 hasher->destroy(hasher);
671 measurements->destroy(measurements);
672 return NULL;
673 }
674 filename = get_filename(pathname);
675 DBG2(DBG_IMC, " %#B for '%s'", &measurement, filename);
676 measurements->add(measurements, filename, measurement);
677 }
678 hasher->destroy(hasher);
679
680 return measurements;
681 }
682
683 METHOD(pts_t, destroy, void,
684 private_pts_t *this)
685 {
686 free(this->platform_info);
687 free(this->tpm_version_info.ptr);
688 free(this);
689 }
690
691 /**
692 * Check for a TPM by querying for TPM Version Info
693 */
694 static bool has_tpm(private_pts_t *this)
695 {
696 TSS_HCONTEXT hContext;
697 TSS_HTPM hTPM;
698 TSS_RESULT result;
699
700 result = Tspi_Context_Create(&hContext);
701 if (result != TSS_SUCCESS)
702 {
703 goto err;
704 }
705 result = Tspi_Context_Connect(hContext, NULL);
706 if (result != TSS_SUCCESS)
707 {
708 goto err;
709 }
710 result = Tspi_Context_GetTpmObject (hContext, &hTPM);
711 if (result != TSS_SUCCESS)
712 {
713 goto err;
714 }
715 result = Tspi_TPM_GetCapability(hTPM, TSS_TPMCAP_VERSION_VAL, 0, NULL,
716 &this->tpm_version_info.len,
717 &this->tpm_version_info.ptr);
718 if (result != TSS_SUCCESS)
719 {
720 goto err;
721 }
722 this->tpm_version_info = chunk_clone(this->tpm_version_info);
723 return TRUE;
724
725 err:
726 DBG1(DBG_TNC, "TPM not available: tss error 0x%x", result);
727 return FALSE;
728 }
729
730 /**
731 * See header
732 */
733 pts_t *pts_create(bool is_imc)
734 {
735 private_pts_t *this;
736
737 INIT(this,
738 .public = {
739 .get_proto_caps = _get_proto_caps,
740 .set_proto_caps = _set_proto_caps,
741 .get_meas_algorithm = _get_meas_algorithm,
742 .set_meas_algorithm = _set_meas_algorithm,
743 .get_platform_info = _get_platform_info,
744 .set_platform_info = _set_platform_info,
745 .get_tpm_version_info = _get_tpm_version_info,
746 .set_tpm_version_info = _set_tpm_version_info,
747 .get_aik = _get_aik,
748 .set_aik = _set_aik,
749 .do_measurements = _do_measurements,
750 .destroy = _destroy,
751 },
752 .proto_caps = PTS_PROTO_CAPS_V,
753 .algorithm = PTS_MEAS_ALGO_SHA256,
754 );
755
756 if (is_imc)
757 {
758 if (has_tpm(this))
759 {
760 this->has_tpm = TRUE;
761 this->proto_caps |= PTS_PROTO_CAPS_T;
762 }
763 }
764 else
765 {
766 this->proto_caps |= PTS_PROTO_CAPS_T | PTS_PROTO_CAPS_C;
767 }
768
769 return &this->public;
770 }
771