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; 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