ia64/xen-unstable

view tools/vtpm_manager/manager/securestorage.c @ 9116:f3661f9a95dd

VTPM_Tools: Fix error when closing only vtpm, and fix restore bug when
no dmis exist

The first bug prevented the TPM tests from running successfully more
than once in a row.

Signed-off-by: Vinnie Scarlata <vincent.r.scarlata@intel.com>
author kaf24@firebug.cl.cam.ac.uk
date Fri Mar 03 10:46:06 2006 +0100 (2006-03-03)
parents 19f1f4fa7745
children 72ef14e79cc0
line source
1 // ===================================================================
2 //
3 // Copyright (c) 2005, Intel Corp.
4 // All rights reserved.
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions
8 // are met:
9 //
10 // * Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 // * Redistributions in binary form must reproduce the above
13 // copyright notice, this list of conditions and the following
14 // disclaimer in the documentation and/or other materials provided
15 // with the distribution.
16 // * Neither the name of Intel Corporation nor the names of its
17 // contributors may be used to endorse or promote products derived
18 // from this software without specific prior written permission.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31 // OF THE POSSIBILITY OF SUCH DAMAGE.
32 // ===================================================================
33 //
34 // securestorage.c
35 //
36 // Functions regarding securely storing DMI secrets.
37 //
38 // ==================================================================
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <fcntl.h>
43 #include <unistd.h>
44 #include <string.h>
46 #include "tcg.h"
47 #include "vtpm_manager.h"
48 #include "vtpmpriv.h"
49 #include "vtsp.h"
50 #include "bsg.h"
51 #include "crypto.h"
52 #include "hashtable.h"
53 #include "hashtable_itr.h"
54 #include "buffer.h"
55 #include "log.h"
57 TPM_RESULT envelope_encrypt(const buffer_t *inbuf,
58 CRYPTO_INFO *asymkey,
59 buffer_t *sealed_data) {
60 TPM_RESULT status = TPM_SUCCESS;
61 symkey_t symkey;
62 buffer_t data_cipher = NULL_BUF,
63 symkey_cipher = NULL_BUF;
65 UINT32 i;
66 struct pack_constbuf_t symkey_cipher32, data_cipher32;
68 vtpmloginfo(VTPM_LOG_VTPM_DEEP, "Enveloping Input[%d]: 0x", buffer_len(inbuf));
69 for (i=0; i< buffer_len(inbuf); i++)
70 vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", inbuf->bytes[i]);
71 vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "\n");
73 // Generate a sym key and encrypt state with it
74 TPMTRY(TPM_ENCRYPT_ERROR, Crypto_symcrypto_genkey (&symkey) );
75 TPMTRY(TPM_ENCRYPT_ERROR, Crypto_symcrypto_encrypt (&symkey, inbuf, &data_cipher) );
77 // Encrypt symmetric key
78 TPMTRYRETURN( VTSP_Bind( asymkey,
79 &symkey.key,
80 &symkey_cipher) );
82 // Create output blob: symkey_size + symkey_cipher + state_cipher_size + state_cipher
84 symkey_cipher32.size = buffer_len(&symkey_cipher);
85 symkey_cipher32.data = symkey_cipher.bytes;
87 data_cipher32.size = buffer_len(&data_cipher);
88 data_cipher32.data = data_cipher.bytes;
90 TPMTRYRETURN( buffer_init(sealed_data, 2 * sizeof(UINT32) + symkey_cipher32.size + data_cipher32.size, NULL));
92 BSG_PackList(sealed_data->bytes, 2,
93 BSG_TPM_SIZE32_DATA, &symkey_cipher32,
94 BSG_TPM_SIZE32_DATA, &data_cipher32);
96 vtpmloginfo(VTPM_LOG_VTPM, "Saved %d bytes of E(symkey) + %d bytes of E(data)\n", buffer_len(&symkey_cipher), buffer_len(&data_cipher));
98 vtpmloginfo(VTPM_LOG_VTPM_DEEP, "Enveloping Output[%d]: 0x", buffer_len(sealed_data));
99 for (i=0; i< buffer_len(sealed_data); i++)
100 vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", sealed_data->bytes[i]);
101 vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "\n");
103 goto egress;
105 abort_egress:
106 vtpmlogerror(VTPM_LOG_VTPM, "Failed to envelope encrypt\n.");
108 egress:
110 buffer_free ( &data_cipher);
111 buffer_free ( &symkey_cipher);
112 Crypto_symcrypto_freekey (&symkey);
114 return status;
115 }
117 TPM_RESULT envelope_decrypt(const long cipher_size,
118 const BYTE *cipher,
119 TCS_CONTEXT_HANDLE TCSContext,
120 TPM_HANDLE keyHandle,
121 const TPM_AUTHDATA *key_usage_auth,
122 buffer_t *unsealed_data) {
124 TPM_RESULT status = TPM_SUCCESS;
125 symkey_t symkey;
126 buffer_t data_cipher = NULL_BUF,
127 symkey_clear = NULL_BUF,
128 symkey_cipher = NULL_BUF;
129 struct pack_buf_t symkey_cipher32, data_cipher32;
130 int i;
132 memset(&symkey, 0, sizeof(symkey_t));
134 vtpmloginfo(VTPM_LOG_VTPM_DEEP, "Envelope Decrypt Input[%ld]: 0x", cipher_size);
135 for (i=0; i< cipher_size; i++)
136 vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", cipher[i]);
137 vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "\n");
139 BSG_UnpackList(cipher, 2,
140 BSG_TPM_SIZE32_DATA, &symkey_cipher32,
141 BSG_TPM_SIZE32_DATA, &data_cipher32);
143 TPMTRYRETURN( buffer_init_convert (&symkey_cipher,
144 symkey_cipher32.size,
145 symkey_cipher32.data) );
147 TPMTRYRETURN( buffer_init_convert (&data_cipher,
148 data_cipher32.size,
149 data_cipher32.data) );
151 // Decrypt Symmetric Key
152 TPMTRYRETURN( VTSP_Unbind( TCSContext,
153 keyHandle,
154 &symkey_cipher,
155 key_usage_auth,
156 &symkey_clear,
157 &(vtpm_globals->keyAuth) ) );
159 // create symmetric key using saved bits
160 Crypto_symcrypto_initkey (&symkey, &symkey_clear);
162 // Decrypt State
163 TPMTRY(TPM_DECRYPT_ERROR, Crypto_symcrypto_decrypt (&symkey, &data_cipher, unsealed_data) );
165 vtpmloginfo(VTPM_LOG_VTPM_DEEP, "Envelope Decrypte Output[%d]: 0x", buffer_len(unsealed_data));
166 for (i=0; i< buffer_len(unsealed_data); i++)
167 vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", unsealed_data->bytes[i]);
168 vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "\n");
170 goto egress;
172 abort_egress:
173 vtpmlogerror(VTPM_LOG_VTPM, "Failed to envelope decrypt data\n.");
175 egress:
176 buffer_free ( &data_cipher);
177 buffer_free ( &symkey_clear);
178 buffer_free ( &symkey_cipher);
179 Crypto_symcrypto_freekey (&symkey);
181 return status;
182 }
184 TPM_RESULT VTPM_Handle_Save_NVM(VTPM_DMI_RESOURCE *myDMI,
185 const buffer_t *inbuf,
186 buffer_t *outbuf) {
188 TPM_RESULT status = TPM_SUCCESS;
189 int fh;
190 long bytes_written;
191 buffer_t sealed_NVM;
194 vtpmloginfo(VTPM_LOG_VTPM_DEEP, "Save_NVMing[%d]: 0x\n", buffer_len(inbuf));
196 TPMTRYRETURN( envelope_encrypt(inbuf,
197 &vtpm_globals->storageKey,
198 &sealed_NVM) );
200 // Mark DMI Table so new save state info will get pushed to disk on return.
201 vtpm_globals->DMI_table_dirty = TRUE;
203 // Write sealed blob off disk from NVMLocation
204 // TODO: How to properly return from these. Do we care if we return failure
205 // after writing the file? We can't get the old one back.
206 // TODO: Backup old file and try and recover that way.
207 fh = open(myDMI->NVMLocation, O_WRONLY | O_CREAT, S_IREAD | S_IWRITE);
208 if ( (bytes_written = write(fh, sealed_NVM.bytes, buffer_len(&sealed_NVM) ) != (long) buffer_len(&sealed_NVM))) {
209 vtpmlogerror(VTPM_LOG_VTPM, "We just overwrote a DMI_NVM and failed to finish. %ld/%ld bytes.\n", bytes_written, (long)buffer_len(&sealed_NVM));
210 status = TPM_IOERROR;
211 goto abort_egress;
212 }
213 close(fh);
215 Crypto_SHA1Full (sealed_NVM.bytes, buffer_len(&sealed_NVM), (BYTE *) &myDMI->NVM_measurement);
217 goto egress;
219 abort_egress:
220 vtpmlogerror(VTPM_LOG_VTPM, "Failed to save NVM\n.");
222 egress:
223 buffer_free(&sealed_NVM);
224 return status;
225 }
228 /* inbuf = null outbuf = sealed blob size, sealed blob.*/
229 TPM_RESULT VTPM_Handle_Load_NVM(VTPM_DMI_RESOURCE *myDMI,
230 const buffer_t *inbuf,
231 buffer_t *outbuf) {
233 TPM_RESULT status = TPM_SUCCESS;
236 UINT32 sealed_NVM_size;
237 BYTE *sealed_NVM = NULL;
238 long fh_size;
239 int fh, stat_ret, i;
240 struct stat file_stat;
241 TPM_DIGEST sealedNVMHash;
243 if (myDMI->NVMLocation == NULL) {
244 vtpmlogerror(VTPM_LOG_VTPM, "Unable to load NVM because the file name NULL.\n");
245 status = TPM_AUTHFAIL;
246 goto abort_egress;
247 }
249 //Read sealed blob off disk from NVMLocation
250 fh = open(myDMI->NVMLocation, O_RDONLY);
251 stat_ret = fstat(fh, &file_stat);
252 if (stat_ret == 0)
253 fh_size = file_stat.st_size;
254 else {
255 status = TPM_IOERROR;
256 goto abort_egress;
257 }
259 sealed_NVM = (BYTE *) malloc(fh_size);
260 sealed_NVM_size = (UINT32) fh_size;
261 if (read(fh, sealed_NVM, fh_size) != fh_size) {
262 status = TPM_IOERROR;
263 goto abort_egress;
264 }
265 close(fh);
267 vtpmloginfo(VTPM_LOG_VTPM_DEEP, "Load_NVMing[%ld],\n", fh_size);
269 Crypto_SHA1Full(sealed_NVM, sealed_NVM_size, (BYTE *) &sealedNVMHash);
271 // Verify measurement of sealed blob.
272 if (memcmp(&sealedNVMHash, &myDMI->NVM_measurement, sizeof(TPM_DIGEST)) ) {
273 vtpmlogerror(VTPM_LOG_VTPM, "VTPM LoadNVM NVM measurement check failed.\n");
274 vtpmloginfo(VTPM_LOG_VTPM_DEEP, "Correct hash: ");
275 for (i=0; i< sizeof(TPM_DIGEST); i++)
276 vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", ((BYTE*)&myDMI->NVM_measurement)[i]);
277 vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "\n");
279 vtpmloginfo(VTPM_LOG_VTPM_DEEP, "Measured hash: ");
280 for (i=0; i< sizeof(TPM_DIGEST); i++)
281 vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", ((BYTE*)&sealedNVMHash)[i]);
282 vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "\n");
284 status = TPM_AUTHFAIL;
285 goto abort_egress;
286 }
288 TPMTRYRETURN( envelope_decrypt(fh_size,
289 sealed_NVM,
290 myDMI->TCSContext,
291 vtpm_globals->storageKeyHandle,
292 (const TPM_AUTHDATA*)&vtpm_globals->storage_key_usage_auth,
293 outbuf) );
294 goto egress;
296 abort_egress:
297 vtpmlogerror(VTPM_LOG_VTPM, "Failed to load NVM\n.");
299 egress:
300 free( sealed_NVM );
302 return status;
303 }
306 TPM_RESULT VTPM_SaveService(void) {
307 TPM_RESULT status=TPM_SUCCESS;
308 int fh, dmis=-1;
310 BYTE *flat_boot_key=NULL, *flat_dmis=NULL, *flat_enc=NULL;
311 buffer_t clear_flat_global=NULL_BUF, enc_flat_global=NULL_BUF;
312 UINT32 storageKeySize = buffer_len(&vtpm_globals->storageKeyWrap);
313 UINT32 bootKeySize = buffer_len(&vtpm_globals->bootKeyWrap);
314 struct pack_buf_t storage_key_pack = {storageKeySize, vtpm_globals->storageKeyWrap.bytes};
315 struct pack_buf_t boot_key_pack = {bootKeySize, vtpm_globals->bootKeyWrap.bytes};
317 struct hashtable_itr *dmi_itr;
318 VTPM_DMI_RESOURCE *dmi_res;
320 UINT32 boot_key_size, flat_dmis_size;
322 // Initially fill these with buffer sizes for each data type. Later fill
323 // in actual size, once flattened.
324 boot_key_size = sizeof(UINT32) + // bootkeysize
325 bootKeySize; // boot key
327 TPMTRYRETURN(buffer_init(&clear_flat_global, 3*sizeof(TPM_DIGEST) + // Auths
328 sizeof(UINT32) +// storagekeysize
329 storageKeySize, NULL) ); // storage key
332 flat_boot_key = (BYTE *) malloc( boot_key_size );
333 flat_enc = (BYTE *) malloc( sizeof(UINT32) );
335 boot_key_size = BSG_PackList(flat_boot_key, 1,
336 BSG_TPM_SIZE32_DATA, &boot_key_pack);
338 BSG_PackList(clear_flat_global.bytes, 3,
339 BSG_TPM_AUTHDATA, &vtpm_globals->owner_usage_auth,
340 BSG_TPM_SECRET, &vtpm_globals->storage_key_usage_auth,
341 BSG_TPM_SIZE32_DATA, &storage_key_pack);
343 TPMTRYRETURN(envelope_encrypt(&clear_flat_global,
344 &vtpm_globals->bootKey,
345 &enc_flat_global) );
347 BSG_PackConst(buffer_len(&enc_flat_global), 4, flat_enc);
349 // Per DMI values to be saved (if any exit)
350 if (hashtable_count(vtpm_globals->dmi_map) > 0) {
352 flat_dmis_size = (hashtable_count(vtpm_globals->dmi_map) - 1) * // num DMIS (-1 for Dom0)
353 (sizeof(UINT32) + 2*sizeof(TPM_DIGEST)); // Per DMI info
354 flat_dmis = (BYTE *) malloc( flat_dmis_size );
356 dmi_itr = hashtable_iterator(vtpm_globals->dmi_map);
357 do {
358 dmi_res = (VTPM_DMI_RESOURCE *) hashtable_iterator_value(dmi_itr);
359 dmis++;
361 // No need to save dmi0.
362 if (dmi_res->dmi_id == 0)
363 continue;
366 flat_dmis_size += BSG_PackList( flat_dmis + flat_dmis_size, 3,
367 BSG_TYPE_UINT32, &dmi_res->dmi_id,
368 BSG_TPM_DIGEST, &dmi_res->NVM_measurement,
369 BSG_TPM_DIGEST, &dmi_res->DMI_measurement);
371 } while (hashtable_iterator_advance(dmi_itr));
372 }
374 fh = open(STATE_FILE, O_WRONLY | O_CREAT, S_IREAD | S_IWRITE);
375 if (fh == -1) {
376 vtpmlogerror(VTPM_LOG_VTPM, "Unable to open %s file for write.\n", STATE_FILE);
377 status = TPM_IOERROR;
378 goto abort_egress;
379 }
381 if ( ( write(fh, flat_boot_key, boot_key_size) != boot_key_size ) ||
382 ( write(fh, flat_enc, sizeof(UINT32)) != sizeof(UINT32) ) ||
383 ( write(fh, enc_flat_global.bytes, buffer_len(&enc_flat_global)) != buffer_len(&enc_flat_global) ) ||
384 ( write(fh, flat_dmis, flat_dmis_size) != flat_dmis_size ) ) {
385 vtpmlogerror(VTPM_LOG_VTPM, "Failed to completely write service data.\n");
386 status = TPM_IOERROR;
387 goto abort_egress;
388 }
390 vtpm_globals->DMI_table_dirty = FALSE;
392 goto egress;
394 abort_egress:
395 egress:
397 free(flat_boot_key);
398 free(flat_enc);
399 buffer_free(&enc_flat_global);
400 free(flat_dmis);
401 close(fh);
403 vtpmloginfo(VTPM_LOG_VTPM, "Saved VTPM Service state (status = %d, dmis = %d)\n", (int) status, dmis);
404 return status;
405 }
407 TPM_RESULT VTPM_LoadService(void) {
409 TPM_RESULT status=TPM_SUCCESS;
410 int fh, stat_ret, dmis=0;
411 long fh_size = 0, step_size;
412 BYTE *flat_table=NULL;
413 buffer_t unsealed_data;
414 struct pack_buf_t storage_key_pack, boot_key_pack;
415 UINT32 *dmi_id_key, enc_size;
417 VTPM_DMI_RESOURCE *dmi_res;
418 struct stat file_stat;
420 TPM_HANDLE boot_key_handle;
421 TPM_AUTHDATA boot_usage_auth;
422 memset(&boot_usage_auth, 0, sizeof(TPM_AUTHDATA));
424 fh = open(STATE_FILE, O_RDONLY );
425 stat_ret = fstat(fh, &file_stat);
426 if (stat_ret == 0)
427 fh_size = file_stat.st_size;
428 else {
429 status = TPM_IOERROR;
430 goto abort_egress;
431 }
433 flat_table = (BYTE *) malloc(fh_size);
435 if ((long) read(fh, flat_table, fh_size) != fh_size ) {
436 status = TPM_IOERROR;
437 goto abort_egress;
438 }
440 // Read Boot Key
441 step_size = BSG_UnpackList( flat_table, 2,
442 BSG_TPM_SIZE32_DATA, &boot_key_pack,
443 BSG_TYPE_UINT32, &enc_size);
445 TPMTRYRETURN(buffer_init(&vtpm_globals->bootKeyWrap, 0, 0) );
446 TPMTRYRETURN(buffer_append_raw(&vtpm_globals->bootKeyWrap, boot_key_pack.size, boot_key_pack.data) );
448 //Load Boot Key
449 TPMTRYRETURN( VTSP_LoadKey( vtpm_globals->manager_tcs_handle,
450 TPM_SRK_KEYHANDLE,
451 &vtpm_globals->bootKeyWrap,
452 &SRK_AUTH,
453 &boot_key_handle,
454 &vtpm_globals->keyAuth,
455 &vtpm_globals->bootKey,
456 FALSE) );
458 TPMTRYRETURN( envelope_decrypt(enc_size,
459 flat_table + step_size,
460 vtpm_globals->manager_tcs_handle,
461 boot_key_handle,
462 (const TPM_AUTHDATA*) &boot_usage_auth,
463 &unsealed_data) );
464 step_size += enc_size;
466 // Global Values needing to be saved
467 BSG_UnpackList( unsealed_data.bytes, 3,
468 BSG_TPM_AUTHDATA, &vtpm_globals->owner_usage_auth,
469 BSG_TPM_SECRET, &vtpm_globals->storage_key_usage_auth,
470 BSG_TPM_SIZE32_DATA, &storage_key_pack);
472 TPMTRYRETURN(buffer_init(&vtpm_globals->storageKeyWrap, 0, 0) );
473 TPMTRYRETURN(buffer_append_raw(&vtpm_globals->storageKeyWrap, storage_key_pack.size, storage_key_pack.data) );
475 // Per DMI values to be saved
476 while ( step_size < fh_size ){
477 if (fh_size - step_size < (long) (sizeof(UINT32) + 2*sizeof(TPM_DIGEST))) {
478 vtpmlogerror(VTPM_LOG_VTPM, "Encountered %ld extra bytes at end of manager state.\n", fh_size-step_size);
479 step_size = fh_size;
480 } else {
481 dmi_res = (VTPM_DMI_RESOURCE *) malloc(sizeof(VTPM_DMI_RESOURCE));
482 dmis++;
484 dmi_res->connected = FALSE;
486 step_size += BSG_UnpackList(flat_table + step_size, 3,
487 BSG_TYPE_UINT32, &dmi_res->dmi_id,
488 BSG_TPM_DIGEST, &dmi_res->NVM_measurement,
489 BSG_TPM_DIGEST, &dmi_res->DMI_measurement);
491 // install into map
492 dmi_id_key = (UINT32 *) malloc (sizeof(UINT32));
493 *dmi_id_key = dmi_res->dmi_id;
494 if (!hashtable_insert(vtpm_globals->dmi_map, dmi_id_key, dmi_res)) {
495 status = TPM_FAIL;
496 goto abort_egress;
497 }
499 }
501 }
503 vtpmloginfo(VTPM_LOG_VTPM, "Loaded saved state (dmis = %d).\n", dmis);
504 goto egress;
506 abort_egress:
507 vtpmlogerror(VTPM_LOG_VTPM, "Failed to load service data with error = %s\n", tpm_get_error_name(status));
508 egress:
510 free(flat_table);
511 close(fh);
513 // TODO: Could be nice and evict BootKey. (Need to add EvictKey to VTSP.
515 return status;
516 }