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