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