Home | History | Annotate | Line # | Download | only in lib
      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 
     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 
    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];
    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