1 /*
2 * The Initial Developer of the Original Code is International
3 * Business Machines Corporation. Portions created by IBM
4 * Corporation are Copyright (C) 2005, 2006 International Business
5 * Machines Corporation. All Rights Reserved.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the Common Public License as published by
9 * IBM Corporation; either version 1 of the License, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * Common Public License for more details.
16 *
17 * You should have received a copy of the Common Public License
18 * along with this program; if not, a copy can be viewed at
19 * http://www.opensource.org/licenses/cpl1.0.php.
20 */
21
22 #include "tpm_tspi.h"
23 #include "tpm_seal.h"
24 #include "tpm_unseal.h"
25 #include <errno.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31 #include <openssl/evp.h>
32 #include <trousers/tss.h>
33 #include <trousers/trousers.h>
34
35 enum tspi_errors {
36 ETSPICTXCREAT = 0,
37 ETSPICTXCNCT,
38 ETSPICTXCO,
39 ETSPICTXLKBU,
40 ETSPICTXLKBB,
41 ETSPISETAD,
42 ETSPIGETPO,
43 ETSPIPOLSS,
44 ETSPIDATU,
45 ETSPIPOLATO,
46 };
47
48 TSS_HCONTEXT hContext = 0;
49 #define TSPI_FUNCTION_NAME_MAX 30
50 char tspi_error_strings[][TSPI_FUNCTION_NAME_MAX]= {
51 "Tspi_Context_Create",
52 "Tspi_Context_Connect",
53 "Tspi_Context_CreateObject",
54 "Tspi_Context_LoadKeyByUUID",
55 "Tspi_Context_LoadKeyByBlob",
56 "Tspi_SetAttribData",
57 "Tspi_GetPolicyObject",
58 "Tspi_Policy_SetSecret",
59 "Tspi_Data_Unseal",
60 "Tspi_Policy_AssignToObject",
61 };
62
63 #define TSSKEY_DEFAULT_SIZE 768
64 #define EVPKEY_DEFAULT_SIZE 512
65
66 int tpm_errno;
67
tpmUnsealFile(char * fname,unsigned char ** tss_data,int * tss_size,BOOL srkWellKnown)68 int tpmUnsealFile( char* fname, unsigned char** tss_data, int* tss_size,
69 BOOL srkWellKnown ) {
70
71 int rc, rcLen=0, tssLen=0, evpLen=0;
72 BYTE* rcPtr;
73 char data[EVP_CIPHER_block_size(EVP_aes_256_cbc()) * 16];
74 BYTE *tssKeyData = NULL;
75 int tssKeyDataSize = 0;
76 BYTE *evpKeyData = NULL;
77 int evpKeyDataSize = 0;
78 struct stat stats;
79 TSS_HENCDATA hEncdata;
80 TSS_HKEY hSrk, hKey;
81 TSS_HPOLICY hPolicy;
82 UINT32 symKeyLen;
83 BYTE *symKey;
84 BYTE wellKnown[TCPA_SHA1_160_HASH_LEN] = TSS_WELL_KNOWN_SECRET;
85 char *srkSecret = NULL;
86 int srkSecretLen;
87 unsigned char* res_data = NULL;
88 int res_size = 0;
89
90 BIO *bdata = NULL, *b64 = NULL, *bmem = NULL;
91 int bioRc;
92
93 if ( tss_data == NULL || tss_size == NULL ) {
94 rc = TPMSEAL_STD_ERROR;
95 tpm_errno = EINVAL;
96 goto out;
97 }
98
99 *tss_data = NULL;
100 *tss_size = 0;
101
102 /* Test for file existence */
103 if ((rc = stat(fname, &stats))) {
104 tpm_errno = errno;
105 goto out;
106 }
107
108 /* Create an input file BIO */
109 if((bdata = BIO_new_file(fname, "r")) == NULL ) {
110 tpm_errno = errno;
111 rc = TPMSEAL_STD_ERROR;
112 goto out;
113 }
114
115 /* Test file header for TSS */
116 BIO_gets(bdata, data, sizeof(data));
117 if (strncmp(data, TPMSEAL_HDR_STRING,
118 strlen(TPMSEAL_HDR_STRING)) != 0) {
119 rc = TPMSEAL_FILE_ERROR;
120 tpm_errno = ENOTSSHDR;
121 goto out;
122 }
123
124 /* Looking for TSS Key Header */
125 BIO_gets(bdata, data, sizeof(data));
126 if (strncmp(data, TPMSEAL_TSS_STRING,
127 strlen(TPMSEAL_TSS_STRING)) != 0) {
128 rc = TPMSEAL_FILE_ERROR;
129 tpm_errno = EWRONGTSSTAG;
130 goto out;
131 }
132
133 /* Create a memory BIO to hold the base64 TSS key */
134 if ((bmem = BIO_new(BIO_s_mem())) == NULL) {
135 tpm_errno = EAGAIN;
136 rc = TPMSEAL_STD_ERROR;
137 goto out;
138 }
139 BIO_set_mem_eof_return(bmem, 0);
140
141 /* Read the base64 TSS key into the memory BIO */
142 while ((rcLen = BIO_gets(bdata, data, sizeof(data))) > 0) {
143 /* Look for EVP Key Header (end of key) */
144 if (strncmp(data, TPMSEAL_EVP_STRING,
145 strlen(TPMSEAL_EVP_STRING)) == 0)
146 break;
147
148 if (BIO_write(bmem, data, rcLen) <= 0) {
149 tpm_errno = EIO;
150 rc = TPMSEAL_STD_ERROR;
151 goto out;
152 }
153 }
154 if (strncmp(data, TPMSEAL_EVP_STRING,
155 strlen(TPMSEAL_EVP_STRING)) != 0 ) {
156 tpm_errno = EWRONGEVPTAG;
157 rc = TPMSEAL_FILE_ERROR;
158 goto out;
159 }
160
161 /* Create a base64 BIO to decode the TSS key */
162 if ((b64 = BIO_new(BIO_f_base64())) == NULL) {
163 tpm_errno = EAGAIN;
164 rc = TPMSEAL_STD_ERROR;
165 goto out;
166 }
167
168 /* Decode the TSS key */
169 bmem = BIO_push( b64, bmem );
170 while ((rcLen = BIO_read(bmem, data, sizeof(data))) > 0) {
171 if ((tssLen + rcLen) > tssKeyDataSize) {
172 tssKeyDataSize += TSSKEY_DEFAULT_SIZE;
173 rcPtr = realloc( tssKeyData, tssKeyDataSize);
174 if ( rcPtr == NULL ) {
175 tpm_errno = ENOMEM;
176 rc = TPMSEAL_STD_ERROR;
177 goto out;
178 }
179 tssKeyData = rcPtr;
180 }
181 memcpy(tssKeyData + tssLen, data, rcLen);
182 tssLen += rcLen;
183 }
184 bmem = BIO_pop(b64);
185 BIO_free(b64);
186 b64 = NULL;
187 bioRc = BIO_reset(bmem);
188 if (bioRc != 1) {
189 tpm_errno = EIO;
190 rc = TPMSEAL_STD_ERROR;
191 goto out;
192 }
193
194 /* Check for EVP Key Type Header */
195 BIO_gets(bdata, data, sizeof(data));
196 if (strncmp(data, TPMSEAL_KEYTYPE_SYM,
197 strlen(TPMSEAL_KEYTYPE_SYM)) != 0 ) {
198 rc = TPMSEAL_FILE_ERROR;
199 tpm_errno = EWRONGKEYTYPE;
200 goto out;
201 }
202
203 /* Make sure it's a supported cipher
204 (currently only AES 256 CBC) */
205 if (strncmp(data + strlen(TPMSEAL_KEYTYPE_SYM),
206 TPMSEAL_CIPHER_AES256CBC,
207 strlen(TPMSEAL_CIPHER_AES256CBC)) != 0) {
208 rc = TPMSEAL_FILE_ERROR;
209 tpm_errno = EWRONGKEYTYPE;
210 goto out;
211 }
212
213 /* Read the base64 Symmetric key into the memory BIO */
214 while ((rcLen = BIO_gets(bdata, data, sizeof(data))) > 0) {
215 /* Look for Encrypted Data Header (end of key) */
216 if (strncmp(data, TPMSEAL_ENC_STRING,
217 strlen(TPMSEAL_ENC_STRING)) == 0)
218 break;
219
220 if (BIO_write(bmem, data, rcLen) <= 0) {
221 tpm_errno = EIO;
222 rc = TPMSEAL_STD_ERROR;
223 goto out;
224 }
225 }
226 if (strncmp(data, TPMSEAL_ENC_STRING,
227 strlen(TPMSEAL_ENC_STRING)) != 0 ) {
228 tpm_errno = EWRONGDATTAG;
229 rc = TPMSEAL_FILE_ERROR;
230 goto out;
231 }
232
233 /* Create a base64 BIO to decode the Symmetric key */
234 if ((b64 = BIO_new(BIO_f_base64())) == NULL) {
235 tpm_errno = EAGAIN;
236 rc = TPMSEAL_STD_ERROR;
237 goto out;
238 }
239
240 /* Decode the Symmetric key */
241 bmem = BIO_push( b64, bmem );
242 while ((rcLen = BIO_read(bmem, data, sizeof(data))) > 0) {
243 if ((evpLen + rcLen) > evpKeyDataSize) {
244 evpKeyDataSize += EVPKEY_DEFAULT_SIZE;
245 rcPtr = realloc( evpKeyData, evpKeyDataSize);
246 if ( rcPtr == NULL ) {
247 tpm_errno = ENOMEM;
248 rc = TPMSEAL_STD_ERROR;
249 goto out;
250 }
251 evpKeyData = rcPtr;
252 }
253 memcpy(evpKeyData + evpLen, data, rcLen);
254 evpLen += rcLen;
255 }
256 bmem = BIO_pop(b64);
257 BIO_free(b64);
258 b64 = NULL;
259 bioRc = BIO_reset(bmem);
260 if (bioRc != 1) {
261 tpm_errno = EIO;
262 rc = TPMSEAL_STD_ERROR;
263 goto out;
264 }
265
266 /* Read the base64 encrypted data into the memory BIO */
267 while ((rcLen = BIO_gets(bdata, data, sizeof(data))) > 0) {
268 /* Look for TSS Footer (end of data) */
269 if (strncmp(data, TPMSEAL_FTR_STRING,
270 strlen(TPMSEAL_FTR_STRING)) == 0)
271 break;
272
273 if (BIO_write(bmem, data, rcLen) <= 0) {
274 tpm_errno = EIO;
275 rc = TPMSEAL_STD_ERROR;
276 goto out;
277 }
278 }
279 if (strncmp(data, TPMSEAL_FTR_STRING,
280 strlen(TPMSEAL_FTR_STRING)) != 0 ) {
281 tpm_errno = ENOTSSFTR;
282 rc = TPMSEAL_FILE_ERROR;
283 goto out;
284 }
285
286 /* Unseal */
287 if ((rc=Tspi_Context_Create(&hContext)) != TSS_SUCCESS) {
288 tpm_errno = ETSPICTXCREAT;
289 goto out;
290 }
291
292 if (!srkWellKnown) {
293 /* Prompt for SRK password */
294 srkSecret = GETPASSWD(_("Enter SRK password: "), &srkSecretLen, FALSE);
295 if (!srkSecret)
296 goto out;
297 }
298 if ((rc=Tspi_Context_Connect(hContext, NULL)) != TSS_SUCCESS) {
299 tpm_errno = ETSPICTXCNCT;
300 goto tss_out;
301 }
302
303 if ((rc=Tspi_Context_CreateObject(hContext,
304 TSS_OBJECT_TYPE_ENCDATA,
305 TSS_ENCDATA_SEAL,
306 &hEncdata)) != TSS_SUCCESS) {
307 tpm_errno = ETSPICTXCO;
308 goto tss_out;
309 }
310
311 if ((rc=Tspi_SetAttribData(hEncdata,
312 TSS_TSPATTRIB_ENCDATA_BLOB,
313 TSS_TSPATTRIB_ENCDATABLOB_BLOB,
314 evpLen, evpKeyData)) != TSS_SUCCESS) {
315 tpm_errno = ETSPISETAD;
316 goto tss_out;
317 }
318
319 if ((rc=Tspi_Context_CreateObject(hContext,
320 TSS_OBJECT_TYPE_POLICY,
321 TSS_POLICY_USAGE,
322 &hPolicy)) != TSS_SUCCESS) {
323 tpm_errno = ETSPICTXCO;
324 goto tss_out;
325 }
326
327 if ((rc=Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_PLAIN,
328 strlen(TPMSEAL_SECRET),
329 (BYTE *)TPMSEAL_SECRET)) != TSS_SUCCESS) {
330 tpm_errno = ETSPIPOLSS;
331 goto tss_out;
332 }
333
334 if ((rc=Tspi_Policy_AssignToObject(hPolicy, hEncdata)) != TSS_SUCCESS) {
335 tpm_errno = ETSPIPOLATO;
336 goto tss_out;
337 }
338
339 if ((rc=Tspi_Context_LoadKeyByUUID(hContext, TSS_PS_TYPE_SYSTEM,
340 SRK_UUID, &hSrk)) != TSS_SUCCESS) {
341 tpm_errno = ETSPICTXLKBU;
342 goto tss_out;
343 }
344
345 /* Don't create a new policy for the SRK's secret, just use the context's
346 * default policy */
347 if ((rc=Tspi_GetPolicyObject(hSrk, TSS_POLICY_USAGE,
348 &hPolicy)) != TSS_SUCCESS){
349 tpm_errno = ETSPIGETPO;
350 goto tss_out;
351 }
352
353 if (srkWellKnown)
354 rc = Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_SHA1,
355 sizeof(wellKnown),
356 (BYTE *) wellKnown);
357 else
358 rc = Tspi_Policy_SetSecret(hPolicy,TSS_SECRET_MODE_PLAIN,
359 srkSecretLen,
360 (BYTE *) srkSecret);
361
362 if (rc != TSS_SUCCESS) {
363 tpm_errno = ETSPIPOLSS;
364 goto tss_out;
365 }
366
367 /* Failure point if trying to unseal data on a differnt TPM */
368 if ((rc=Tspi_Context_LoadKeyByBlob(hContext, hSrk, tssLen,
369 tssKeyData, &hKey)) != TSS_SUCCESS) {
370 tpm_errno = ETSPICTXLKBB;
371 goto tss_out;
372 }
373
374 if ((rc=Tspi_Context_CreateObject(hContext,
375 TSS_OBJECT_TYPE_POLICY,
376 TSS_POLICY_USAGE,
377 &hPolicy)) != TSS_SUCCESS) {
378 tpm_errno = ETSPICTXCO;
379 goto tss_out;
380 }
381
382 if ((rc=Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_PLAIN,
383 strlen(TPMSEAL_SECRET),
384 (BYTE *)TPMSEAL_SECRET)) != TSS_SUCCESS) {
385 tpm_errno = ETSPIPOLSS;
386 goto tss_out;
387 }
388
389 if ((rc=Tspi_Policy_AssignToObject(hPolicy, hKey)) != TSS_SUCCESS) {
390 tpm_errno = ETSPIPOLATO;
391 goto tss_out;
392 }
393
394 if ((rc=Tspi_Data_Unseal(hEncdata, hKey, &symKeyLen,
395 &symKey)) != TSS_SUCCESS) {
396 tpm_errno = ETSPIDATU;
397 goto tss_out;
398 }
399
400 /* Malloc a block of storage to hold the decrypted data
401 Using the size of the mem BIO is more than enough
402 (plus an extra cipher block size) */
403 res_data = malloc(BIO_pending(bmem) + EVP_CIPHER_block_size(EVP_aes_256_cbc()));
404 if ( res_data == NULL ) {
405 rc = TPMSEAL_STD_ERROR;
406 tpm_errno = ENOMEM;
407 goto tss_out;
408 }
409
410 /* Decode and decrypt the encrypted data */
411 EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
412 EVP_DecryptInit(ctx, EVP_aes_256_cbc(), symKey, (unsigned char *)TPMSEAL_IV);
413
414 /* Create a base64 BIO to decode the encrypted data */
415 if ((b64 = BIO_new(BIO_f_base64())) == NULL) {
416 tpm_errno = EAGAIN;
417 rc = TPMSEAL_STD_ERROR;
418 goto tss_out;
419 }
420
421 bmem = BIO_push( b64, bmem );
422 while ((rcLen = BIO_read(bmem, data, sizeof(data))) > 0) {
423 EVP_DecryptUpdate(ctx, res_data+res_size,
424 &rcLen, (unsigned char *)data, rcLen);
425 res_size += rcLen;
426 }
427 EVP_DecryptFinal(ctx, res_data+res_size, &rcLen);
428 res_size += rcLen;
429 bmem = BIO_pop(b64);
430 BIO_free(b64);
431 b64 = NULL;
432 /* a BIO_reset failure shouldn't have an affect at this point */
433 BIO_reset(bmem);
434
435 tss_out:
436 Tspi_Context_Close(hContext);
437 out:
438
439 if (srkSecret)
440 shredPasswd(srkSecret);
441
442 if ( bdata )
443 BIO_free(bdata);
444 if ( b64 )
445 BIO_free(b64);
446 if ( bmem ) {
447 BIO_set_close(bmem, BIO_CLOSE);
448 BIO_free(bmem);
449 }
450
451 if ( evpKeyData )
452 free(evpKeyData);
453 if ( tssKeyData )
454 free(tssKeyData);
455
456 if ( rc == 0 ) {
457 *tss_data = res_data;
458 *tss_size = res_size;
459 } else
460 free(res_data);
461
462 return rc;
463 }
464
tpmUnsealShred(unsigned char * data,int size)465 void tpmUnsealShred(unsigned char* data, int size) {
466
467 if ( data != NULL ) {
468 __memset( data, 0, size);
469 free(data);
470 }
471
472 }
473
474 char tpm_error_buf[512];
tpmUnsealStrerror(int rc)475 char * tpmUnsealStrerror(int rc) {
476
477 switch(rc) {
478 case 0:
479 return "Success";
480 case TPMSEAL_STD_ERROR:
481 return strerror(tpm_errno);
482 case TPMSEAL_FILE_ERROR:
483 switch(tpm_errno) {
484 case ENOTSSHDR:
485 return _("No TSS header present");
486 case ENOTSSFTR:
487 return _("No TSS footer present");
488 case EWRONGTSSTAG:
489 return _("Wrong TSS tag");
490 case EWRONGEVPTAG:
491 return _("Wrong EVP tag");
492 case EWRONGDATTAG:
493 return _("Wrong DATA tag");
494 case EWRONGKEYTYPE:
495 return _("Not a Symmetric EVP Key");
496 case EBADSEEK:
497 return _("Unable to move to desired file position");
498 }
499 default:
500 snprintf(tpm_error_buf, sizeof(tpm_error_buf),
501 "%s: 0x%08x - layer=%s, code=%04x (%d), %s",
502 tspi_error_strings[tpm_errno],
503 rc, Trspi_Error_Layer(rc),
504 Trspi_Error_Code(rc),
505 Trspi_Error_Code(rc),
506 Trspi_Error_String(rc));
507 return tpm_error_buf;
508 }
509 return "";
510 }
511