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