TPM_RESULT envelope_encrypt(const buffer_t     *inbuf,
                            CRYPTO_INFO        *asymkey,
                            buffer_t           *sealed_data) {
  TPM_RESULT status = TPM_SUCCESS;
  symkey_t    symkey;
  buffer_t    data_cipher = NULL_BUF,
              symkey_cipher = NULL_BUF;
  
  UINT32 i;
  struct pack_constbuf_t symkey_cipher32, data_cipher32;
  
  vtpmloginfo(VTPM_LOG_VTPM_DEEP, "Enveloping Input[%d]: 0x", buffer_len(inbuf));
  for (i=0; i< buffer_len(inbuf); i++)
    vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", inbuf->bytes[i]);
  vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "\n");
  
  // Generate a sym key and encrypt state with it
  TPMTRY(TPM_ENCRYPT_ERROR, Crypto_symcrypto_genkey (&symkey) );
  TPMTRY(TPM_ENCRYPT_ERROR, Crypto_symcrypto_encrypt (&symkey, inbuf, &data_cipher) );
  
  // Encrypt symmetric key
  TPMTRYRETURN( VTSP_Bind(    asymkey, 
			      &symkey.key, 
			      &symkey_cipher) );
  
  // Create output blob: symkey_size + symkey_cipher + state_cipher_size + state_cipher
  
  symkey_cipher32.size = buffer_len(&symkey_cipher);
  symkey_cipher32.data = symkey_cipher.bytes;
  
  data_cipher32.size = buffer_len(&data_cipher);
  data_cipher32.data = data_cipher.bytes;
  
  TPMTRYRETURN( buffer_init(sealed_data, 2 * sizeof(UINT32) + symkey_cipher32.size + data_cipher32.size, NULL));
  
  BSG_PackList(sealed_data->bytes, 2,
	       BSG_TPM_SIZE32_DATA, &symkey_cipher32,
	       BSG_TPM_SIZE32_DATA, &data_cipher32);

  vtpmloginfo(VTPM_LOG_VTPM, "Saved %d bytes of E(symkey) + %d bytes of E(data)\n", buffer_len(&symkey_cipher), buffer_len(&data_cipher));

  vtpmloginfo(VTPM_LOG_VTPM_DEEP, "Enveloping Output[%d]: 0x", buffer_len(sealed_data));
  for (i=0; i< buffer_len(sealed_data); i++)
    vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", sealed_data->bytes[i]);
  vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "\n");

  goto egress;

 abort_egress:
  vtpmlogerror(VTPM_LOG_VTPM, "Failed to envelope encrypt\n.");
  
 egress:
  
  buffer_free ( &data_cipher);
  buffer_free ( &symkey_cipher);
  Crypto_symcrypto_freekey (&symkey);
  
  return status;
}
Exemple #2
0
TPM_RC TPM2_disk_bind(struct disk_seal_entry *dst, void* src, unsigned int size)
{
    TPM_RESULT status = TPM_SUCCESS;

    TPMTRYRETURN(TPM2_Bind(vtpm_globals.sk_handle,
                           src,
                           size,
                           dst->sealed_data));

abort_egress:
egress:
   return status;
}
TPM_RESULT handle_vtpm_mig_step2(char *server_addr, 
                                 char *name, 
                                 UINT32 instance) {
  TPM_RESULT status, cmd_status;
  buffer_t out_param_buf=NULL_BUF, mig_key_buf=NULL_BUF, empty_buf=NULL_BUF;
  UINT32 offset; 
  struct pack_buf_t addr_data32;

  //===== Get Destination's Public Migration Key ======
  TPMTRYRETURN( vtpm_migratord_open(server_addr) );

  TPMTRYRETURN( vtpm_migratord_command(VTPM_MORD_MIG_STEP2,
                                     &out_param_buf,
                                     &cmd_status, 
                                     &mig_key_buf) ); 
  vtpm_migratord_close();

  TPMTRYRETURN(cmd_status);

  //===== Load migration key into vtpm_manager ========

  addr_data32.data = (BYTE *)server_addr;
  addr_data32.size = strlen(server_addr) + 1; // Include the null

  TPMTRYRETURN ( buffer_init ( &out_param_buf, 
                               sizeof(UINT32) + addr_data32.size +buffer_len(&mig_key_buf),
                               NULL ) ) ;

  offset =  BSG_PackList(out_param_buf.bytes, 1,
               BSG_TPM_SIZE32_DATA, &addr_data32);

  memcpy(out_param_buf.bytes + offset , mig_key_buf.bytes, buffer_len(&mig_key_buf) );

  TPMTRYRETURN ( vtpm_manager_open() );

  TPMTRYRETURN ( vtpm_manager_command(VTPM_ORD_LOAD_MIG_KEY,
                                      &out_param_buf,
                                      &cmd_status,
                                      &empty_buf) );

  vtpm_manager_close();

  TPMTRYRETURN(cmd_status);

  goto egress;

 abort_egress:
 egress:

  buffer_free(&mig_key_buf);
  buffer_free(&out_param_buf);

  return status;
}
Exemple #4
0
TPM_RC TPM2_disk_unbind(void *dst, unsigned int *size, const struct disk_seal_entry *src)
{
    TPM_RESULT status = TPM_SUCCESS;
    unsigned char buf[RSA_CIPHER_SIZE];

    memcpy(buf, src->sealed_data, RSA_CIPHER_SIZE);
    TPMTRYRETURN(TPM2_UnBind(vtpm_globals.sk_handle,
                             RSA_CIPHER_SIZE,
                             buf,
                             size,
                             dst));
abort_egress:
egress:
   return status;
}
TPM_RESULT VTPM_Handle_Save_NVM(VTPM_DMI_RESOURCE *myDMI, 
				const buffer_t *inbuf, 
				buffer_t *outbuf) {
  
  TPM_RESULT status = TPM_SUCCESS;
  int fh;
  long bytes_written;
  buffer_t sealed_NVM = NULL_BUF;
  
  vtpmloginfo(VTPM_LOG_VTPM_DEEP, "Saving %d bytes of NVM.\n", buffer_len(inbuf));

  TPMTRYRETURN( envelope_encrypt(inbuf,
                                 &vtpm_globals->storageKey,
                                 &sealed_NVM) );
				  
  // Write sealed blob off disk from NVMLocation
  // TODO: How to properly return from these. Do we care if we return failure
  //       after writing the file? We can't get the old one back.
  // TODO: Backup old file and try and recover that way.
  fh = open(myDMI->NVMLocation, O_WRONLY | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE);
  if ( (bytes_written = write(fh, sealed_NVM.bytes, buffer_len(&sealed_NVM) ) != (long) buffer_len(&sealed_NVM))) {
    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));
    status = TPM_IOERROR;
    goto abort_egress;
  }
  close(fh);
  
  Crypto_SHA1Full (sealed_NVM.bytes, buffer_len(&sealed_NVM), (BYTE *) &myDMI->NVM_measurement);   
  
  goto egress;
  
 abort_egress:
  vtpmlogerror(VTPM_LOG_VTPM, "Failed to save NVM\n.");
  
 egress:
  buffer_free(&sealed_NVM);
  return status;
}
TPM_RESULT handle_vtpm_mig_step3(char *server_addr, 
                                 char *name, 
                                 UINT32 instance) {
  TPM_RESULT status, cmd_status;
  buffer_t out_param_buf=NULL_BUF, state_buf=NULL_BUF, empty_buf=NULL_BUF;
  struct pack_buf_t addr_data32, name_data32, state_data32;

  //===== Get vtpm state from vtpm_manager ========
  addr_data32.data = (BYTE *)server_addr;
  addr_data32.size = strlen(server_addr) + 1; // Include the null

  TPMTRYRETURN ( buffer_init ( &out_param_buf,
                               (2 * sizeof(UINT32)) + addr_data32.size,
                               NULL ) ) ;

  BSG_PackList(out_param_buf.bytes, 2,
                 BSG_TYPE_UINT32, &instance, 
                 BSG_TPM_SIZE32_DATA, &addr_data32);

  TPMTRYRETURN ( vtpm_manager_open() );

  TPMTRYRETURN ( vtpm_manager_command(VTPM_ORD_MIGRATE_OUT,
                                      &out_param_buf,
                                      &cmd_status,
                                      &state_buf) );

  vtpm_manager_close();

  TPMTRYRETURN(cmd_status);

  TPMTRYRETURN( buffer_free( &out_param_buf ) );

  //===== Send vtpm state to destination ======
  name_data32.data = (BYTE *)name;
  name_data32.size = strlen(name) + 1; // Include the null
  state_data32.data = state_buf.bytes;
  state_data32.size = buffer_len(&state_buf);

  TPMTRYRETURN( buffer_init( &out_param_buf,
                             2 * sizeof(UINT32) + name_data32.size + state_data32.size,
                             NULL ) ) ;
                             
  BSG_PackList(out_param_buf.bytes, 2,
                 BSG_TPM_SIZE32_DATA, &name_data32,
                 BSG_TPM_SIZE32_DATA, &state_data32);

  TPMTRYRETURN( vtpm_migratord_open(server_addr) );

  TPMTRYRETURN( vtpm_migratord_command(VTPM_MORD_MIG_STEP3,
                                     &out_param_buf,
                                     &cmd_status, 
                                     &empty_buf) ); 
  vtpm_migratord_close();

  TPMTRYRETURN(cmd_status);

  goto egress;

 abort_egress:
 egress:

  buffer_free( &out_param_buf);
  buffer_free( &state_buf);
  buffer_free( &empty_buf);

  return status;
}
TPM_RESULT vtpm_manager_command(TPM_COMMAND_CODE ord,
                                buffer_t *command_param_buf,
                                TPM_RESULT *cmd_status, /* out */
                                buffer_t *result_param_buf) {

  TPM_RESULT status = TPM_FAIL;
  int  size_read, size_write, i;
  BYTE *adj_command, response_header[VTPM_COMMAND_HEADER_SIZE_SRV];
  UINT32 dmi_id=0, adj_command_size, out_param_size, adj_param_size;
  TPM_TAG tag=VTPM_TAG_REQ;

  if ( (!command_param_buf) || (!result_param_buf) || (!cmd_status) ) {
    status = TPM_BAD_PARAMETER;
    goto abort_egress;
  }   
  
  adj_command_size = VTPM_COMMAND_HEADER_SIZE_SRV + buffer_len(command_param_buf);
  adj_command = (BYTE *) malloc( adj_command_size );
  if (!adj_command) {
    status = TPM_RESOURCES;
    goto abort_egress;
  }

  out_param_size = VTPM_COMMAND_HEADER_SIZE + buffer_len(command_param_buf);
  BSG_PackList(adj_command, 4,
                 BSG_TYPE_UINT32, &dmi_id,
                 BSG_TPM_TAG, &tag,
                 BSG_TYPE_UINT32, &out_param_size,
                 BSG_TPM_COMMAND_CODE, &ord );

  memcpy(adj_command + VTPM_COMMAND_HEADER_SIZE_SRV, command_param_buf->bytes, buffer_len(command_param_buf));

  size_write = vtpm_ipc_write(&tx_ipc_h, NULL, adj_command, adj_command_size);

  if (size_write > 0) {
    vtpmloginfo(VTPM_LOG_VTPM_DEEP, "SENT (MGR): 0x");
    for (i=0; i< adj_command_size; i++) {
      vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", adj_command[i]);
    }
    vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "\n");
  } else {
    vtpmlogerror(VTPM_LOG_VTPM, "Error writing VTPM Manager console.\n");
    status = TPM_IOERROR;
    goto abort_egress;
  }

  if (size_write != (int) adj_command_size )
    vtpmlogerror(VTPM_LOG_VTPM, "Could not write entire command to mgr (%d/%d)\n", size_write, adj_command_size);

  // Read header for response to manager command
  size_read = vtpm_ipc_read(&rx_ipc_h, NULL, response_header, VTPM_COMMAND_HEADER_SIZE_SRV);
  if (size_read > 0) {
    vtpmloginfo(VTPM_LOG_VTPM_DEEP, "RECV (MGR): 0x");
    for (i=0; i<size_read; i++)
      vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", response_header[i]);

  } else {
    vtpmlogerror(VTPM_LOG_VTPM, "Error reading from vtpm manager.\n");
    status = TPM_IOERROR;
    goto abort_egress;
  }

  if (size_read < (int) VTPM_COMMAND_HEADER_SIZE_SRV) {
    vtpmlogerror(VTPM_LOG_VTPM, "Command from vtpm_manager shorter than std header.\n");
    status = TPM_IOERROR;
    goto abort_egress;
  }

  // Unpack response from DMI for TPM command
  BSG_UnpackList(response_header, 4,
                 BSG_TYPE_UINT32, &dmi_id,
                 BSG_TPM_TAG, &tag,
                 BSG_TYPE_UINT32, &out_param_size,
                 BSG_TPM_COMMAND_CODE, cmd_status );

  // If response has parameters, read them.
  // Note that out_param_size is in the client's context
  adj_param_size = out_param_size - VTPM_COMMAND_HEADER_SIZE;
  if (adj_param_size > 0) {
    TPMTRYRETURN( buffer_init( result_param_buf, adj_param_size, NULL) );
    size_read = vtpm_ipc_read(&rx_ipc_h, NULL, result_param_buf->bytes, adj_param_size);
    if (size_read > 0) {
      for (i=0; i< size_read; i++)
        vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", result_param_buf->bytes[i]);

    } else {
      vtpmlogerror(VTPM_LOG_VTPM, "Error reading from vtpm manager.\n");
      goto abort_egress;
    }
    vtpmloginfomore(VTPM_LOG_VTPM, "\n");

    if (size_read < (int)adj_param_size) {
      vtpmloginfomore(VTPM_LOG_VTPM, "\n");
      vtpmlogerror(VTPM_LOG_VTPM, "Command read(%d) is shorter than header indicates(%d).\n", size_read, adj_param_size);
      status = TPM_IOERROR;
      goto abort_egress;
    }
  } else {
    vtpmloginfomore(VTPM_LOG_VTPM, "\n");
  }

  status=TPM_SUCCESS;
  goto egress;

 abort_egress:
 egress:

  return status;
}
TPM_RESULT VTPM_LoadManagerData(void) {

  TPM_RESULT status=TPM_SUCCESS;
  int fh, stat_ret, dmis=0;
  long fh_size = 0, step_size;
  BYTE *flat_table=NULL;
  buffer_t  unsealed_data, enc_table_abuf;
  struct pack_buf_t storage_key_pack, boot_key_pack;
  UINT32 *dmi_id_key, enc_size;
  BYTE vtpm_manager_gen;

  VTPM_DMI_RESOURCE *dmi_res;
  UINT32 dmi_id;
  BYTE dmi_type;
  struct stat file_stat;

  TPM_HANDLE boot_key_handle;
  TPM_AUTHDATA boot_usage_auth;
  memset(&boot_usage_auth, 0, sizeof(TPM_AUTHDATA));

  fh = open(STATE_FILE, O_RDONLY );
  stat_ret = fstat(fh, &file_stat);
  if (stat_ret == 0)
    fh_size = file_stat.st_size;
  else {
    status = TPM_IOERROR;
    goto abort_egress;
  }

  flat_table = (BYTE *) malloc(fh_size);

  if ((long) read(fh, flat_table, fh_size) != fh_size ) {
    status = TPM_IOERROR;
    goto abort_egress;
  }

  // Read Boot Key
  step_size = BSG_UnpackList( flat_table, 2,
                              BSG_TPM_SIZE32_DATA, &boot_key_pack,
                              BSG_TYPE_UINT32, &enc_size);

  TPMTRYRETURN(buffer_init(&vtpm_globals->bootKeyWrap, 0, 0) );
  TPMTRYRETURN(buffer_init_alias_convert(&enc_table_abuf, enc_size, flat_table + step_size) );
  TPMTRYRETURN(buffer_append_raw(&vtpm_globals->bootKeyWrap, boot_key_pack.size, boot_key_pack.data) );

  //Load Boot Key
  TPMTRYRETURN( VTSP_LoadKey( vtpm_globals->manager_tcs_handle,
                              TPM_SRK_KEYHANDLE,
                              &vtpm_globals->bootKeyWrap,
                              &SRK_AUTH,
                              &boot_key_handle,
                              &vtpm_globals->keyAuth,
                              &vtpm_globals->bootKey,
                              FALSE) );

  TPMTRYRETURN( envelope_decrypt(&enc_table_abuf,
                                 vtpm_globals->manager_tcs_handle,
                                 boot_key_handle,
                                 (const TPM_AUTHDATA*) &boot_usage_auth,
                                 &unsealed_data) );
  step_size += enc_size;

  if (*unsealed_data.bytes != VTPM_MANAGER_GEN) {
      // Once there is more than one gen, this will include some compatability stuff
      vtpmlogerror(VTPM_LOG_VTPM, "Warning: Manager Data file is gen %d, which this manager is gen %d.\n", vtpm_manager_gen, VTPM_MANAGER_GEN);
  }

  // Global Values needing to be saved
  BSG_UnpackList( unsealed_data.bytes, 4,
                  BSG_TYPE_BYTE,    &vtpm_manager_gen, 
                  BSG_TPM_AUTHDATA, &vtpm_globals->owner_usage_auth,
                  BSG_TPM_SECRET,   &vtpm_globals->storage_key_usage_auth,
                  BSG_TPM_SIZE32_DATA, &storage_key_pack);

  TPMTRYRETURN(buffer_init(&vtpm_globals->storageKeyWrap, 0, 0) );
  TPMTRYRETURN(buffer_append_raw(&vtpm_globals->storageKeyWrap, storage_key_pack.size, storage_key_pack.data) );

  // Per DMI values to be saved
  while ( step_size < fh_size ){
    if (fh_size - step_size < (long) (sizeof(UINT32) + sizeof(BYTE) + 2*sizeof(TPM_DIGEST))) {
      vtpmlogerror(VTPM_LOG_VTPM, "Encountered %ld extra bytes at end of manager state.\n", fh_size-step_size);
      step_size = fh_size;
    } else {
      step_size += BSG_UnpackList(flat_table + step_size, 2,
                                 BSG_TYPE_UINT32, &dmi_id,
                                 BSG_TYPE_BYTE, &dmi_type);

      //TODO: Try and gracefully recover from problems.
      TPMTRYRETURN(init_dmi(dmi_id, dmi_type, &dmi_res) );
      dmis++;

      step_size += BSG_UnpackList(flat_table + step_size, 2,
                                 BSG_TPM_DIGEST, &dmi_res->NVM_measurement,
                                 BSG_TPM_DIGEST, &dmi_res->DMI_measurement);
    }

  }

  vtpmloginfo(VTPM_LOG_VTPM, "Loaded saved state (dmis = %d).\n", dmis);
  goto egress;

 abort_egress:
  vtpmlogerror(VTPM_LOG_VTPM, "Failed to load service data with error = %s\n", tpm_get_error_name(status));
 egress:

  free(flat_table);
  close(fh);

  // TODO: Could be nice and evict BootKey. (Need to add EvictKey to VTSP.

  return status;
}
TPM_RESULT VTPM_SaveManagerData(void) {
  TPM_RESULT status=TPM_SUCCESS;
  int fh, dmis=-1;

  BYTE *flat_boot_key=NULL, *flat_dmis=NULL, *flat_enc=NULL;
  buffer_t clear_flat_global=NULL_BUF, enc_flat_global=NULL_BUF;
  UINT32 storageKeySize = buffer_len(&vtpm_globals->storageKeyWrap);
  UINT32 bootKeySize = buffer_len(&vtpm_globals->bootKeyWrap);
  struct pack_buf_t storage_key_pack = {storageKeySize, vtpm_globals->storageKeyWrap.bytes};
  struct pack_buf_t boot_key_pack = {bootKeySize, vtpm_globals->bootKeyWrap.bytes};
  BYTE vtpm_manager_gen = VTPM_MANAGER_GEN;

  struct hashtable_itr *dmi_itr;
  VTPM_DMI_RESOURCE *dmi_res;

  UINT32 boot_key_size = 0, flat_dmis_size = 0;

  // Initially fill these with buffer sizes for each data type. Later fill
  // in actual size, once flattened.
  boot_key_size =  sizeof(UINT32) +       // bootkeysize
                   bootKeySize;           // boot key

  TPMTRYRETURN(buffer_init(&clear_flat_global,sizeof(BYTE) + // manager version
                                              3*sizeof(TPM_DIGEST) + // Auths
                                              sizeof(UINT32) +// storagekeysize
                                              storageKeySize, NULL) ); // storage key


  flat_boot_key = (BYTE *) malloc( boot_key_size );
  flat_enc = (BYTE *) malloc( sizeof(UINT32) );

  boot_key_size = BSG_PackList(flat_boot_key, 1,
                               BSG_TPM_SIZE32_DATA, &boot_key_pack);

  BSG_PackList(clear_flat_global.bytes, 4,
                BSG_TYPE_BYTE,    &vtpm_manager_gen,
                BSG_TPM_AUTHDATA, &vtpm_globals->owner_usage_auth,
                BSG_TPM_SECRET,   &vtpm_globals->storage_key_usage_auth,
                BSG_TPM_SIZE32_DATA, &storage_key_pack);

  TPMTRYRETURN(envelope_encrypt(&clear_flat_global,
                                &vtpm_globals->bootKey,
                                &enc_flat_global) );

  BSG_PackConst(buffer_len(&enc_flat_global), 4, flat_enc);

  // Per DMI values to be saved (if any exit)
  if (hashtable_count(vtpm_globals->dmi_map) > 1) {

    flat_dmis = (BYTE *) malloc( 
                     (hashtable_count(vtpm_globals->dmi_map) - 1) * // num DMIS (-1 for Dom0)
                     (sizeof(UINT32) +sizeof(BYTE) + 2*sizeof(TPM_DIGEST)) ); // Per DMI info

    dmi_itr = hashtable_iterator(vtpm_globals->dmi_map);
    do {
      dmi_res = (VTPM_DMI_RESOURCE *) hashtable_iterator_value(dmi_itr);
      dmis++;

      // No need to save dmi0.
      if (dmi_res->dmi_id == 0)
        continue;


      flat_dmis_size += BSG_PackList( flat_dmis + flat_dmis_size, 4,
                                        BSG_TYPE_UINT32, &dmi_res->dmi_id,
                                        BSG_TYPE_BYTE, &dmi_res->dmi_type,
                                        BSG_TPM_DIGEST, &dmi_res->NVM_measurement,
                                        BSG_TPM_DIGEST, &dmi_res->DMI_measurement);

    } while (hashtable_iterator_advance(dmi_itr));
  }

  fh = open(STATE_FILE, O_WRONLY | O_CREAT, S_IREAD | S_IWRITE);
  if (fh == -1) {
    vtpmlogerror(VTPM_LOG_VTPM, "Unable to open %s file for write.\n", STATE_FILE);
    status = TPM_IOERROR;
    goto abort_egress;
  }

  if ( ( write(fh, flat_boot_key, boot_key_size) != boot_key_size ) ||
       ( write(fh, flat_enc, sizeof(UINT32)) != sizeof(UINT32) ) ||
       ( write(fh, enc_flat_global.bytes, buffer_len(&enc_flat_global)) != buffer_len(&enc_flat_global) ) ||
       ( write(fh, flat_dmis, flat_dmis_size) != flat_dmis_size ) ) {
    vtpmlogerror(VTPM_LOG_VTPM, "Failed to completely write service data.\n");
    status = TPM_IOERROR;
    goto abort_egress;
 }

  goto egress;

 abort_egress:
 egress:

  free(flat_boot_key);
  free(flat_enc);
  buffer_free(&enc_flat_global);
  free(flat_dmis);
  close(fh);

  vtpmloginfo(VTPM_LOG_VTPM, "Saved VTPM Manager state (status = %d, dmis = %d)\n", (int) status, dmis);
  return status;
}
/* Expected Params: inbuf = null, outbuf = sealed blob size, sealed blob.*/
TPM_RESULT VTPM_Handle_Load_NVM(VTPM_DMI_RESOURCE *myDMI, 
				const buffer_t    *inbuf, 
				buffer_t          *outbuf) {
  
  TPM_RESULT status = TPM_SUCCESS;

  buffer_t sealed_NVM = NULL_BUF;
  long fh_size;
  int fh, stat_ret, i;
  struct stat file_stat;
  TPM_DIGEST sealedNVMHash;
   
  if (myDMI->NVMLocation == NULL) {
    vtpmlogerror(VTPM_LOG_VTPM, "Unable to load NVM because the file name NULL.\n");
    status = TPM_AUTHFAIL;
    goto abort_egress;
  }
  
  //Read sealed blob off disk from NVMLocation
  fh = open(myDMI->NVMLocation, O_RDONLY);
  stat_ret = fstat(fh, &file_stat);
  if (stat_ret == 0) 
    fh_size = file_stat.st_size;
  else {
    status = TPM_IOERROR;
    goto abort_egress;
  }
  
  TPMTRYRETURN( buffer_init( &sealed_NVM, fh_size, NULL) );
  if (read(fh, sealed_NVM.bytes, buffer_len(&sealed_NVM)) != fh_size) {
    status = TPM_IOERROR;
    goto abort_egress;
  }
  close(fh);
  
  vtpmloginfo(VTPM_LOG_VTPM_DEEP, "Load_NVMing[%d],\n", buffer_len(&sealed_NVM));
  
  Crypto_SHA1Full(sealed_NVM.bytes, buffer_len(&sealed_NVM), (BYTE *) &sealedNVMHash);    
  
  // Verify measurement of sealed blob.
  if (memcmp(&sealedNVMHash, &myDMI->NVM_measurement, sizeof(TPM_DIGEST)) ) {
    vtpmlogerror(VTPM_LOG_VTPM, "VTPM LoadNVM NVM measurement check failed.\n");
    vtpmloginfo(VTPM_LOG_VTPM_DEEP, "Correct hash: ");
    for (i=0; i< sizeof(TPM_DIGEST); i++)
      vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", ((BYTE*)&myDMI->NVM_measurement)[i]);
    vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "\n");

    vtpmloginfo(VTPM_LOG_VTPM_DEEP, "Measured hash: ");
    for (i=0; i< sizeof(TPM_DIGEST); i++)
      vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", ((BYTE*)&sealedNVMHash)[i]);
    vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "\n");
    
    status = TPM_AUTHFAIL;
    goto abort_egress;
  }
  
  TPMTRYRETURN( envelope_decrypt(&sealed_NVM,
                                 myDMI->TCSContext,
		        	 vtpm_globals->storageKeyHandle,
			         (const TPM_AUTHDATA*)&vtpm_globals->storage_key_usage_auth,
                                 outbuf) );  
  goto egress;
  
 abort_egress:
  vtpmlogerror(VTPM_LOG_VTPM, "Failed to load NVM\n.");
  
 egress:
  buffer_free( &sealed_NVM );
  
  return status;
}
TPM_RESULT envelope_decrypt(const buffer_t     *cipher,
                            TCS_CONTEXT_HANDLE TCSContext,
			    TPM_HANDLE         keyHandle,
			    const TPM_AUTHDATA *key_usage_auth,
                            buffer_t           *unsealed_data) {

  TPM_RESULT status = TPM_SUCCESS;
  symkey_t    symkey;
  buffer_t    data_cipher = NULL_BUF, 
              symkey_clear = NULL_BUF, 
              symkey_cipher = NULL_BUF;
  struct pack_buf_t symkey_cipher32, data_cipher32;
  int i;

  memset(&symkey, 0, sizeof(symkey_t));

  vtpmloginfo(VTPM_LOG_VTPM_DEEP, "Envelope Decrypt Input[%d]: 0x", buffer_len(cipher) );
  for (i=0; i< buffer_len(cipher); i++)
    vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", cipher->bytes[i]);
  vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "\n");
  
  BSG_UnpackList(cipher->bytes, 2,
		 BSG_TPM_SIZE32_DATA, &symkey_cipher32,
		 BSG_TPM_SIZE32_DATA, &data_cipher32);
  
  TPMTRYRETURN( buffer_init_alias_convert (&symkey_cipher, 
				           symkey_cipher32.size, 
				           symkey_cipher32.data) );
  
  TPMTRYRETURN( buffer_init_alias_convert (&data_cipher, 
				           data_cipher32.size, 
				           data_cipher32.data) );

  // Decrypt Symmetric Key
  TPMTRYRETURN( VTSP_Unbind(  TCSContext,
			      keyHandle,
			      &symkey_cipher,
			      key_usage_auth,
			      &symkey_clear,
			      &(vtpm_globals->keyAuth) ) );
  
  // create symmetric key using saved bits
  Crypto_symcrypto_initkey (&symkey, &symkey_clear);
  
  // Decrypt State
  TPMTRY(TPM_DECRYPT_ERROR, Crypto_symcrypto_decrypt (&symkey, &data_cipher, unsealed_data) );

  vtpmloginfo(VTPM_LOG_VTPM_DEEP, "Envelope Decrypte Output[%d]: 0x", buffer_len(unsealed_data));
  for (i=0; i< buffer_len(unsealed_data); i++)
    vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", unsealed_data->bytes[i]);
  vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "\n");
  
  goto egress;
  
 abort_egress:
  vtpmlogerror(VTPM_LOG_VTPM, "Failed to envelope decrypt data\n.");
  
 egress:
  buffer_free ( &data_cipher);
  buffer_free ( &symkey_clear);
  buffer_free ( &symkey_cipher);
  Crypto_symcrypto_freekey (&symkey);
  
  return status;
}
TPM_RESULT vtpm_migratord_command(TPM_COMMAND_CODE ord,
                                buffer_t *command_param_buf,
                                TPM_RESULT *cmd_status, /* out */
                                buffer_t *result_param_buf) {

  TPM_RESULT status = TPM_FAIL;
  int  size_read, size_write, i;
  BYTE *command, response_header[VTPM_COMMAND_HEADER_SIZE];
  UINT32 dmi_id=0, command_size, out_param_size, adj_param_size;
  TPM_TAG tag=VTPM_MTAG_REQ;

  if ( (!command_param_buf) || (!result_param_buf) || (!cmd_status) ) {
    status = TPM_BAD_PARAMETER;
    goto abort_egress;
  }   
  
  command_size = VTPM_COMMAND_HEADER_SIZE + buffer_len(command_param_buf);
  command = (BYTE *) malloc( command_size );
  if (!command) {
    status = TPM_RESOURCES;
    goto abort_egress;
  }

  BSG_PackList(command, 3,
                 BSG_TPM_TAG, &tag,
                 BSG_TYPE_UINT32, &command_size,
                 BSG_TPM_COMMAND_CODE, &ord );

  memcpy(command + VTPM_COMMAND_HEADER_SIZE, command_param_buf->bytes, buffer_len(command_param_buf));

  size_write = write(sock_desc, command, command_size);

  if (size_write > 0) {
    vtpmloginfo(VTPM_LOG_VTPM_DEEP, "SENT (MIGd): 0x");
    for (i=0; i< command_size; i++) {
      vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", command[i]);
    }
    vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "\n");
  } else {
    vtpmlogerror(VTPM_LOG_VTPM, "Error writing to migration server via network.\n");
    status = TPM_IOERROR;
    goto abort_egress;
  }

  if (size_write != (int) command_size )
    vtpmlogerror(VTPM_LOG_VTPM, "Could not write entire command to migration server (%d/%d)\n", size_write, command_size);

  // Read header for response 
  size_read = read(sock_desc, response_header, VTPM_COMMAND_HEADER_SIZE);
  if (size_read > 0) {
    vtpmloginfo(VTPM_LOG_VTPM_DEEP, "RECV (MIGd): 0x");
    for (i=0; i<size_read; i++)
      vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", response_header[i]);

  } else {
    vtpmlogerror(VTPM_LOG_VTPM, "Error reading from Migration Server.\n");
    status = TPM_IOERROR;
    goto abort_egress;
  }

  if (size_read < (int) VTPM_COMMAND_HEADER_SIZE) {
    vtpmlogerror(VTPM_LOG_VTPM, "Command from migration server shorter than std header.\n");
    status = TPM_IOERROR;
    goto abort_egress;
  }

  // Unpack response from DMI for TPM command
  BSG_UnpackList(response_header, 3,
                 BSG_TPM_TAG, &tag,
                 BSG_TYPE_UINT32, &out_param_size,
                 BSG_TPM_COMMAND_CODE, cmd_status );

  // If response has parameters, read them.
  adj_param_size = out_param_size - VTPM_COMMAND_HEADER_SIZE;
  if (adj_param_size > 0) {
    TPMTRYRETURN( buffer_init( result_param_buf, adj_param_size, NULL) );
    size_read = read(sock_desc, result_param_buf->bytes, adj_param_size);
    if (size_read > 0) {
      for (i=0; i< size_read; i++)
        vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", result_param_buf->bytes[i]);

    } else {
      vtpmlogerror(VTPM_LOG_VTPM, "Error reading from migration server.\n");
      goto abort_egress;
    }
    vtpmloginfomore(VTPM_LOG_VTPM, "\n");

    if (size_read < (int)adj_param_size) {
      vtpmloginfomore(VTPM_LOG_VTPM, "\n");
      vtpmlogerror(VTPM_LOG_VTPM, "Command read(%d) is shorter than header indicates(%d).\n", size_read, adj_param_size);
      status = TPM_IOERROR;
      goto abort_egress;
    }
  } else {
    vtpmloginfomore(VTPM_LOG_VTPM, "\n");
  }

  status=TPM_SUCCESS;
  goto egress;

 abort_egress:
 egress:

  return status;
}