Home | History | Annotate | Line # | Download | only in cmds
      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 #include <openssl/evp.h>
     22 #include <limits.h>
     23 #include "tpm_tspi.h"
     24 #include "tpm_utils.h"
     25 #include "tpm_seal.h"
     26 
     27 static void help(const char *aCmd)
     28 {
     29 	logCmdHelp(aCmd);
     30 	logCmdOption("-i, --infile FILE",
     31 		     _
     32 		     ("Filename containing key to seal. Default is STDIN."));
     33 	logCmdOption("-o, --outfile FILE",
     34 		     _
     35 		     ("Filename to write sealed key to.  Default is STDOUT."));
     36 	logCmdOption("-p, --pcr NUMBER",
     37 		     _
     38 		     ("PCR to seal data to.  Default is none.  This option can be specified multiple times to choose more than one PCR."));
     39 	logCmdOption("-z, --well-known", _("Use TSS_WELL_KNOWN_SECRET as the SRK secret."));
     40 	logCmdOption("-u, --unicode", _("Use TSS UNICODE encoding for the SRK password to comply with applications using TSS popup boxes"));
     41 
     42 }
     43 
     44 static char in_filename[PATH_MAX] = "", out_filename[PATH_MAX] = "";
     45 static TSS_HPCRS hPcrs = NULL_HPCRS;
     46 static TSS_HTPM hTpm;
     47 static UINT32 selectedPcrs[24];
     48 static UINT32 selectedPcrsLen = 0;
     49 static BOOL passUnicode = FALSE;
     50 static BOOL isWellKnown = FALSE;
     51 TSS_HCONTEXT hContext = 0;
     52 
     53 static int parse(const int aOpt, const char *aArg)
     54 {
     55 	int rc = -1;
     56 
     57 	switch (aOpt) {
     58 	case 'i':
     59 		if (aArg) {
     60 			strncpy(in_filename, aArg, PATH_MAX);
     61 			rc = 0;
     62 		}
     63 		break;
     64 	case 'o':
     65 		if (aArg) {
     66 			strncpy(out_filename, aArg, PATH_MAX);
     67 			rc = 0;
     68 		}
     69 		break;
     70 	case 'p':
     71 		if (aArg) {
     72 			selectedPcrs[selectedPcrsLen++] = atoi(aArg);
     73 			rc = 0;
     74 		}
     75 		break;
     76 	case 'u':
     77 		passUnicode = TRUE;
     78 		rc = 0;
     79 		break;
     80 	case 'z':
     81 		isWellKnown = TRUE;
     82 		rc = 0;
     83 		break;
     84 	default:
     85 		break;
     86 	}
     87 	return rc;
     88 
     89 }
     90 
     91 int main(int argc, char **argv)
     92 {
     93 
     94 	TSS_HKEY hSrk, hKey;
     95 	TSS_HENCDATA hEncdata;
     96 	TSS_HPOLICY hPolicy;
     97 	int iRc = -1;
     98 	struct option opts[] =
     99 	    { {"infile", required_argument, NULL, 'i'},
    100 	{"outfile", required_argument, NULL, 'o'},
    101 	{"pcr", required_argument, NULL, 'p'},
    102 	{"unicode", no_argument, NULL, 'u'},
    103 	{"well-known", no_argument, NULL, 'z'}
    104 	};
    105 	unsigned char line[EVP_CIPHER_block_size(EVP_aes_256_cbc()) * 16];
    106 	int lineLen;
    107 	unsigned char encData[sizeof(line) + EVP_CIPHER_block_size(EVP_aes_256_cbc())];
    108 	int encDataLen;
    109 	UINT32 encLen, i;
    110 	BYTE *encKey;
    111 	BYTE *randKey = NULL;
    112 	UINT32 sealKeyLen;
    113 	BYTE *sealKey;
    114 	TSS_FLAG keyFlags = TSS_KEY_TYPE_STORAGE | TSS_KEY_SIZE_2048 |
    115 	    TSS_KEY_VOLATILE | TSS_KEY_AUTHORIZATION |
    116 	    TSS_KEY_NOT_MIGRATABLE;
    117 	TSS_HPOLICY hSrkPolicy;
    118 	char *passwd = NULL;
    119 	int pswd_len;
    120 	BYTE wellKnown[TCPA_SHA1_160_HASH_LEN] = TSS_WELL_KNOWN_SECRET;
    121 
    122 	BIO *bin = NULL, *bdata=NULL, *b64=NULL;
    123 
    124 	initIntlSys();
    125 
    126 	if (genericOptHandler(argc, argv, "i:o:p:uz", opts,
    127 			      sizeof(opts) / sizeof(struct option), parse,
    128 			      help) != 0)
    129 		goto out;
    130 
    131 	if (contextCreate(&hContext) != TSS_SUCCESS)
    132 		goto out;
    133 
    134 	if (contextConnect(hContext) != TSS_SUCCESS)
    135 		goto out_close;
    136 
    137 	if (contextGetTpm(hContext, &hTpm) != TSS_SUCCESS)
    138 		goto out_close;
    139 
    140 	/* Create a BIO for the input file */
    141 	if ((bin = BIO_new(BIO_s_file())) == NULL) {
    142 		logError(_("Unable to open input BIO\n"));
    143 		goto out_close;
    144 	}
    145 
    146 	/* Assign the input file to the BIO */
    147 	if (strlen(in_filename) == 0)
    148 		BIO_set_fp(bin, stdin, BIO_NOCLOSE);
    149 	else if (!BIO_read_filename(bin, in_filename)) {
    150 		logError(_("Unable to open input file: %s\n"),
    151 			 in_filename);
    152 		goto out_close;
    153 	}
    154 
    155 	/* Create the PCRs object. If any PCRs above 15 are selected, this will need to be
    156 	 * a 1.2 TSS/TPM */
    157 	if (selectedPcrsLen) {
    158 		TSS_FLAG initFlag = 0;
    159 		UINT32 pcrSize;
    160 		BYTE *pcrValue;
    161 
    162 		for (i = 0; i < selectedPcrsLen; i++) {
    163 			if (selectedPcrs[i] > 15) {
    164 #ifdef TSS_LIB_IS_12
    165 				initFlag |= TSS_PCRS_STRUCT_INFO_LONG;
    166 #else
    167 				logError(_("This version of %s was compiled for a v1.1 TSS, which "
    168 					 "can only seal\n data to PCRs 0-15. PCR %u is out of range"
    169 					 "\n"), argv[0], selectedPcrs[i]);
    170 				goto out_close;
    171 #endif
    172 			}
    173 		}
    174 
    175 		if (contextCreateObject(hContext, TSS_OBJECT_TYPE_PCRS, initFlag,
    176 					&hPcrs) != TSS_SUCCESS)
    177 			goto out_close;
    178 
    179 		for (i = 0; i < selectedPcrsLen; i++) {
    180 			if (tpmPcrRead(hTpm, selectedPcrs[i], &pcrSize, &pcrValue) != TSS_SUCCESS)
    181 				goto out_close;
    182 
    183 			if (pcrcompositeSetPcrValue(hPcrs, selectedPcrs[i], pcrSize, pcrValue)
    184 					!= TSS_SUCCESS)
    185 				goto out_close;
    186 		}
    187 #ifdef TSS_LIB_IS_12
    188 		if (initFlag) {
    189 			UINT32 localityValue =
    190 				TPM_LOC_ZERO | TPM_LOC_ONE | TPM_LOC_TWO | TPM_LOC_THREE |
    191 				TPM_LOC_FOUR;
    192 
    193 			if (pcrcompositeSetPcrLocality(hPcrs, localityValue) != TSS_SUCCESS)
    194 				goto out_close;
    195 		}
    196 #endif
    197 	}
    198 
    199 	/* Retrieve random data to be used as the symmetric key
    200 	   (this key will encrypt the input file contents) */
    201 	if (tpmGetRandom(hTpm, EVP_CIPHER_key_length(EVP_aes_256_cbc()),
    202 			 &randKey) != TSS_SUCCESS)
    203 		goto out_close;
    204 
    205 	/* Load the SRK and set the SRK policy (no password) */
    206 	if (keyLoadKeyByUUID(hContext, TSS_PS_TYPE_SYSTEM, SRK_UUID, &hSrk)
    207 	    != TSS_SUCCESS)
    208 		goto out_close;
    209 
    210 	/* Use the context's default policy for the SRK secret */
    211 	if (policyGet(hSrk, &hSrkPolicy) != TSS_SUCCESS)
    212 		goto out_close;
    213 
    214 	/* Prompt for SRK password */
    215 	if (!isWellKnown) {
    216 		passwd = _GETPASSWD(_("Enter SRK password: "), (int *)&pswd_len, FALSE,
    217 				    passUnicode);
    218 		if (!passwd) {
    219 			logError(_("Failed to get SRK password\n"));
    220 			goto out_close;
    221 		}
    222 	} else {
    223 		passwd = (char *)wellKnown;
    224 		pswd_len = sizeof(wellKnown);
    225 	}
    226 
    227 	if (policySetSecret(hSrkPolicy, (UINT32)pswd_len, (BYTE *)passwd) != TSS_SUCCESS)
    228 		goto out_close;
    229 
    230 	if (!isWellKnown)
    231 		shredPasswd(passwd);
    232 	passwd = NULL;
    233 
    234 	/* Build an RSA key object that will be created by the TPM
    235 	   (this will encrypt and protect the symmetric key) */
    236 	if (contextCreateObject
    237 	    (hContext, TSS_OBJECT_TYPE_RSAKEY, keyFlags,
    238 	     &hKey) != TSS_SUCCESS)
    239 		goto out_close;
    240 
    241 	if (contextCreateObject
    242 	    (hContext, TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE,
    243 	     &hPolicy) != TSS_SUCCESS)
    244 		goto out_close;
    245 
    246 	if (policySetSecret(hPolicy, strlen(TPMSEAL_SECRET), (BYTE *)TPMSEAL_SECRET)
    247 	    != TSS_SUCCESS)
    248 		goto out_close;
    249 
    250 	if (policyAssign(hPolicy, hKey) != TSS_SUCCESS)
    251 		goto out_close;
    252 
    253 	/* Create the RSA key (under the SRK) */
    254 	if (keyCreateKey(hKey, hSrk, NULL_HPCRS) != TSS_SUCCESS)
    255 		goto out_close;
    256 
    257 	/* Load the newly created RSA key */
    258 	if (keyLoadKey(hKey, hSrk) != TSS_SUCCESS)
    259 		goto out_close;
    260 
    261 	/* Build an encrypted data object that will hold the encrypted
    262 	   version of the symmetric key */
    263 	if (contextCreateObject
    264 	    (hContext, TSS_OBJECT_TYPE_ENCDATA, TSS_ENCDATA_SEAL,
    265 	     &hEncdata) != TSS_SUCCESS)
    266 		goto out_close;
    267 
    268 	if (contextCreateObject
    269 	    (hContext, TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE,
    270 	     &hPolicy) != TSS_SUCCESS)
    271 		goto out_close;
    272 
    273 	if (policySetSecret(hPolicy, strlen(TPMSEAL_SECRET), (BYTE *)TPMSEAL_SECRET)
    274 	    != TSS_SUCCESS)
    275 		goto out_close;
    276 
    277 	if (policyAssign(hPolicy, hEncdata) != TSS_SUCCESS)
    278 		goto out_close;
    279 
    280 	/* Encrypt and seal the symmetric key */
    281 	if (dataSeal
    282 	    (hEncdata, hKey, EVP_CIPHER_key_length(EVP_aes_256_cbc()),
    283 	     randKey, hPcrs) != TSS_SUCCESS)
    284 		goto out_close;
    285 
    286 	if (getAttribData(hEncdata, TSS_TSPATTRIB_ENCDATA_BLOB,
    287 			  TSS_TSPATTRIB_ENCDATABLOB_BLOB, &encLen,
    288 			  &encKey) != TSS_SUCCESS)
    289 		goto out_close;
    290 
    291 	if (getAttribData
    292 	    (hKey, TSS_TSPATTRIB_KEY_BLOB, TSS_TSPATTRIB_KEYBLOB_BLOB,
    293 	     &sealKeyLen, &sealKey) != TSS_SUCCESS)
    294 		goto out_close;
    295 
    296 	/* Create a BIO to perform base64 encoding */
    297 	if ((b64 = BIO_new(BIO_f_base64())) == NULL) {
    298 		logError(_("Unable to open base64 BIO\n"));
    299 		goto out_close;
    300 	}
    301 
    302 	/* Create a BIO for the output file */
    303 	if ((bdata = BIO_new(BIO_s_file())) == NULL) {
    304 		logError(_("Unable to open output BIO\n"));
    305 		goto out_close;
    306 	}
    307 
    308 	/* Assign the output file to the BIO */
    309 	if (strlen(out_filename) == 0)
    310 		BIO_set_fp(bdata, stdout, BIO_NOCLOSE);
    311 	else if (BIO_write_filename(bdata, out_filename) <= 0) {
    312 		logError(_("Unable to open output file: %s\n"),
    313 			 out_filename);
    314 		goto out_close;
    315 	}
    316 
    317 	/* Output the sealed data header string */
    318 	BIO_puts(bdata, TPMSEAL_HDR_STRING);
    319 
    320 	/* Sealing key used on the TPM */
    321 	BIO_puts(bdata, TPMSEAL_TSS_STRING);
    322 	bdata = BIO_push(b64, bdata);
    323 	BIO_write(bdata, sealKey, sealKeyLen);
    324 	if (BIO_flush(bdata) != 1) {
    325 		logError(_("Unable to flush output\n"));
    326 		goto out_close;
    327 	}
    328 	bdata = BIO_pop(b64);
    329 
    330 	/* Sealed EVP Symmetric Key */
    331 	BIO_puts(bdata, TPMSEAL_EVP_STRING);
    332 	BIO_puts(bdata, TPMSEAL_KEYTYPE_SYM);
    333 	BIO_puts(bdata, TPMSEAL_CIPHER_AES256CBC);
    334 	bdata = BIO_push(b64, bdata);
    335 	BIO_write(bdata, encKey, encLen);
    336 	if (BIO_flush(bdata) != 1) {
    337 		logError(_("Unable to flush output\n"));
    338 		goto out_close;
    339 	}
    340 	bdata = BIO_pop(b64);
    341 
    342 	/* Encrypted Data */
    343 	BIO_puts(bdata, TPMSEAL_ENC_STRING);
    344 	bdata = BIO_push(b64, bdata);
    345 
    346 	EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    347 	EVP_EncryptInit(ctx, EVP_aes_256_cbc(), randKey, (unsigned char *)TPMSEAL_IV);
    348 
    349 	while ((lineLen = BIO_read(bin, line, sizeof(line))) > 0) {
    350 		EVP_EncryptUpdate(ctx, encData, &encDataLen,
    351 				  line, lineLen);
    352 		BIO_write(bdata, encData, encDataLen);
    353 	}
    354 
    355 	EVP_EncryptFinal(ctx, encData, &encDataLen);
    356 	BIO_write(bdata, encData, encDataLen);
    357 	if (BIO_flush(bdata) != 1) {
    358 		logError(_("Unable to flush output\n"));
    359 		goto out_close;
    360 	}
    361 	bdata = BIO_pop(b64);
    362 
    363 	BIO_puts( bdata, TPMSEAL_FTR_STRING);
    364 
    365 	iRc = 0;
    366 	logSuccess(argv[0]);
    367 
    368 out_close:
    369 	contextClose(hContext);
    370 
    371 out:
    372 	if (bin)
    373 		BIO_free(bin);
    374 	if (bdata)
    375 		BIO_free(bdata);
    376 	if (b64)
    377 		BIO_free(b64);
    378 	return iRc;
    379 }
    380