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