ia64/xen-unstable

view tools/vtpm_manager/manager/securestorage.c @ 8977:f84d5cdd9895

Clean up segment selector fixup and validation.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Thu Feb 23 14:43:45 2006 +0100 (2006-02-23)
parents 19f1f4fa7745
children f3661f9a95dd
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, *flat_dmis, *flat_enc;
311 buffer_t clear_flat_global, enc_flat_global;
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
331 flat_dmis_size = (hashtable_count(vtpm_globals->dmi_map) - 1) * // num DMIS (-1 for Dom0)
332 (sizeof(UINT32) + 2*sizeof(TPM_DIGEST)); // Per DMI info
334 flat_boot_key = (BYTE *) malloc( boot_key_size );
335 flat_enc = (BYTE *) malloc( sizeof(UINT32) );
336 flat_dmis = (BYTE *) malloc( flat_dmis_size );
338 boot_key_size = BSG_PackList(flat_boot_key, 1,
339 BSG_TPM_SIZE32_DATA, &boot_key_pack);
341 BSG_PackList(clear_flat_global.bytes, 3,
342 BSG_TPM_AUTHDATA, &vtpm_globals->owner_usage_auth,
343 BSG_TPM_SECRET, &vtpm_globals->storage_key_usage_auth,
344 BSG_TPM_SIZE32_DATA, &storage_key_pack);
346 TPMTRYRETURN(envelope_encrypt(&clear_flat_global,
347 &vtpm_globals->bootKey,
348 &enc_flat_global) );
350 BSG_PackConst(buffer_len(&enc_flat_global), 4, flat_enc);
352 // Per DMI values to be saved
353 if (hashtable_count(vtpm_globals->dmi_map) > 0) {
355 dmi_itr = hashtable_iterator(vtpm_globals->dmi_map);
356 do {
357 dmi_res = (VTPM_DMI_RESOURCE *) hashtable_iterator_value(dmi_itr);
358 dmis++;
360 // No need to save dmi0.
361 if (dmi_res->dmi_id == 0)
362 continue;
365 flat_dmis_size += BSG_PackList( flat_dmis + flat_dmis_size, 3,
366 BSG_TYPE_UINT32, &dmi_res->dmi_id,
367 BSG_TPM_DIGEST, &dmi_res->NVM_measurement,
368 BSG_TPM_DIGEST, &dmi_res->DMI_measurement);
370 } while (hashtable_iterator_advance(dmi_itr));
371 }
373 fh = open(STATE_FILE, O_WRONLY | O_CREAT, S_IREAD | S_IWRITE);
374 if (fh == -1) {
375 vtpmlogerror(VTPM_LOG_VTPM, "Unable to open %s file for write.\n", STATE_FILE);
376 status = TPM_IOERROR;
377 goto abort_egress;
378 }
380 if ( ( write(fh, flat_boot_key, boot_key_size) != boot_key_size ) ||
381 ( write(fh, flat_enc, sizeof(UINT32)) != sizeof(UINT32) ) ||
382 ( write(fh, enc_flat_global.bytes, buffer_len(&enc_flat_global)) != buffer_len(&enc_flat_global) ) ||
383 ( write(fh, flat_dmis, flat_dmis_size) != flat_dmis_size ) ) {
384 vtpmlogerror(VTPM_LOG_VTPM, "Failed to completely write service data.\n");
385 status = TPM_IOERROR;
386 goto abort_egress;
387 }
389 vtpm_globals->DMI_table_dirty = FALSE;
391 goto egress;
393 abort_egress:
394 egress:
396 free(flat_boot_key);
397 free(flat_enc);
398 buffer_free(&enc_flat_global);
399 free(flat_dmis);
400 close(fh);
402 vtpmloginfo(VTPM_LOG_VTPM, "Saved VTPM Service state (status = %d, dmis = %d)\n", (int) status, dmis);
403 return status;
404 }
406 TPM_RESULT VTPM_LoadService(void) {
408 TPM_RESULT status=TPM_SUCCESS;
409 int fh, stat_ret, dmis=0;
410 long fh_size = 0, step_size;
411 BYTE *flat_table=NULL;
412 buffer_t unsealed_data;
413 struct pack_buf_t storage_key_pack, boot_key_pack;
414 UINT32 *dmi_id_key, enc_size;
416 VTPM_DMI_RESOURCE *dmi_res;
417 struct stat file_stat;
419 TPM_HANDLE boot_key_handle;
420 TPM_AUTHDATA boot_usage_auth;
421 memset(&boot_usage_auth, 0, sizeof(TPM_AUTHDATA));
423 fh = open(STATE_FILE, O_RDONLY );
424 stat_ret = fstat(fh, &file_stat);
425 if (stat_ret == 0)
426 fh_size = file_stat.st_size;
427 else {
428 status = TPM_IOERROR;
429 goto abort_egress;
430 }
432 flat_table = (BYTE *) malloc(fh_size);
434 if ((long) read(fh, flat_table, fh_size) != fh_size ) {
435 status = TPM_IOERROR;
436 goto abort_egress;
437 }
439 // Read Boot Key
440 step_size = BSG_UnpackList( flat_table, 2,
441 BSG_TPM_SIZE32_DATA, &boot_key_pack,
442 BSG_TYPE_UINT32, &enc_size);
444 TPMTRYRETURN(buffer_init(&vtpm_globals->bootKeyWrap, 0, 0) );
445 TPMTRYRETURN(buffer_append_raw(&vtpm_globals->bootKeyWrap, boot_key_pack.size, boot_key_pack.data) );
447 //Load Boot Key
448 TPMTRYRETURN( VTSP_LoadKey( vtpm_globals->manager_tcs_handle,
449 TPM_SRK_KEYHANDLE,
450 &vtpm_globals->bootKeyWrap,
451 &SRK_AUTH,
452 &boot_key_handle,
453 &vtpm_globals->keyAuth,
454 &vtpm_globals->bootKey,
455 FALSE) );
457 TPMTRYRETURN( envelope_decrypt(enc_size,
458 flat_table + step_size,
459 vtpm_globals->manager_tcs_handle,
460 boot_key_handle,
461 (const TPM_AUTHDATA*) &boot_usage_auth,
462 &unsealed_data) );
463 step_size += enc_size;
465 // Global Values needing to be saved
466 BSG_UnpackList( unsealed_data.bytes, 3,
467 BSG_TPM_AUTHDATA, &vtpm_globals->owner_usage_auth,
468 BSG_TPM_SECRET, &vtpm_globals->storage_key_usage_auth,
469 BSG_TPM_SIZE32_DATA, &storage_key_pack);
471 TPMTRYRETURN(buffer_init(&vtpm_globals->storageKeyWrap, 0, 0) );
472 TPMTRYRETURN(buffer_append_raw(&vtpm_globals->storageKeyWrap, storage_key_pack.size, storage_key_pack.data) );
474 // Per DMI values to be saved
475 while ( step_size < fh_size ){
476 if (fh_size - step_size < (long) (sizeof(UINT32) + 2*sizeof(TPM_DIGEST))) {
477 vtpmlogerror(VTPM_LOG_VTPM, "Encountered %ld extra bytes at end of manager state.\n", fh_size-step_size);
478 step_size = fh_size;
479 } else {
480 dmi_res = (VTPM_DMI_RESOURCE *) malloc(sizeof(VTPM_DMI_RESOURCE));
481 dmis++;
483 dmi_res->connected = FALSE;
485 step_size += BSG_UnpackList(flat_table + step_size, 3,
486 BSG_TYPE_UINT32, &dmi_res->dmi_id,
487 BSG_TPM_DIGEST, &dmi_res->NVM_measurement,
488 BSG_TPM_DIGEST, &dmi_res->DMI_measurement);
490 // install into map
491 dmi_id_key = (UINT32 *) malloc (sizeof(UINT32));
492 *dmi_id_key = dmi_res->dmi_id;
493 if (!hashtable_insert(vtpm_globals->dmi_map, dmi_id_key, dmi_res)) {
494 status = TPM_FAIL;
495 goto abort_egress;
496 }
498 }
500 }
502 vtpmloginfo(VTPM_LOG_VTPM, "Loaded saved state (dmis = %d).\n", dmis);
503 goto egress;
505 abort_egress:
506 vtpmlogerror(VTPM_LOG_VTPM, "Failed to load service data with error = %s\n", tpm_get_error_name(status));
507 egress:
509 free(flat_table);
510 close(fh);
512 // TODO: Could be nice and evict BootKey. (Need to add EvictKey to VTSP.
514 return status;
515 }