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