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 
help(const char * aCmd)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 
parse(const int aOpt,const char * aArg)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 
main(int argc,char ** argv)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