普通文本  |  33227行  |  1.1 MB

//
// Copyright (C) 2015 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

// THIS CODE IS GENERATED - DO NOT MODIFY!

#include "trunks/tpm_generated.h"

#include <memory>
#include <string>

#include <base/bind.h>
#include <base/callback.h>
#include <base/logging.h>
#include <base/macros.h>
#include <base/stl_util.h>
#include <base/strings/string_number_conversions.h>
#include <base/sys_byteorder.h>
#include <crypto/secure_hash.h>

#include "trunks/authorization_delegate.h"
#include "trunks/command_transceiver.h"
#include "trunks/error_codes.h"

namespace trunks {

size_t GetNumberOfRequestHandles(TPM_CC command_code) {
  switch (command_code) {
    case TPM_CC_Startup:
      return 0;
    case TPM_CC_Shutdown:
      return 0;
    case TPM_CC_SelfTest:
      return 0;
    case TPM_CC_IncrementalSelfTest:
      return 0;
    case TPM_CC_GetTestResult:
      return 0;
    case TPM_CC_StartAuthSession:
      return 2;
    case TPM_CC_PolicyRestart:
      return 1;
    case TPM_CC_Create:
      return 1;
    case TPM_CC_Load:
      return 1;
    case TPM_CC_LoadExternal:
      return 0;
    case TPM_CC_ReadPublic:
      return 1;
    case TPM_CC_ActivateCredential:
      return 2;
    case TPM_CC_MakeCredential:
      return 1;
    case TPM_CC_Unseal:
      return 1;
    case TPM_CC_ObjectChangeAuth:
      return 2;
    case TPM_CC_Duplicate:
      return 2;
    case TPM_CC_Rewrap:
      return 2;
    case TPM_CC_Import:
      return 1;
    case TPM_CC_RSA_Encrypt:
      return 1;
    case TPM_CC_RSA_Decrypt:
      return 1;
    case TPM_CC_ECDH_KeyGen:
      return 1;
    case TPM_CC_ECDH_ZGen:
      return 1;
    case TPM_CC_ECC_Parameters:
      return 0;
    case TPM_CC_ZGen_2Phase:
      return 1;
    case TPM_CC_EncryptDecrypt:
      return 1;
    case TPM_CC_Hash:
      return 0;
    case TPM_CC_HMAC:
      return 1;
    case TPM_CC_GetRandom:
      return 0;
    case TPM_CC_StirRandom:
      return 0;
    case TPM_CC_HMAC_Start:
      return 1;
    case TPM_CC_HashSequenceStart:
      return 0;
    case TPM_CC_SequenceUpdate:
      return 1;
    case TPM_CC_SequenceComplete:
      return 1;
    case TPM_CC_EventSequenceComplete:
      return 2;
    case TPM_CC_Certify:
      return 2;
    case TPM_CC_CertifyCreation:
      return 2;
    case TPM_CC_Quote:
      return 1;
    case TPM_CC_GetSessionAuditDigest:
      return 3;
    case TPM_CC_GetCommandAuditDigest:
      return 2;
    case TPM_CC_GetTime:
      return 2;
    case TPM_CC_Commit:
      return 1;
    case TPM_CC_EC_Ephemeral:
      return 0;
    case TPM_CC_VerifySignature:
      return 1;
    case TPM_CC_Sign:
      return 1;
    case TPM_CC_SetCommandCodeAuditStatus:
      return 1;
    case TPM_CC_PCR_Extend:
      return 1;
    case TPM_CC_PCR_Event:
      return 1;
    case TPM_CC_PCR_Read:
      return 0;
    case TPM_CC_PCR_Allocate:
      return 1;
    case TPM_CC_PCR_SetAuthPolicy:
      return 2;
    case TPM_CC_PCR_SetAuthValue:
      return 1;
    case TPM_CC_PCR_Reset:
      return 1;
    case TPM_CC_PolicySigned:
      return 2;
    case TPM_CC_PolicySecret:
      return 2;
    case TPM_CC_PolicyTicket:
      return 1;
    case TPM_CC_PolicyOR:
      return 1;
    case TPM_CC_PolicyPCR:
      return 1;
    case TPM_CC_PolicyLocality:
      return 1;
    case TPM_CC_PolicyNV:
      return 3;
    case TPM_CC_PolicyCounterTimer:
      return 1;
    case TPM_CC_PolicyCommandCode:
      return 1;
    case TPM_CC_PolicyPhysicalPresence:
      return 1;
    case TPM_CC_PolicyCpHash:
      return 1;
    case TPM_CC_PolicyNameHash:
      return 1;
    case TPM_CC_PolicyDuplicationSelect:
      return 1;
    case TPM_CC_PolicyAuthorize:
      return 1;
    case TPM_CC_PolicyAuthValue:
      return 1;
    case TPM_CC_PolicyPassword:
      return 1;
    case TPM_CC_PolicyGetDigest:
      return 1;
    case TPM_CC_PolicyNvWritten:
      return 1;
    case TPM_CC_CreatePrimary:
      return 1;
    case TPM_CC_HierarchyControl:
      return 1;
    case TPM_CC_SetPrimaryPolicy:
      return 1;
    case TPM_CC_ChangePPS:
      return 1;
    case TPM_CC_ChangeEPS:
      return 1;
    case TPM_CC_Clear:
      return 1;
    case TPM_CC_ClearControl:
      return 1;
    case TPM_CC_HierarchyChangeAuth:
      return 1;
    case TPM_CC_DictionaryAttackLockReset:
      return 1;
    case TPM_CC_DictionaryAttackParameters:
      return 1;
    case TPM_CC_PP_Commands:
      return 1;
    case TPM_CC_SetAlgorithmSet:
      return 1;
    case TPM_CC_FieldUpgradeStart:
      return 2;
    case TPM_CC_FieldUpgradeData:
      return 0;
    case TPM_CC_FirmwareRead:
      return 0;
    case TPM_CC_ContextSave:
      return 1;
    case TPM_CC_ContextLoad:
      return 0;
    case TPM_CC_FlushContext:
      return 0;
    case TPM_CC_EvictControl:
      return 2;
    case TPM_CC_ReadClock:
      return 0;
    case TPM_CC_ClockSet:
      return 1;
    case TPM_CC_ClockRateAdjust:
      return 1;
    case TPM_CC_GetCapability:
      return 0;
    case TPM_CC_TestParms:
      return 0;
    case TPM_CC_NV_DefineSpace:
      return 1;
    case TPM_CC_NV_UndefineSpace:
      return 2;
    case TPM_CC_NV_UndefineSpaceSpecial:
      return 2;
    case TPM_CC_NV_ReadPublic:
      return 1;
    case TPM_CC_NV_Write:
      return 2;
    case TPM_CC_NV_Increment:
      return 2;
    case TPM_CC_NV_Extend:
      return 2;
    case TPM_CC_NV_SetBits:
      return 2;
    case TPM_CC_NV_WriteLock:
      return 2;
    case TPM_CC_NV_GlobalWriteLock:
      return 1;
    case TPM_CC_NV_Read:
      return 2;
    case TPM_CC_NV_ReadLock:
      return 2;
    case TPM_CC_NV_ChangeAuth:
      return 1;
    case TPM_CC_NV_Certify:
      return 3;
    default:
      LOG(WARNING) << "Unknown command code: " << command_code;
  }
  return 0;
}

size_t GetNumberOfResponseHandles(TPM_CC command_code) {
  switch (command_code) {
    case TPM_CC_Startup:
      return 0;
    case TPM_CC_Shutdown:
      return 0;
    case TPM_CC_SelfTest:
      return 0;
    case TPM_CC_IncrementalSelfTest:
      return 0;
    case TPM_CC_GetTestResult:
      return 0;
    case TPM_CC_StartAuthSession:
      return 1;
    case TPM_CC_PolicyRestart:
      return 0;
    case TPM_CC_Create:
      return 0;
    case TPM_CC_Load:
      return 1;
    case TPM_CC_LoadExternal:
      return 1;
    case TPM_CC_ReadPublic:
      return 0;
    case TPM_CC_ActivateCredential:
      return 0;
    case TPM_CC_MakeCredential:
      return 0;
    case TPM_CC_Unseal:
      return 0;
    case TPM_CC_ObjectChangeAuth:
      return 0;
    case TPM_CC_Duplicate:
      return 0;
    case TPM_CC_Rewrap:
      return 0;
    case TPM_CC_Import:
      return 0;
    case TPM_CC_RSA_Encrypt:
      return 0;
    case TPM_CC_RSA_Decrypt:
      return 0;
    case TPM_CC_ECDH_KeyGen:
      return 0;
    case TPM_CC_ECDH_ZGen:
      return 0;
    case TPM_CC_ECC_Parameters:
      return 0;
    case TPM_CC_ZGen_2Phase:
      return 0;
    case TPM_CC_EncryptDecrypt:
      return 0;
    case TPM_CC_Hash:
      return 0;
    case TPM_CC_HMAC:
      return 0;
    case TPM_CC_GetRandom:
      return 0;
    case TPM_CC_StirRandom:
      return 0;
    case TPM_CC_HMAC_Start:
      return 1;
    case TPM_CC_HashSequenceStart:
      return 1;
    case TPM_CC_SequenceUpdate:
      return 0;
    case TPM_CC_SequenceComplete:
      return 0;
    case TPM_CC_EventSequenceComplete:
      return 0;
    case TPM_CC_Certify:
      return 0;
    case TPM_CC_CertifyCreation:
      return 0;
    case TPM_CC_Quote:
      return 0;
    case TPM_CC_GetSessionAuditDigest:
      return 0;
    case TPM_CC_GetCommandAuditDigest:
      return 0;
    case TPM_CC_GetTime:
      return 0;
    case TPM_CC_Commit:
      return 0;
    case TPM_CC_EC_Ephemeral:
      return 0;
    case TPM_CC_VerifySignature:
      return 0;
    case TPM_CC_Sign:
      return 0;
    case TPM_CC_SetCommandCodeAuditStatus:
      return 0;
    case TPM_CC_PCR_Extend:
      return 0;
    case TPM_CC_PCR_Event:
      return 0;
    case TPM_CC_PCR_Read:
      return 0;
    case TPM_CC_PCR_Allocate:
      return 0;
    case TPM_CC_PCR_SetAuthPolicy:
      return 0;
    case TPM_CC_PCR_SetAuthValue:
      return 0;
    case TPM_CC_PCR_Reset:
      return 0;
    case TPM_CC_PolicySigned:
      return 0;
    case TPM_CC_PolicySecret:
      return 0;
    case TPM_CC_PolicyTicket:
      return 0;
    case TPM_CC_PolicyOR:
      return 0;
    case TPM_CC_PolicyPCR:
      return 0;
    case TPM_CC_PolicyLocality:
      return 0;
    case TPM_CC_PolicyNV:
      return 0;
    case TPM_CC_PolicyCounterTimer:
      return 0;
    case TPM_CC_PolicyCommandCode:
      return 0;
    case TPM_CC_PolicyPhysicalPresence:
      return 0;
    case TPM_CC_PolicyCpHash:
      return 0;
    case TPM_CC_PolicyNameHash:
      return 0;
    case TPM_CC_PolicyDuplicationSelect:
      return 0;
    case TPM_CC_PolicyAuthorize:
      return 0;
    case TPM_CC_PolicyAuthValue:
      return 0;
    case TPM_CC_PolicyPassword:
      return 0;
    case TPM_CC_PolicyGetDigest:
      return 0;
    case TPM_CC_PolicyNvWritten:
      return 0;
    case TPM_CC_CreatePrimary:
      return 1;
    case TPM_CC_HierarchyControl:
      return 0;
    case TPM_CC_SetPrimaryPolicy:
      return 0;
    case TPM_CC_ChangePPS:
      return 0;
    case TPM_CC_ChangeEPS:
      return 0;
    case TPM_CC_Clear:
      return 0;
    case TPM_CC_ClearControl:
      return 0;
    case TPM_CC_HierarchyChangeAuth:
      return 0;
    case TPM_CC_DictionaryAttackLockReset:
      return 0;
    case TPM_CC_DictionaryAttackParameters:
      return 0;
    case TPM_CC_PP_Commands:
      return 0;
    case TPM_CC_SetAlgorithmSet:
      return 0;
    case TPM_CC_FieldUpgradeStart:
      return 0;
    case TPM_CC_FieldUpgradeData:
      return 0;
    case TPM_CC_FirmwareRead:
      return 0;
    case TPM_CC_ContextSave:
      return 0;
    case TPM_CC_ContextLoad:
      return 1;
    case TPM_CC_FlushContext:
      return 0;
    case TPM_CC_EvictControl:
      return 0;
    case TPM_CC_ReadClock:
      return 0;
    case TPM_CC_ClockSet:
      return 0;
    case TPM_CC_ClockRateAdjust:
      return 0;
    case TPM_CC_GetCapability:
      return 0;
    case TPM_CC_TestParms:
      return 0;
    case TPM_CC_NV_DefineSpace:
      return 0;
    case TPM_CC_NV_UndefineSpace:
      return 0;
    case TPM_CC_NV_UndefineSpaceSpecial:
      return 0;
    case TPM_CC_NV_ReadPublic:
      return 0;
    case TPM_CC_NV_Write:
      return 0;
    case TPM_CC_NV_Increment:
      return 0;
    case TPM_CC_NV_Extend:
      return 0;
    case TPM_CC_NV_SetBits:
      return 0;
    case TPM_CC_NV_WriteLock:
      return 0;
    case TPM_CC_NV_GlobalWriteLock:
      return 0;
    case TPM_CC_NV_Read:
      return 0;
    case TPM_CC_NV_ReadLock:
      return 0;
    case TPM_CC_NV_ChangeAuth:
      return 0;
    case TPM_CC_NV_Certify:
      return 0;
    default:
      LOG(WARNING) << "Unknown command code: " << command_code;
  }
  return 0;
}

TPM_RC Serialize_uint8_t(const uint8_t& value, std::string* buffer) {
  VLOG(3) << __func__;
  uint8_t value_net = value;
  switch (sizeof(uint8_t)) {
    case 2:
      value_net = base::HostToNet16(value);
      break;
    case 4:
      value_net = base::HostToNet32(value);
      break;
    case 8:
      value_net = base::HostToNet64(value);
      break;
    default:
      break;
  }
  const char* value_bytes = reinterpret_cast<const char*>(&value_net);
  buffer->append(value_bytes, sizeof(uint8_t));
  return TPM_RC_SUCCESS;
}

TPM_RC Parse_uint8_t(std::string* buffer,
                     uint8_t* value,
                     std::string* value_bytes) {
  VLOG(3) << __func__;
  if (buffer->size() < sizeof(uint8_t))
    return TPM_RC_INSUFFICIENT;
  uint8_t value_net = 0;
  memcpy(&value_net, buffer->data(), sizeof(uint8_t));
  switch (sizeof(uint8_t)) {
    case 2:
      *value = base::NetToHost16(value_net);
      break;
    case 4:
      *value = base::NetToHost32(value_net);
      break;
    case 8:
      *value = base::NetToHost64(value_net);
      break;
    default:
      *value = value_net;
  }
  if (value_bytes) {
    value_bytes->append(buffer->substr(0, sizeof(uint8_t)));
  }
  buffer->erase(0, sizeof(uint8_t));
  return TPM_RC_SUCCESS;
}

TPM_RC Serialize_int8_t(const int8_t& value, std::string* buffer) {
  VLOG(3) << __func__;
  int8_t value_net = value;
  switch (sizeof(int8_t)) {
    case 2:
      value_net = base::HostToNet16(value);
      break;
    case 4:
      value_net = base::HostToNet32(value);
      break;
    case 8:
      value_net = base::HostToNet64(value);
      break;
    default:
      break;
  }
  const char* value_bytes = reinterpret_cast<const char*>(&value_net);
  buffer->append(value_bytes, sizeof(int8_t));
  return TPM_RC_SUCCESS;
}

TPM_RC Parse_int8_t(std::string* buffer,
                    int8_t* value,
                    std::string* value_bytes) {
  VLOG(3) << __func__;
  if (buffer->size() < sizeof(int8_t))
    return TPM_RC_INSUFFICIENT;
  int8_t value_net = 0;
  memcpy(&value_net, buffer->data(), sizeof(int8_t));
  switch (sizeof(int8_t)) {
    case 2:
      *value = base::NetToHost16(value_net);
      break;
    case 4:
      *value = base::NetToHost32(value_net);
      break;
    case 8:
      *value = base::NetToHost64(value_net);
      break;
    default:
      *value = value_net;
  }
  if (value_bytes) {
    value_bytes->append(buffer->substr(0, sizeof(int8_t)));
  }
  buffer->erase(0, sizeof(int8_t));
  return TPM_RC_SUCCESS;
}

TPM_RC Serialize_int(const int& value, std::string* buffer) {
  VLOG(3) << __func__;
  int value_net = value;
  switch (sizeof(int)) {
    case 2:
      value_net = base::HostToNet16(value);
      break;
    case 4:
      value_net = base::HostToNet32(value);
      break;
    case 8:
      value_net = base::HostToNet64(value);
      break;
    default:
      break;
  }
  const char* value_bytes = reinterpret_cast<const char*>(&value_net);
  buffer->append(value_bytes, sizeof(int));
  return TPM_RC_SUCCESS;
}

TPM_RC Parse_int(std::string* buffer, int* value, std::string* value_bytes) {
  VLOG(3) << __func__;
  if (buffer->size() < sizeof(int))
    return TPM_RC_INSUFFICIENT;
  int value_net = 0;
  memcpy(&value_net, buffer->data(), sizeof(int));
  switch (sizeof(int)) {
    case 2:
      *value = base::NetToHost16(value_net);
      break;
    case 4:
      *value = base::NetToHost32(value_net);
      break;
    case 8:
      *value = base::NetToHost64(value_net);
      break;
    default:
      *value = value_net;
  }
  if (value_bytes) {
    value_bytes->append(buffer->substr(0, sizeof(int)));
  }
  buffer->erase(0, sizeof(int));
  return TPM_RC_SUCCESS;
}

TPM_RC Serialize_uint16_t(const uint16_t& value, std::string* buffer) {
  VLOG(3) << __func__;
  uint16_t value_net = value;
  switch (sizeof(uint16_t)) {
    case 2:
      value_net = base::HostToNet16(value);
      break;
    case 4:
      value_net = base::HostToNet32(value);
      break;
    case 8:
      value_net = base::HostToNet64(value);
      break;
    default:
      break;
  }
  const char* value_bytes = reinterpret_cast<const char*>(&value_net);
  buffer->append(value_bytes, sizeof(uint16_t));
  return TPM_RC_SUCCESS;
}

TPM_RC Parse_uint16_t(std::string* buffer,
                      uint16_t* value,
                      std::string* value_bytes) {
  VLOG(3) << __func__;
  if (buffer->size() < sizeof(uint16_t))
    return TPM_RC_INSUFFICIENT;
  uint16_t value_net = 0;
  memcpy(&value_net, buffer->data(), sizeof(uint16_t));
  switch (sizeof(uint16_t)) {
    case 2:
      *value = base::NetToHost16(value_net);
      break;
    case 4:
      *value = base::NetToHost32(value_net);
      break;
    case 8:
      *value = base::NetToHost64(value_net);
      break;
    default:
      *value = value_net;
  }
  if (value_bytes) {
    value_bytes->append(buffer->substr(0, sizeof(uint16_t)));
  }
  buffer->erase(0, sizeof(uint16_t));
  return TPM_RC_SUCCESS;
}

TPM_RC Serialize_int16_t(const int16_t& value, std::string* buffer) {
  VLOG(3) << __func__;
  int16_t value_net = value;
  switch (sizeof(int16_t)) {
    case 2:
      value_net = base::HostToNet16(value);
      break;
    case 4:
      value_net = base::HostToNet32(value);
      break;
    case 8:
      value_net = base::HostToNet64(value);
      break;
    default:
      break;
  }
  const char* value_bytes = reinterpret_cast<const char*>(&value_net);
  buffer->append(value_bytes, sizeof(int16_t));
  return TPM_RC_SUCCESS;
}

TPM_RC Parse_int16_t(std::string* buffer,
                     int16_t* value,
                     std::string* value_bytes) {
  VLOG(3) << __func__;
  if (buffer->size() < sizeof(int16_t))
    return TPM_RC_INSUFFICIENT;
  int16_t value_net = 0;
  memcpy(&value_net, buffer->data(), sizeof(int16_t));
  switch (sizeof(int16_t)) {
    case 2:
      *value = base::NetToHost16(value_net);
      break;
    case 4:
      *value = base::NetToHost32(value_net);
      break;
    case 8:
      *value = base::NetToHost64(value_net);
      break;
    default:
      *value = value_net;
  }
  if (value_bytes) {
    value_bytes->append(buffer->substr(0, sizeof(int16_t)));
  }
  buffer->erase(0, sizeof(int16_t));
  return TPM_RC_SUCCESS;
}

TPM_RC Serialize_uint32_t(const uint32_t& value, std::string* buffer) {
  VLOG(3) << __func__;
  uint32_t value_net = value;
  switch (sizeof(uint32_t)) {
    case 2:
      value_net = base::HostToNet16(value);
      break;
    case 4:
      value_net = base::HostToNet32(value);
      break;
    case 8:
      value_net = base::HostToNet64(value);
      break;
    default:
      break;
  }
  const char* value_bytes = reinterpret_cast<const char*>(&value_net);
  buffer->append(value_bytes, sizeof(uint32_t));
  return TPM_RC_SUCCESS;
}

TPM_RC Parse_uint32_t(std::string* buffer,
                      uint32_t* value,
                      std::string* value_bytes) {
  VLOG(3) << __func__;
  if (buffer->size() < sizeof(uint32_t))
    return TPM_RC_INSUFFICIENT;
  uint32_t value_net = 0;
  memcpy(&value_net, buffer->data(), sizeof(uint32_t));
  switch (sizeof(uint32_t)) {
    case 2:
      *value = base::NetToHost16(value_net);
      break;
    case 4:
      *value = base::NetToHost32(value_net);
      break;
    case 8:
      *value = base::NetToHost64(value_net);
      break;
    default:
      *value = value_net;
  }
  if (value_bytes) {
    value_bytes->append(buffer->substr(0, sizeof(uint32_t)));
  }
  buffer->erase(0, sizeof(uint32_t));
  return TPM_RC_SUCCESS;
}

TPM_RC Serialize_int32_t(const int32_t& value, std::string* buffer) {
  VLOG(3) << __func__;
  int32_t value_net = value;
  switch (sizeof(int32_t)) {
    case 2:
      value_net = base::HostToNet16(value);
      break;
    case 4:
      value_net = base::HostToNet32(value);
      break;
    case 8:
      value_net = base::HostToNet64(value);
      break;
    default:
      break;
  }
  const char* value_bytes = reinterpret_cast<const char*>(&value_net);
  buffer->append(value_bytes, sizeof(int32_t));
  return TPM_RC_SUCCESS;
}

TPM_RC Parse_int32_t(std::string* buffer,
                     int32_t* value,
                     std::string* value_bytes) {
  VLOG(3) << __func__;
  if (buffer->size() < sizeof(int32_t))
    return TPM_RC_INSUFFICIENT;
  int32_t value_net = 0;
  memcpy(&value_net, buffer->data(), sizeof(int32_t));
  switch (sizeof(int32_t)) {
    case 2:
      *value = base::NetToHost16(value_net);
      break;
    case 4:
      *value = base::NetToHost32(value_net);
      break;
    case 8:
      *value = base::NetToHost64(value_net);
      break;
    default:
      *value = value_net;
  }
  if (value_bytes) {
    value_bytes->append(buffer->substr(0, sizeof(int32_t)));
  }
  buffer->erase(0, sizeof(int32_t));
  return TPM_RC_SUCCESS;
}

TPM_RC Serialize_uint64_t(const uint64_t& value, std::string* buffer) {
  VLOG(3) << __func__;
  uint64_t value_net = value;
  switch (sizeof(uint64_t)) {
    case 2:
      value_net = base::HostToNet16(value);
      break;
    case 4:
      value_net = base::HostToNet32(value);
      break;
    case 8:
      value_net = base::HostToNet64(value);
      break;
    default:
      break;
  }
  const char* value_bytes = reinterpret_cast<const char*>(&value_net);
  buffer->append(value_bytes, sizeof(uint64_t));
  return TPM_RC_SUCCESS;
}

TPM_RC Parse_uint64_t(std::string* buffer,
                      uint64_t* value,
                      std::string* value_bytes) {
  VLOG(3) << __func__;
  if (buffer->size() < sizeof(uint64_t))
    return TPM_RC_INSUFFICIENT;
  uint64_t value_net = 0;
  memcpy(&value_net, buffer->data(), sizeof(uint64_t));
  switch (sizeof(uint64_t)) {
    case 2:
      *value = base::NetToHost16(value_net);
      break;
    case 4:
      *value = base::NetToHost32(value_net);
      break;
    case 8:
      *value = base::NetToHost64(value_net);
      break;
    default:
      *value = value_net;
  }
  if (value_bytes) {
    value_bytes->append(buffer->substr(0, sizeof(uint64_t)));
  }
  buffer->erase(0, sizeof(uint64_t));
  return TPM_RC_SUCCESS;
}

TPM_RC Serialize_int64_t(const int64_t& value, std::string* buffer) {
  VLOG(3) << __func__;
  int64_t value_net = value;
  switch (sizeof(int64_t)) {
    case 2:
      value_net = base::HostToNet16(value);
      break;
    case 4:
      value_net = base::HostToNet32(value);
      break;
    case 8:
      value_net = base::HostToNet64(value);
      break;
    default:
      break;
  }
  const char* value_bytes = reinterpret_cast<const char*>(&value_net);
  buffer->append(value_bytes, sizeof(int64_t));
  return TPM_RC_SUCCESS;
}

TPM_RC Parse_int64_t(std::string* buffer,
                     int64_t* value,
                     std::string* value_bytes) {
  VLOG(3) << __func__;
  if (buffer->size() < sizeof(int64_t))
    return TPM_RC_INSUFFICIENT;
  int64_t value_net = 0;
  memcpy(&value_net, buffer->data(), sizeof(int64_t));
  switch (sizeof(int64_t)) {
    case 2:
      *value = base::NetToHost16(value_net);
      break;
    case 4:
      *value = base::NetToHost32(value_net);
      break;
    case 8:
      *value = base::NetToHost64(value_net);
      break;
    default:
      *value = value_net;
  }
  if (value_bytes) {
    value_bytes->append(buffer->substr(0, sizeof(int64_t)));
  }
  buffer->erase(0, sizeof(int64_t));
  return TPM_RC_SUCCESS;
}

TPM_RC Serialize_UINT8(const UINT8& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_uint8_t(value, buffer);
}

TPM_RC Parse_UINT8(std::string* buffer,
                   UINT8* value,
                   std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_uint8_t(buffer, value, value_bytes);
}

TPM_RC Serialize_BYTE(const BYTE& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_uint8_t(value, buffer);
}

TPM_RC Parse_BYTE(std::string* buffer, BYTE* value, std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_uint8_t(buffer, value, value_bytes);
}

TPM_RC Serialize_INT8(const INT8& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_int8_t(value, buffer);
}

TPM_RC Parse_INT8(std::string* buffer, INT8* value, std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_int8_t(buffer, value, value_bytes);
}

TPM_RC Serialize_BOOL(const BOOL& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_int(value, buffer);
}

TPM_RC Parse_BOOL(std::string* buffer, BOOL* value, std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_int(buffer, value, value_bytes);
}

TPM_RC Serialize_UINT16(const UINT16& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_uint16_t(value, buffer);
}

TPM_RC Parse_UINT16(std::string* buffer,
                    UINT16* value,
                    std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_uint16_t(buffer, value, value_bytes);
}

TPM_RC Serialize_INT16(const INT16& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_int16_t(value, buffer);
}

TPM_RC Parse_INT16(std::string* buffer,
                   INT16* value,
                   std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_int16_t(buffer, value, value_bytes);
}

TPM_RC Serialize_UINT32(const UINT32& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_uint32_t(value, buffer);
}

TPM_RC Parse_UINT32(std::string* buffer,
                    UINT32* value,
                    std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_uint32_t(buffer, value, value_bytes);
}

TPM_RC Serialize_INT32(const INT32& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_int32_t(value, buffer);
}

TPM_RC Parse_INT32(std::string* buffer,
                   INT32* value,
                   std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_int32_t(buffer, value, value_bytes);
}

TPM_RC Serialize_UINT64(const UINT64& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_uint64_t(value, buffer);
}

TPM_RC Parse_UINT64(std::string* buffer,
                    UINT64* value,
                    std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_uint64_t(buffer, value, value_bytes);
}

TPM_RC Serialize_INT64(const INT64& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_int64_t(value, buffer);
}

TPM_RC Parse_INT64(std::string* buffer,
                   INT64* value,
                   std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_int64_t(buffer, value, value_bytes);
}

TPM_RC Serialize_TPM_ALGORITHM_ID(const TPM_ALGORITHM_ID& value,
                                  std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT32(value, buffer);
}

TPM_RC Parse_TPM_ALGORITHM_ID(std::string* buffer,
                              TPM_ALGORITHM_ID* value,
                              std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT32(buffer, value, value_bytes);
}

TPM_RC Serialize_TPM_MODIFIER_INDICATOR(const TPM_MODIFIER_INDICATOR& value,
                                        std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT32(value, buffer);
}

TPM_RC Parse_TPM_MODIFIER_INDICATOR(std::string* buffer,
                                    TPM_MODIFIER_INDICATOR* value,
                                    std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT32(buffer, value, value_bytes);
}

TPM_RC Serialize_TPM_AUTHORIZATION_SIZE(const TPM_AUTHORIZATION_SIZE& value,
                                        std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT32(value, buffer);
}

TPM_RC Parse_TPM_AUTHORIZATION_SIZE(std::string* buffer,
                                    TPM_AUTHORIZATION_SIZE* value,
                                    std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT32(buffer, value, value_bytes);
}

TPM_RC Serialize_TPM_PARAMETER_SIZE(const TPM_PARAMETER_SIZE& value,
                                    std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT32(value, buffer);
}

TPM_RC Parse_TPM_PARAMETER_SIZE(std::string* buffer,
                                TPM_PARAMETER_SIZE* value,
                                std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT32(buffer, value, value_bytes);
}

TPM_RC Serialize_TPM_KEY_SIZE(const TPM_KEY_SIZE& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT16(value, buffer);
}

TPM_RC Parse_TPM_KEY_SIZE(std::string* buffer,
                          TPM_KEY_SIZE* value,
                          std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT16(buffer, value, value_bytes);
}

TPM_RC Serialize_TPM_KEY_BITS(const TPM_KEY_BITS& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT16(value, buffer);
}

TPM_RC Parse_TPM_KEY_BITS(std::string* buffer,
                          TPM_KEY_BITS* value,
                          std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT16(buffer, value, value_bytes);
}

TPM_RC Serialize_TPM_HANDLE(const TPM_HANDLE& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT32(value, buffer);
}

TPM_RC Parse_TPM_HANDLE(std::string* buffer,
                        TPM_HANDLE* value,
                        std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT32(buffer, value, value_bytes);
}

TPM_RC Serialize_TPM2B_DIGEST(const TPM2B_DIGEST& value, std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT16(value.size, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.buffer) < value.size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.size; ++i) {
    result = Serialize_BYTE(value.buffer[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPM2B_DIGEST(std::string* buffer,
                          TPM2B_DIGEST* value,
                          std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT16(buffer, &value->size, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->buffer) < value->size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->size; ++i) {
    result = Parse_BYTE(buffer, &value->buffer[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM2B_DIGEST Make_TPM2B_DIGEST(const std::string& bytes) {
  TPM2B_DIGEST tpm2b;
  CHECK(bytes.size() <= sizeof(tpm2b.buffer));
  memset(&tpm2b, 0, sizeof(TPM2B_DIGEST));
  tpm2b.size = bytes.size();
  memcpy(tpm2b.buffer, bytes.data(), bytes.size());
  return tpm2b;
}

std::string StringFrom_TPM2B_DIGEST(const TPM2B_DIGEST& tpm2b) {
  const char* char_buffer = reinterpret_cast<const char*>(tpm2b.buffer);
  return std::string(char_buffer, tpm2b.size);
}

TPM_RC Serialize_TPM2B_NONCE(const TPM2B_NONCE& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM2B_DIGEST(value, buffer);
}

TPM_RC Parse_TPM2B_NONCE(std::string* buffer,
                         TPM2B_NONCE* value,
                         std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM2B_DIGEST(buffer, value, value_bytes);
}

TPM_RC Serialize_TPM2B_AUTH(const TPM2B_AUTH& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM2B_DIGEST(value, buffer);
}

TPM_RC Parse_TPM2B_AUTH(std::string* buffer,
                        TPM2B_AUTH* value,
                        std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM2B_DIGEST(buffer, value, value_bytes);
}

TPM_RC Serialize_TPM2B_OPERAND(const TPM2B_OPERAND& value,
                               std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM2B_DIGEST(value, buffer);
}

TPM_RC Parse_TPM2B_OPERAND(std::string* buffer,
                           TPM2B_OPERAND* value,
                           std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM2B_DIGEST(buffer, value, value_bytes);
}

TPM_RC Serialize_TPM_ALG_ID(const TPM_ALG_ID& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT16(value, buffer);
}

TPM_RC Parse_TPM_ALG_ID(std::string* buffer,
                        TPM_ALG_ID* value,
                        std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT16(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_ALG_HASH(const TPMI_ALG_HASH& value,
                               std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_ALG_ID(value, buffer);
}

TPM_RC Parse_TPMI_ALG_HASH(std::string* buffer,
                           TPMI_ALG_HASH* value,
                           std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_ALG_ID(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMS_SCHEME_SIGHASH(const TPMS_SCHEME_SIGHASH& value,
                                     std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_ALG_HASH(value.hash_alg, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_SCHEME_SIGHASH(std::string* buffer,
                                 TPMS_SCHEME_SIGHASH* value,
                                 std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_ALG_HASH(buffer, &value->hash_alg, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMS_SCHEME_HMAC(const TPMS_SCHEME_HMAC& value,
                                  std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPMS_SCHEME_SIGHASH(value, buffer);
}

TPM_RC Parse_TPMS_SCHEME_HMAC(std::string* buffer,
                              TPMS_SCHEME_HMAC* value,
                              std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPMS_SCHEME_SIGHASH(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMS_SCHEME_RSASSA(const TPMS_SCHEME_RSASSA& value,
                                    std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPMS_SCHEME_SIGHASH(value, buffer);
}

TPM_RC Parse_TPMS_SCHEME_RSASSA(std::string* buffer,
                                TPMS_SCHEME_RSASSA* value,
                                std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPMS_SCHEME_SIGHASH(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMS_SCHEME_RSAPSS(const TPMS_SCHEME_RSAPSS& value,
                                    std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPMS_SCHEME_SIGHASH(value, buffer);
}

TPM_RC Parse_TPMS_SCHEME_RSAPSS(std::string* buffer,
                                TPMS_SCHEME_RSAPSS* value,
                                std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPMS_SCHEME_SIGHASH(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMS_SCHEME_ECDSA(const TPMS_SCHEME_ECDSA& value,
                                   std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPMS_SCHEME_SIGHASH(value, buffer);
}

TPM_RC Parse_TPMS_SCHEME_ECDSA(std::string* buffer,
                               TPMS_SCHEME_ECDSA* value,
                               std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPMS_SCHEME_SIGHASH(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMS_SCHEME_SM2(const TPMS_SCHEME_SM2& value,
                                 std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPMS_SCHEME_SIGHASH(value, buffer);
}

TPM_RC Parse_TPMS_SCHEME_SM2(std::string* buffer,
                             TPMS_SCHEME_SM2* value,
                             std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPMS_SCHEME_SIGHASH(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMS_SCHEME_ECSCHNORR(const TPMS_SCHEME_ECSCHNORR& value,
                                       std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPMS_SCHEME_SIGHASH(value, buffer);
}

TPM_RC Parse_TPMS_SCHEME_ECSCHNORR(std::string* buffer,
                                   TPMS_SCHEME_ECSCHNORR* value,
                                   std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPMS_SCHEME_SIGHASH(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_YES_NO(const TPMI_YES_NO& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_BYTE(value, buffer);
}

TPM_RC Parse_TPMI_YES_NO(std::string* buffer,
                         TPMI_YES_NO* value,
                         std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_BYTE(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_DH_OBJECT(const TPMI_DH_OBJECT& value,
                                std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_HANDLE(value, buffer);
}

TPM_RC Parse_TPMI_DH_OBJECT(std::string* buffer,
                            TPMI_DH_OBJECT* value,
                            std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_HANDLE(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_DH_PERSISTENT(const TPMI_DH_PERSISTENT& value,
                                    std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_HANDLE(value, buffer);
}

TPM_RC Parse_TPMI_DH_PERSISTENT(std::string* buffer,
                                TPMI_DH_PERSISTENT* value,
                                std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_HANDLE(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_DH_ENTITY(const TPMI_DH_ENTITY& value,
                                std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_HANDLE(value, buffer);
}

TPM_RC Parse_TPMI_DH_ENTITY(std::string* buffer,
                            TPMI_DH_ENTITY* value,
                            std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_HANDLE(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_DH_PCR(const TPMI_DH_PCR& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_HANDLE(value, buffer);
}

TPM_RC Parse_TPMI_DH_PCR(std::string* buffer,
                         TPMI_DH_PCR* value,
                         std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_HANDLE(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_SH_AUTH_SESSION(const TPMI_SH_AUTH_SESSION& value,
                                      std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_HANDLE(value, buffer);
}

TPM_RC Parse_TPMI_SH_AUTH_SESSION(std::string* buffer,
                                  TPMI_SH_AUTH_SESSION* value,
                                  std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_HANDLE(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_SH_HMAC(const TPMI_SH_HMAC& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_HANDLE(value, buffer);
}

TPM_RC Parse_TPMI_SH_HMAC(std::string* buffer,
                          TPMI_SH_HMAC* value,
                          std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_HANDLE(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_SH_POLICY(const TPMI_SH_POLICY& value,
                                std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_HANDLE(value, buffer);
}

TPM_RC Parse_TPMI_SH_POLICY(std::string* buffer,
                            TPMI_SH_POLICY* value,
                            std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_HANDLE(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_DH_CONTEXT(const TPMI_DH_CONTEXT& value,
                                 std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_HANDLE(value, buffer);
}

TPM_RC Parse_TPMI_DH_CONTEXT(std::string* buffer,
                             TPMI_DH_CONTEXT* value,
                             std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_HANDLE(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_RH_HIERARCHY(const TPMI_RH_HIERARCHY& value,
                                   std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_HANDLE(value, buffer);
}

TPM_RC Parse_TPMI_RH_HIERARCHY(std::string* buffer,
                               TPMI_RH_HIERARCHY* value,
                               std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_HANDLE(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_RH_ENABLES(const TPMI_RH_ENABLES& value,
                                 std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_HANDLE(value, buffer);
}

TPM_RC Parse_TPMI_RH_ENABLES(std::string* buffer,
                             TPMI_RH_ENABLES* value,
                             std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_HANDLE(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_RH_HIERARCHY_AUTH(const TPMI_RH_HIERARCHY_AUTH& value,
                                        std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_HANDLE(value, buffer);
}

TPM_RC Parse_TPMI_RH_HIERARCHY_AUTH(std::string* buffer,
                                    TPMI_RH_HIERARCHY_AUTH* value,
                                    std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_HANDLE(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_RH_PLATFORM(const TPMI_RH_PLATFORM& value,
                                  std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_HANDLE(value, buffer);
}

TPM_RC Parse_TPMI_RH_PLATFORM(std::string* buffer,
                              TPMI_RH_PLATFORM* value,
                              std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_HANDLE(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_RH_OWNER(const TPMI_RH_OWNER& value,
                               std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_HANDLE(value, buffer);
}

TPM_RC Parse_TPMI_RH_OWNER(std::string* buffer,
                           TPMI_RH_OWNER* value,
                           std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_HANDLE(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_RH_ENDORSEMENT(const TPMI_RH_ENDORSEMENT& value,
                                     std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_HANDLE(value, buffer);
}

TPM_RC Parse_TPMI_RH_ENDORSEMENT(std::string* buffer,
                                 TPMI_RH_ENDORSEMENT* value,
                                 std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_HANDLE(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_RH_PROVISION(const TPMI_RH_PROVISION& value,
                                   std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_HANDLE(value, buffer);
}

TPM_RC Parse_TPMI_RH_PROVISION(std::string* buffer,
                               TPMI_RH_PROVISION* value,
                               std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_HANDLE(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_RH_CLEAR(const TPMI_RH_CLEAR& value,
                               std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_HANDLE(value, buffer);
}

TPM_RC Parse_TPMI_RH_CLEAR(std::string* buffer,
                           TPMI_RH_CLEAR* value,
                           std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_HANDLE(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_RH_NV_AUTH(const TPMI_RH_NV_AUTH& value,
                                 std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_HANDLE(value, buffer);
}

TPM_RC Parse_TPMI_RH_NV_AUTH(std::string* buffer,
                             TPMI_RH_NV_AUTH* value,
                             std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_HANDLE(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_RH_LOCKOUT(const TPMI_RH_LOCKOUT& value,
                                 std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_HANDLE(value, buffer);
}

TPM_RC Parse_TPMI_RH_LOCKOUT(std::string* buffer,
                             TPMI_RH_LOCKOUT* value,
                             std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_HANDLE(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_RH_NV_INDEX(const TPMI_RH_NV_INDEX& value,
                                  std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_HANDLE(value, buffer);
}

TPM_RC Parse_TPMI_RH_NV_INDEX(std::string* buffer,
                              TPMI_RH_NV_INDEX* value,
                              std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_HANDLE(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_ALG_ASYM(const TPMI_ALG_ASYM& value,
                               std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_ALG_ID(value, buffer);
}

TPM_RC Parse_TPMI_ALG_ASYM(std::string* buffer,
                           TPMI_ALG_ASYM* value,
                           std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_ALG_ID(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_ALG_SYM(const TPMI_ALG_SYM& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_ALG_ID(value, buffer);
}

TPM_RC Parse_TPMI_ALG_SYM(std::string* buffer,
                          TPMI_ALG_SYM* value,
                          std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_ALG_ID(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_ALG_SYM_OBJECT(const TPMI_ALG_SYM_OBJECT& value,
                                     std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_ALG_ID(value, buffer);
}

TPM_RC Parse_TPMI_ALG_SYM_OBJECT(std::string* buffer,
                                 TPMI_ALG_SYM_OBJECT* value,
                                 std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_ALG_ID(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_ALG_SYM_MODE(const TPMI_ALG_SYM_MODE& value,
                                   std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_ALG_ID(value, buffer);
}

TPM_RC Parse_TPMI_ALG_SYM_MODE(std::string* buffer,
                               TPMI_ALG_SYM_MODE* value,
                               std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_ALG_ID(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_ALG_KDF(const TPMI_ALG_KDF& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_ALG_ID(value, buffer);
}

TPM_RC Parse_TPMI_ALG_KDF(std::string* buffer,
                          TPMI_ALG_KDF* value,
                          std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_ALG_ID(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_ALG_SIG_SCHEME(const TPMI_ALG_SIG_SCHEME& value,
                                     std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_ALG_ID(value, buffer);
}

TPM_RC Parse_TPMI_ALG_SIG_SCHEME(std::string* buffer,
                                 TPMI_ALG_SIG_SCHEME* value,
                                 std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_ALG_ID(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_ECC_KEY_EXCHANGE(const TPMI_ECC_KEY_EXCHANGE& value,
                                       std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_ALG_ID(value, buffer);
}

TPM_RC Parse_TPMI_ECC_KEY_EXCHANGE(std::string* buffer,
                                   TPMI_ECC_KEY_EXCHANGE* value,
                                   std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_ALG_ID(buffer, value, value_bytes);
}

TPM_RC Serialize_TPM_ST(const TPM_ST& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT16(value, buffer);
}

TPM_RC Parse_TPM_ST(std::string* buffer,
                    TPM_ST* value,
                    std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT16(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_ST_COMMAND_TAG(const TPMI_ST_COMMAND_TAG& value,
                                     std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_ST(value, buffer);
}

TPM_RC Parse_TPMI_ST_COMMAND_TAG(std::string* buffer,
                                 TPMI_ST_COMMAND_TAG* value,
                                 std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_ST(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_ST_ATTEST(const TPMI_ST_ATTEST& value,
                                std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_ST(value, buffer);
}

TPM_RC Parse_TPMI_ST_ATTEST(std::string* buffer,
                            TPMI_ST_ATTEST* value,
                            std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_ST(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_AES_KEY_BITS(const TPMI_AES_KEY_BITS& value,
                                   std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_KEY_BITS(value, buffer);
}

TPM_RC Parse_TPMI_AES_KEY_BITS(std::string* buffer,
                               TPMI_AES_KEY_BITS* value,
                               std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_KEY_BITS(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_SM4_KEY_BITS(const TPMI_SM4_KEY_BITS& value,
                                   std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_KEY_BITS(value, buffer);
}

TPM_RC Parse_TPMI_SM4_KEY_BITS(std::string* buffer,
                               TPMI_SM4_KEY_BITS* value,
                               std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_KEY_BITS(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_ALG_KEYEDHASH_SCHEME(
    const TPMI_ALG_KEYEDHASH_SCHEME& value,
    std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_ALG_ID(value, buffer);
}

TPM_RC Parse_TPMI_ALG_KEYEDHASH_SCHEME(std::string* buffer,
                                       TPMI_ALG_KEYEDHASH_SCHEME* value,
                                       std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_ALG_ID(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_ALG_ASYM_SCHEME(const TPMI_ALG_ASYM_SCHEME& value,
                                      std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_ALG_ID(value, buffer);
}

TPM_RC Parse_TPMI_ALG_ASYM_SCHEME(std::string* buffer,
                                  TPMI_ALG_ASYM_SCHEME* value,
                                  std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_ALG_ID(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_ALG_RSA_SCHEME(const TPMI_ALG_RSA_SCHEME& value,
                                     std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_ALG_ID(value, buffer);
}

TPM_RC Parse_TPMI_ALG_RSA_SCHEME(std::string* buffer,
                                 TPMI_ALG_RSA_SCHEME* value,
                                 std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_ALG_ID(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_ALG_RSA_DECRYPT(const TPMI_ALG_RSA_DECRYPT& value,
                                      std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_ALG_ID(value, buffer);
}

TPM_RC Parse_TPMI_ALG_RSA_DECRYPT(std::string* buffer,
                                  TPMI_ALG_RSA_DECRYPT* value,
                                  std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_ALG_ID(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_RSA_KEY_BITS(const TPMI_RSA_KEY_BITS& value,
                                   std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_KEY_BITS(value, buffer);
}

TPM_RC Parse_TPMI_RSA_KEY_BITS(std::string* buffer,
                               TPMI_RSA_KEY_BITS* value,
                               std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_KEY_BITS(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_ALG_ECC_SCHEME(const TPMI_ALG_ECC_SCHEME& value,
                                     std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_ALG_ID(value, buffer);
}

TPM_RC Parse_TPMI_ALG_ECC_SCHEME(std::string* buffer,
                                 TPMI_ALG_ECC_SCHEME* value,
                                 std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_ALG_ID(buffer, value, value_bytes);
}

TPM_RC Serialize_TPM_ECC_CURVE(const TPM_ECC_CURVE& value,
                               std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT16(value, buffer);
}

TPM_RC Parse_TPM_ECC_CURVE(std::string* buffer,
                           TPM_ECC_CURVE* value,
                           std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT16(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_ECC_CURVE(const TPMI_ECC_CURVE& value,
                                std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_ECC_CURVE(value, buffer);
}

TPM_RC Parse_TPMI_ECC_CURVE(std::string* buffer,
                            TPMI_ECC_CURVE* value,
                            std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_ECC_CURVE(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMI_ALG_PUBLIC(const TPMI_ALG_PUBLIC& value,
                                 std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_ALG_ID(value, buffer);
}

TPM_RC Parse_TPMI_ALG_PUBLIC(std::string* buffer,
                             TPMI_ALG_PUBLIC* value,
                             std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_ALG_ID(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMA_ALGORITHM(const TPMA_ALGORITHM& value,
                                std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT32(value, buffer);
}

TPM_RC Parse_TPMA_ALGORITHM(std::string* buffer,
                            TPMA_ALGORITHM* value,
                            std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT32(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMA_OBJECT(const TPMA_OBJECT& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT32(value, buffer);
}

TPM_RC Parse_TPMA_OBJECT(std::string* buffer,
                         TPMA_OBJECT* value,
                         std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT32(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMA_SESSION(const TPMA_SESSION& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT8(value, buffer);
}

TPM_RC Parse_TPMA_SESSION(std::string* buffer,
                          TPMA_SESSION* value,
                          std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT8(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMA_LOCALITY(const TPMA_LOCALITY& value,
                               std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT8(value, buffer);
}

TPM_RC Parse_TPMA_LOCALITY(std::string* buffer,
                           TPMA_LOCALITY* value,
                           std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT8(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMA_PERMANENT(const TPMA_PERMANENT& value,
                                std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT32(value, buffer);
}

TPM_RC Parse_TPMA_PERMANENT(std::string* buffer,
                            TPMA_PERMANENT* value,
                            std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT32(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMA_STARTUP_CLEAR(const TPMA_STARTUP_CLEAR& value,
                                    std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT32(value, buffer);
}

TPM_RC Parse_TPMA_STARTUP_CLEAR(std::string* buffer,
                                TPMA_STARTUP_CLEAR* value,
                                std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT32(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMA_MEMORY(const TPMA_MEMORY& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT32(value, buffer);
}

TPM_RC Parse_TPMA_MEMORY(std::string* buffer,
                         TPMA_MEMORY* value,
                         std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT32(buffer, value, value_bytes);
}

TPM_RC Serialize_TPM_CC(const TPM_CC& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT32(value, buffer);
}

TPM_RC Parse_TPM_CC(std::string* buffer,
                    TPM_CC* value,
                    std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT32(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMA_CC(const TPMA_CC& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_CC(value, buffer);
}

TPM_RC Parse_TPMA_CC(std::string* buffer,
                     TPMA_CC* value,
                     std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_CC(buffer, value, value_bytes);
}

TPM_RC Serialize_TPM_NV_INDEX(const TPM_NV_INDEX& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT32(value, buffer);
}

TPM_RC Parse_TPM_NV_INDEX(std::string* buffer,
                          TPM_NV_INDEX* value,
                          std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT32(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMA_NV(const TPMA_NV& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT32(value, buffer);
}

TPM_RC Parse_TPMA_NV(std::string* buffer,
                     TPMA_NV* value,
                     std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT32(buffer, value, value_bytes);
}

TPM_RC Serialize_TPM_SPEC(const TPM_SPEC& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT32(value, buffer);
}

TPM_RC Parse_TPM_SPEC(std::string* buffer,
                      TPM_SPEC* value,
                      std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT32(buffer, value, value_bytes);
}

TPM_RC Serialize_TPM_GENERATED(const TPM_GENERATED& value,
                               std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT32(value, buffer);
}

TPM_RC Parse_TPM_GENERATED(std::string* buffer,
                           TPM_GENERATED* value,
                           std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT32(buffer, value, value_bytes);
}

TPM_RC Serialize_TPM_RC(const TPM_RC& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT32(value, buffer);
}

TPM_RC Parse_TPM_RC(std::string* buffer,
                    TPM_RC* value,
                    std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT32(buffer, value, value_bytes);
}

TPM_RC Serialize_TPM_CLOCK_ADJUST(const TPM_CLOCK_ADJUST& value,
                                  std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_INT8(value, buffer);
}

TPM_RC Parse_TPM_CLOCK_ADJUST(std::string* buffer,
                              TPM_CLOCK_ADJUST* value,
                              std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_INT8(buffer, value, value_bytes);
}

TPM_RC Serialize_TPM_EO(const TPM_EO& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT16(value, buffer);
}

TPM_RC Parse_TPM_EO(std::string* buffer,
                    TPM_EO* value,
                    std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT16(buffer, value, value_bytes);
}

TPM_RC Serialize_TPM_SU(const TPM_SU& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT16(value, buffer);
}

TPM_RC Parse_TPM_SU(std::string* buffer,
                    TPM_SU* value,
                    std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT16(buffer, value, value_bytes);
}

TPM_RC Serialize_TPM_SE(const TPM_SE& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT8(value, buffer);
}

TPM_RC Parse_TPM_SE(std::string* buffer,
                    TPM_SE* value,
                    std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT8(buffer, value, value_bytes);
}

TPM_RC Serialize_TPM_CAP(const TPM_CAP& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT32(value, buffer);
}

TPM_RC Parse_TPM_CAP(std::string* buffer,
                     TPM_CAP* value,
                     std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT32(buffer, value, value_bytes);
}

TPM_RC Serialize_TPM_PT(const TPM_PT& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT32(value, buffer);
}

TPM_RC Parse_TPM_PT(std::string* buffer,
                    TPM_PT* value,
                    std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT32(buffer, value, value_bytes);
}

TPM_RC Serialize_TPM_PT_PCR(const TPM_PT_PCR& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT32(value, buffer);
}

TPM_RC Parse_TPM_PT_PCR(std::string* buffer,
                        TPM_PT_PCR* value,
                        std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT32(buffer, value, value_bytes);
}

TPM_RC Serialize_TPM_PS(const TPM_PS& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT32(value, buffer);
}

TPM_RC Parse_TPM_PS(std::string* buffer,
                    TPM_PS* value,
                    std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT32(buffer, value, value_bytes);
}

TPM_RC Serialize_TPM_HT(const TPM_HT& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT8(value, buffer);
}

TPM_RC Parse_TPM_HT(std::string* buffer,
                    TPM_HT* value,
                    std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT8(buffer, value, value_bytes);
}

TPM_RC Serialize_TPM_RH(const TPM_RH& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_UINT32(value, buffer);
}

TPM_RC Parse_TPM_RH(std::string* buffer,
                    TPM_RH* value,
                    std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_UINT32(buffer, value, value_bytes);
}

TPM_RC Serialize_TPM_HC(const TPM_HC& value, std::string* buffer) {
  VLOG(3) << __func__;
  return Serialize_TPM_HANDLE(value, buffer);
}

TPM_RC Parse_TPM_HC(std::string* buffer,
                    TPM_HC* value,
                    std::string* value_bytes) {
  VLOG(3) << __func__;
  return Parse_TPM_HANDLE(buffer, value, value_bytes);
}

TPM_RC Serialize_TPMS_ALGORITHM_DESCRIPTION(
    const TPMS_ALGORITHM_DESCRIPTION& value,
    std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPM_ALG_ID(value.alg, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMA_ALGORITHM(value.attributes, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_ALGORITHM_DESCRIPTION(std::string* buffer,
                                        TPMS_ALGORITHM_DESCRIPTION* value,
                                        std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPM_ALG_ID(buffer, &value->alg, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMA_ALGORITHM(buffer, &value->attributes, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMU_HA(const TPMU_HA& value,
                         TPMI_ALG_HASH selector,
                         std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  if (selector == TPM_ALG_SHA384) {
    if (arraysize(value.sha384) < SHA384_DIGEST_SIZE) {
      return TPM_RC_INSUFFICIENT;
    }
    for (uint32_t i = 0; i < SHA384_DIGEST_SIZE; ++i) {
      result = Serialize_BYTE(value.sha384[i], buffer);
      if (result) {
        return result;
      }
    }
  }

  if (selector == TPM_ALG_SHA1) {
    if (arraysize(value.sha1) < SHA1_DIGEST_SIZE) {
      return TPM_RC_INSUFFICIENT;
    }
    for (uint32_t i = 0; i < SHA1_DIGEST_SIZE; ++i) {
      result = Serialize_BYTE(value.sha1[i], buffer);
      if (result) {
        return result;
      }
    }
  }

  if (selector == TPM_ALG_SM3_256) {
    if (arraysize(value.sm3_256) < SM3_256_DIGEST_SIZE) {
      return TPM_RC_INSUFFICIENT;
    }
    for (uint32_t i = 0; i < SM3_256_DIGEST_SIZE; ++i) {
      result = Serialize_BYTE(value.sm3_256[i], buffer);
      if (result) {
        return result;
      }
    }
  }

  if (selector == TPM_ALG_NULL) {
    // Do nothing.
  }

  if (selector == TPM_ALG_SHA256) {
    if (arraysize(value.sha256) < SHA256_DIGEST_SIZE) {
      return TPM_RC_INSUFFICIENT;
    }
    for (uint32_t i = 0; i < SHA256_DIGEST_SIZE; ++i) {
      result = Serialize_BYTE(value.sha256[i], buffer);
      if (result) {
        return result;
      }
    }
  }

  if (selector == TPM_ALG_SHA512) {
    if (arraysize(value.sha512) < SHA512_DIGEST_SIZE) {
      return TPM_RC_INSUFFICIENT;
    }
    for (uint32_t i = 0; i < SHA512_DIGEST_SIZE; ++i) {
      result = Serialize_BYTE(value.sha512[i], buffer);
      if (result) {
        return result;
      }
    }
  }
  return result;
}

TPM_RC Parse_TPMU_HA(std::string* buffer,
                     TPMI_ALG_HASH selector,
                     TPMU_HA* value,
                     std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  if (selector == TPM_ALG_SHA384) {
    if (arraysize(value->sha384) < SHA384_DIGEST_SIZE) {
      return TPM_RC_INSUFFICIENT;
    }
    for (uint32_t i = 0; i < SHA384_DIGEST_SIZE; ++i) {
      result = Parse_BYTE(buffer, &value->sha384[i], value_bytes);
      if (result) {
        return result;
      }
    }
  }

  if (selector == TPM_ALG_SHA1) {
    if (arraysize(value->sha1) < SHA1_DIGEST_SIZE) {
      return TPM_RC_INSUFFICIENT;
    }
    for (uint32_t i = 0; i < SHA1_DIGEST_SIZE; ++i) {
      result = Parse_BYTE(buffer, &value->sha1[i], value_bytes);
      if (result) {
        return result;
      }
    }
  }

  if (selector == TPM_ALG_SM3_256) {
    if (arraysize(value->sm3_256) < SM3_256_DIGEST_SIZE) {
      return TPM_RC_INSUFFICIENT;
    }
    for (uint32_t i = 0; i < SM3_256_DIGEST_SIZE; ++i) {
      result = Parse_BYTE(buffer, &value->sm3_256[i], value_bytes);
      if (result) {
        return result;
      }
    }
  }

  if (selector == TPM_ALG_NULL) {
    // Do nothing.
  }

  if (selector == TPM_ALG_SHA256) {
    if (arraysize(value->sha256) < SHA256_DIGEST_SIZE) {
      return TPM_RC_INSUFFICIENT;
    }
    for (uint32_t i = 0; i < SHA256_DIGEST_SIZE; ++i) {
      result = Parse_BYTE(buffer, &value->sha256[i], value_bytes);
      if (result) {
        return result;
      }
    }
  }

  if (selector == TPM_ALG_SHA512) {
    if (arraysize(value->sha512) < SHA512_DIGEST_SIZE) {
      return TPM_RC_INSUFFICIENT;
    }
    for (uint32_t i = 0; i < SHA512_DIGEST_SIZE; ++i) {
      result = Parse_BYTE(buffer, &value->sha512[i], value_bytes);
      if (result) {
        return result;
      }
    }
  }
  return result;
}

TPM_RC Serialize_TPMT_HA(const TPMT_HA& value, std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_ALG_HASH(value.hash_alg, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMU_HA(value.digest, value.hash_alg, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMT_HA(std::string* buffer,
                     TPMT_HA* value,
                     std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_ALG_HASH(buffer, &value->hash_alg, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMU_HA(buffer, value->hash_alg, &value->digest, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPM2B_DATA(const TPM2B_DATA& value, std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT16(value.size, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.buffer) < value.size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.size; ++i) {
    result = Serialize_BYTE(value.buffer[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPM2B_DATA(std::string* buffer,
                        TPM2B_DATA* value,
                        std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT16(buffer, &value->size, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->buffer) < value->size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->size; ++i) {
    result = Parse_BYTE(buffer, &value->buffer[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM2B_DATA Make_TPM2B_DATA(const std::string& bytes) {
  TPM2B_DATA tpm2b;
  CHECK(bytes.size() <= sizeof(tpm2b.buffer));
  memset(&tpm2b, 0, sizeof(TPM2B_DATA));
  tpm2b.size = bytes.size();
  memcpy(tpm2b.buffer, bytes.data(), bytes.size());
  return tpm2b;
}

std::string StringFrom_TPM2B_DATA(const TPM2B_DATA& tpm2b) {
  const char* char_buffer = reinterpret_cast<const char*>(tpm2b.buffer);
  return std::string(char_buffer, tpm2b.size);
}

TPM_RC Serialize_TPM2B_EVENT(const TPM2B_EVENT& value, std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT16(value.size, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.buffer) < value.size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.size; ++i) {
    result = Serialize_BYTE(value.buffer[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPM2B_EVENT(std::string* buffer,
                         TPM2B_EVENT* value,
                         std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT16(buffer, &value->size, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->buffer) < value->size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->size; ++i) {
    result = Parse_BYTE(buffer, &value->buffer[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM2B_EVENT Make_TPM2B_EVENT(const std::string& bytes) {
  TPM2B_EVENT tpm2b;
  CHECK(bytes.size() <= sizeof(tpm2b.buffer));
  memset(&tpm2b, 0, sizeof(TPM2B_EVENT));
  tpm2b.size = bytes.size();
  memcpy(tpm2b.buffer, bytes.data(), bytes.size());
  return tpm2b;
}

std::string StringFrom_TPM2B_EVENT(const TPM2B_EVENT& tpm2b) {
  const char* char_buffer = reinterpret_cast<const char*>(tpm2b.buffer);
  return std::string(char_buffer, tpm2b.size);
}

TPM_RC Serialize_TPM2B_MAX_BUFFER(const TPM2B_MAX_BUFFER& value,
                                  std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT16(value.size, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.buffer) < value.size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.size; ++i) {
    result = Serialize_BYTE(value.buffer[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPM2B_MAX_BUFFER(std::string* buffer,
                              TPM2B_MAX_BUFFER* value,
                              std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT16(buffer, &value->size, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->buffer) < value->size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->size; ++i) {
    result = Parse_BYTE(buffer, &value->buffer[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM2B_MAX_BUFFER Make_TPM2B_MAX_BUFFER(const std::string& bytes) {
  TPM2B_MAX_BUFFER tpm2b;
  CHECK(bytes.size() <= sizeof(tpm2b.buffer));
  memset(&tpm2b, 0, sizeof(TPM2B_MAX_BUFFER));
  tpm2b.size = bytes.size();
  memcpy(tpm2b.buffer, bytes.data(), bytes.size());
  return tpm2b;
}

std::string StringFrom_TPM2B_MAX_BUFFER(const TPM2B_MAX_BUFFER& tpm2b) {
  const char* char_buffer = reinterpret_cast<const char*>(tpm2b.buffer);
  return std::string(char_buffer, tpm2b.size);
}

TPM_RC Serialize_TPM2B_MAX_NV_BUFFER(const TPM2B_MAX_NV_BUFFER& value,
                                     std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT16(value.size, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.buffer) < value.size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.size; ++i) {
    result = Serialize_BYTE(value.buffer[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPM2B_MAX_NV_BUFFER(std::string* buffer,
                                 TPM2B_MAX_NV_BUFFER* value,
                                 std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT16(buffer, &value->size, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->buffer) < value->size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->size; ++i) {
    result = Parse_BYTE(buffer, &value->buffer[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM2B_MAX_NV_BUFFER Make_TPM2B_MAX_NV_BUFFER(const std::string& bytes) {
  TPM2B_MAX_NV_BUFFER tpm2b;
  CHECK(bytes.size() <= sizeof(tpm2b.buffer));
  memset(&tpm2b, 0, sizeof(TPM2B_MAX_NV_BUFFER));
  tpm2b.size = bytes.size();
  memcpy(tpm2b.buffer, bytes.data(), bytes.size());
  return tpm2b;
}

std::string StringFrom_TPM2B_MAX_NV_BUFFER(const TPM2B_MAX_NV_BUFFER& tpm2b) {
  const char* char_buffer = reinterpret_cast<const char*>(tpm2b.buffer);
  return std::string(char_buffer, tpm2b.size);
}

TPM_RC Serialize_TPM2B_TIMEOUT(const TPM2B_TIMEOUT& value,
                               std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT16(value.size, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.buffer) < value.size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.size; ++i) {
    result = Serialize_BYTE(value.buffer[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPM2B_TIMEOUT(std::string* buffer,
                           TPM2B_TIMEOUT* value,
                           std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT16(buffer, &value->size, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->buffer) < value->size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->size; ++i) {
    result = Parse_BYTE(buffer, &value->buffer[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM2B_TIMEOUT Make_TPM2B_TIMEOUT(const std::string& bytes) {
  TPM2B_TIMEOUT tpm2b;
  CHECK(bytes.size() <= sizeof(tpm2b.buffer));
  memset(&tpm2b, 0, sizeof(TPM2B_TIMEOUT));
  tpm2b.size = bytes.size();
  memcpy(tpm2b.buffer, bytes.data(), bytes.size());
  return tpm2b;
}

std::string StringFrom_TPM2B_TIMEOUT(const TPM2B_TIMEOUT& tpm2b) {
  const char* char_buffer = reinterpret_cast<const char*>(tpm2b.buffer);
  return std::string(char_buffer, tpm2b.size);
}

TPM_RC Serialize_TPM2B_IV(const TPM2B_IV& value, std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT16(value.size, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.buffer) < value.size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.size; ++i) {
    result = Serialize_BYTE(value.buffer[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPM2B_IV(std::string* buffer,
                      TPM2B_IV* value,
                      std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT16(buffer, &value->size, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->buffer) < value->size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->size; ++i) {
    result = Parse_BYTE(buffer, &value->buffer[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM2B_IV Make_TPM2B_IV(const std::string& bytes) {
  TPM2B_IV tpm2b;
  CHECK(bytes.size() <= sizeof(tpm2b.buffer));
  memset(&tpm2b, 0, sizeof(TPM2B_IV));
  tpm2b.size = bytes.size();
  memcpy(tpm2b.buffer, bytes.data(), bytes.size());
  return tpm2b;
}

std::string StringFrom_TPM2B_IV(const TPM2B_IV& tpm2b) {
  const char* char_buffer = reinterpret_cast<const char*>(tpm2b.buffer);
  return std::string(char_buffer, tpm2b.size);
}

TPM_RC Serialize_TPM2B_NAME(const TPM2B_NAME& value, std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT16(value.size, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.name) < value.size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.size; ++i) {
    result = Serialize_BYTE(value.name[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPM2B_NAME(std::string* buffer,
                        TPM2B_NAME* value,
                        std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT16(buffer, &value->size, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->name) < value->size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->size; ++i) {
    result = Parse_BYTE(buffer, &value->name[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM2B_NAME Make_TPM2B_NAME(const std::string& bytes) {
  TPM2B_NAME tpm2b;
  CHECK(bytes.size() <= sizeof(tpm2b.name));
  memset(&tpm2b, 0, sizeof(TPM2B_NAME));
  tpm2b.size = bytes.size();
  memcpy(tpm2b.name, bytes.data(), bytes.size());
  return tpm2b;
}

std::string StringFrom_TPM2B_NAME(const TPM2B_NAME& tpm2b) {
  const char* char_buffer = reinterpret_cast<const char*>(tpm2b.name);
  return std::string(char_buffer, tpm2b.size);
}

TPM_RC Serialize_TPMS_PCR_SELECT(const TPMS_PCR_SELECT& value,
                                 std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT8(value.sizeof_select, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.pcr_select) < value.sizeof_select) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.sizeof_select; ++i) {
    result = Serialize_BYTE(value.pcr_select[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPMS_PCR_SELECT(std::string* buffer,
                             TPMS_PCR_SELECT* value,
                             std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT8(buffer, &value->sizeof_select, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->pcr_select) < value->sizeof_select) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->sizeof_select; ++i) {
    result = Parse_BYTE(buffer, &value->pcr_select[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Serialize_TPMS_PCR_SELECTION(const TPMS_PCR_SELECTION& value,
                                    std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_ALG_HASH(value.hash, buffer);
  if (result) {
    return result;
  }

  result = Serialize_UINT8(value.sizeof_select, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.pcr_select) < value.sizeof_select) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.sizeof_select; ++i) {
    result = Serialize_BYTE(value.pcr_select[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPMS_PCR_SELECTION(std::string* buffer,
                                TPMS_PCR_SELECTION* value,
                                std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_ALG_HASH(buffer, &value->hash, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_UINT8(buffer, &value->sizeof_select, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->pcr_select) < value->sizeof_select) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->sizeof_select; ++i) {
    result = Parse_BYTE(buffer, &value->pcr_select[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Serialize_TPMT_TK_CREATION(const TPMT_TK_CREATION& value,
                                  std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPM_ST(value.tag, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMI_RH_HIERARCHY(value.hierarchy, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_DIGEST(value.digest, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMT_TK_CREATION(std::string* buffer,
                              TPMT_TK_CREATION* value,
                              std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPM_ST(buffer, &value->tag, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMI_RH_HIERARCHY(buffer, &value->hierarchy, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_DIGEST(buffer, &value->digest, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMT_TK_VERIFIED(const TPMT_TK_VERIFIED& value,
                                  std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPM_ST(value.tag, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMI_RH_HIERARCHY(value.hierarchy, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_DIGEST(value.digest, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMT_TK_VERIFIED(std::string* buffer,
                              TPMT_TK_VERIFIED* value,
                              std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPM_ST(buffer, &value->tag, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMI_RH_HIERARCHY(buffer, &value->hierarchy, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_DIGEST(buffer, &value->digest, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMT_TK_AUTH(const TPMT_TK_AUTH& value, std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_RH_HIERARCHY(value.hierarchy, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_DIGEST(value.digest, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMT_TK_AUTH(std::string* buffer,
                          TPMT_TK_AUTH* value,
                          std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_RH_HIERARCHY(buffer, &value->hierarchy, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_DIGEST(buffer, &value->digest, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMT_TK_HASHCHECK(const TPMT_TK_HASHCHECK& value,
                                   std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPM_ST(value.tag, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMI_RH_HIERARCHY(value.hierarchy, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_DIGEST(value.digest, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMT_TK_HASHCHECK(std::string* buffer,
                               TPMT_TK_HASHCHECK* value,
                               std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPM_ST(buffer, &value->tag, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMI_RH_HIERARCHY(buffer, &value->hierarchy, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_DIGEST(buffer, &value->digest, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMS_ALG_PROPERTY(const TPMS_ALG_PROPERTY& value,
                                   std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPM_ALG_ID(value.alg, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMA_ALGORITHM(value.alg_properties, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_ALG_PROPERTY(std::string* buffer,
                               TPMS_ALG_PROPERTY* value,
                               std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPM_ALG_ID(buffer, &value->alg, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMA_ALGORITHM(buffer, &value->alg_properties, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMS_TAGGED_PROPERTY(const TPMS_TAGGED_PROPERTY& value,
                                      std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPM_PT(value.property, buffer);
  if (result) {
    return result;
  }

  result = Serialize_UINT32(value.value, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_TAGGED_PROPERTY(std::string* buffer,
                                  TPMS_TAGGED_PROPERTY* value,
                                  std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPM_PT(buffer, &value->property, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_UINT32(buffer, &value->value, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMS_TAGGED_PCR_SELECT(const TPMS_TAGGED_PCR_SELECT& value,
                                        std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPM_PT(value.tag, buffer);
  if (result) {
    return result;
  }

  result = Serialize_UINT8(value.sizeof_select, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.pcr_select) < value.sizeof_select) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.sizeof_select; ++i) {
    result = Serialize_BYTE(value.pcr_select[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPMS_TAGGED_PCR_SELECT(std::string* buffer,
                                    TPMS_TAGGED_PCR_SELECT* value,
                                    std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPM_PT(buffer, &value->tag, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_UINT8(buffer, &value->sizeof_select, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->pcr_select) < value->sizeof_select) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->sizeof_select; ++i) {
    result = Parse_BYTE(buffer, &value->pcr_select[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Serialize_TPML_CC(const TPML_CC& value, std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT32(value.count, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.command_codes) < value.count) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.count; ++i) {
    result = Serialize_TPM_CC(value.command_codes[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPML_CC(std::string* buffer,
                     TPML_CC* value,
                     std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT32(buffer, &value->count, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->command_codes) < value->count) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->count; ++i) {
    result = Parse_TPM_CC(buffer, &value->command_codes[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Serialize_TPML_CCA(const TPML_CCA& value, std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT32(value.count, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.command_attributes) < value.count) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.count; ++i) {
    result = Serialize_TPMA_CC(value.command_attributes[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPML_CCA(std::string* buffer,
                      TPML_CCA* value,
                      std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT32(buffer, &value->count, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->command_attributes) < value->count) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->count; ++i) {
    result = Parse_TPMA_CC(buffer, &value->command_attributes[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Serialize_TPML_ALG(const TPML_ALG& value, std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT32(value.count, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.algorithms) < value.count) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.count; ++i) {
    result = Serialize_TPM_ALG_ID(value.algorithms[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPML_ALG(std::string* buffer,
                      TPML_ALG* value,
                      std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT32(buffer, &value->count, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->algorithms) < value->count) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->count; ++i) {
    result = Parse_TPM_ALG_ID(buffer, &value->algorithms[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Serialize_TPML_HANDLE(const TPML_HANDLE& value, std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT32(value.count, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.handle) < value.count) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.count; ++i) {
    result = Serialize_TPM_HANDLE(value.handle[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPML_HANDLE(std::string* buffer,
                         TPML_HANDLE* value,
                         std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT32(buffer, &value->count, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->handle) < value->count) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->count; ++i) {
    result = Parse_TPM_HANDLE(buffer, &value->handle[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Serialize_TPML_DIGEST(const TPML_DIGEST& value, std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT32(value.count, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.digests) < value.count) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.count; ++i) {
    result = Serialize_TPM2B_DIGEST(value.digests[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPML_DIGEST(std::string* buffer,
                         TPML_DIGEST* value,
                         std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT32(buffer, &value->count, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->digests) < value->count) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->count; ++i) {
    result = Parse_TPM2B_DIGEST(buffer, &value->digests[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Serialize_TPML_DIGEST_VALUES(const TPML_DIGEST_VALUES& value,
                                    std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT32(value.count, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.digests) < value.count) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.count; ++i) {
    result = Serialize_TPMT_HA(value.digests[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPML_DIGEST_VALUES(std::string* buffer,
                                TPML_DIGEST_VALUES* value,
                                std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT32(buffer, &value->count, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->digests) < value->count) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->count; ++i) {
    result = Parse_TPMT_HA(buffer, &value->digests[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Serialize_TPM2B_DIGEST_VALUES(const TPM2B_DIGEST_VALUES& value,
                                     std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT16(value.size, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.buffer) < value.size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.size; ++i) {
    result = Serialize_BYTE(value.buffer[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPM2B_DIGEST_VALUES(std::string* buffer,
                                 TPM2B_DIGEST_VALUES* value,
                                 std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT16(buffer, &value->size, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->buffer) < value->size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->size; ++i) {
    result = Parse_BYTE(buffer, &value->buffer[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM2B_DIGEST_VALUES Make_TPM2B_DIGEST_VALUES(const std::string& bytes) {
  TPM2B_DIGEST_VALUES tpm2b;
  CHECK(bytes.size() <= sizeof(tpm2b.buffer));
  memset(&tpm2b, 0, sizeof(TPM2B_DIGEST_VALUES));
  tpm2b.size = bytes.size();
  memcpy(tpm2b.buffer, bytes.data(), bytes.size());
  return tpm2b;
}

std::string StringFrom_TPM2B_DIGEST_VALUES(const TPM2B_DIGEST_VALUES& tpm2b) {
  const char* char_buffer = reinterpret_cast<const char*>(tpm2b.buffer);
  return std::string(char_buffer, tpm2b.size);
}

TPM_RC Serialize_TPML_PCR_SELECTION(const TPML_PCR_SELECTION& value,
                                    std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT32(value.count, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.pcr_selections) < value.count) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.count; ++i) {
    result = Serialize_TPMS_PCR_SELECTION(value.pcr_selections[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPML_PCR_SELECTION(std::string* buffer,
                                TPML_PCR_SELECTION* value,
                                std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT32(buffer, &value->count, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->pcr_selections) < value->count) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->count; ++i) {
    result = Parse_TPMS_PCR_SELECTION(buffer, &value->pcr_selections[i],
                                      value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Serialize_TPML_ALG_PROPERTY(const TPML_ALG_PROPERTY& value,
                                   std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT32(value.count, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.alg_properties) < value.count) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.count; ++i) {
    result = Serialize_TPMS_ALG_PROPERTY(value.alg_properties[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPML_ALG_PROPERTY(std::string* buffer,
                               TPML_ALG_PROPERTY* value,
                               std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT32(buffer, &value->count, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->alg_properties) < value->count) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->count; ++i) {
    result =
        Parse_TPMS_ALG_PROPERTY(buffer, &value->alg_properties[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Serialize_TPML_TAGGED_TPM_PROPERTY(const TPML_TAGGED_TPM_PROPERTY& value,
                                          std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT32(value.count, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.tpm_property) < value.count) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.count; ++i) {
    result = Serialize_TPMS_TAGGED_PROPERTY(value.tpm_property[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPML_TAGGED_TPM_PROPERTY(std::string* buffer,
                                      TPML_TAGGED_TPM_PROPERTY* value,
                                      std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT32(buffer, &value->count, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->tpm_property) < value->count) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->count; ++i) {
    result = Parse_TPMS_TAGGED_PROPERTY(buffer, &value->tpm_property[i],
                                        value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Serialize_TPML_TAGGED_PCR_PROPERTY(const TPML_TAGGED_PCR_PROPERTY& value,
                                          std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT32(value.count, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.pcr_property) < value.count) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.count; ++i) {
    result = Serialize_TPMS_TAGGED_PCR_SELECT(value.pcr_property[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPML_TAGGED_PCR_PROPERTY(std::string* buffer,
                                      TPML_TAGGED_PCR_PROPERTY* value,
                                      std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT32(buffer, &value->count, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->pcr_property) < value->count) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->count; ++i) {
    result = Parse_TPMS_TAGGED_PCR_SELECT(buffer, &value->pcr_property[i],
                                          value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Serialize_TPML_ECC_CURVE(const TPML_ECC_CURVE& value,
                                std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT32(value.count, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.ecc_curves) < value.count) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.count; ++i) {
    result = Serialize_TPM_ECC_CURVE(value.ecc_curves[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPML_ECC_CURVE(std::string* buffer,
                            TPML_ECC_CURVE* value,
                            std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT32(buffer, &value->count, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->ecc_curves) < value->count) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->count; ++i) {
    result = Parse_TPM_ECC_CURVE(buffer, &value->ecc_curves[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Serialize_TPMU_CAPABILITIES(const TPMU_CAPABILITIES& value,
                                   TPM_CAP selector,
                                   std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  if (selector == TPM_CAP_PCRS) {
    result = Serialize_TPML_PCR_SELECTION(value.assigned_pcr, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_CAP_TPM_PROPERTIES) {
    result = Serialize_TPML_TAGGED_TPM_PROPERTY(value.tpm_properties, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_CAP_PP_COMMANDS) {
    result = Serialize_TPML_CC(value.pp_commands, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_CAP_AUDIT_COMMANDS) {
    result = Serialize_TPML_CC(value.audit_commands, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_CAP_COMMANDS) {
    result = Serialize_TPML_CCA(value.command, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_CAP_ECC_CURVES) {
    result = Serialize_TPML_ECC_CURVE(value.ecc_curves, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_CAP_PCR_PROPERTIES) {
    result = Serialize_TPML_TAGGED_PCR_PROPERTY(value.pcr_properties, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_CAP_HANDLES) {
    result = Serialize_TPML_HANDLE(value.handles, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_CAP_ALGS) {
    result = Serialize_TPML_ALG_PROPERTY(value.algorithms, buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPMU_CAPABILITIES(std::string* buffer,
                               TPM_CAP selector,
                               TPMU_CAPABILITIES* value,
                               std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  if (selector == TPM_CAP_PCRS) {
    result =
        Parse_TPML_PCR_SELECTION(buffer, &value->assigned_pcr, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_CAP_TPM_PROPERTIES) {
    result = Parse_TPML_TAGGED_TPM_PROPERTY(buffer, &value->tpm_properties,
                                            value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_CAP_PP_COMMANDS) {
    result = Parse_TPML_CC(buffer, &value->pp_commands, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_CAP_AUDIT_COMMANDS) {
    result = Parse_TPML_CC(buffer, &value->audit_commands, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_CAP_COMMANDS) {
    result = Parse_TPML_CCA(buffer, &value->command, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_CAP_ECC_CURVES) {
    result = Parse_TPML_ECC_CURVE(buffer, &value->ecc_curves, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_CAP_PCR_PROPERTIES) {
    result = Parse_TPML_TAGGED_PCR_PROPERTY(buffer, &value->pcr_properties,
                                            value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_CAP_HANDLES) {
    result = Parse_TPML_HANDLE(buffer, &value->handles, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_CAP_ALGS) {
    result = Parse_TPML_ALG_PROPERTY(buffer, &value->algorithms, value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Serialize_TPMS_CAPABILITY_DATA(const TPMS_CAPABILITY_DATA& value,
                                      std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPM_CAP(value.capability, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMU_CAPABILITIES(value.data, value.capability, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_CAPABILITY_DATA(std::string* buffer,
                                  TPMS_CAPABILITY_DATA* value,
                                  std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPM_CAP(buffer, &value->capability, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMU_CAPABILITIES(buffer, value->capability, &value->data,
                                   value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMS_CLOCK_INFO(const TPMS_CLOCK_INFO& value,
                                 std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT64(value.clock, buffer);
  if (result) {
    return result;
  }

  result = Serialize_UINT32(value.reset_count, buffer);
  if (result) {
    return result;
  }

  result = Serialize_UINT32(value.restart_count, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMI_YES_NO(value.safe, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_CLOCK_INFO(std::string* buffer,
                             TPMS_CLOCK_INFO* value,
                             std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT64(buffer, &value->clock, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_UINT32(buffer, &value->reset_count, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_UINT32(buffer, &value->restart_count, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMI_YES_NO(buffer, &value->safe, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMS_TIME_INFO(const TPMS_TIME_INFO& value,
                                std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT64(value.time, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMS_CLOCK_INFO(value.clock_info, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_TIME_INFO(std::string* buffer,
                            TPMS_TIME_INFO* value,
                            std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT64(buffer, &value->time, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMS_CLOCK_INFO(buffer, &value->clock_info, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMS_TIME_ATTEST_INFO(const TPMS_TIME_ATTEST_INFO& value,
                                       std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMS_TIME_INFO(value.time, buffer);
  if (result) {
    return result;
  }

  result = Serialize_UINT64(value.firmware_version, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_TIME_ATTEST_INFO(std::string* buffer,
                                   TPMS_TIME_ATTEST_INFO* value,
                                   std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMS_TIME_INFO(buffer, &value->time, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_UINT64(buffer, &value->firmware_version, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMS_CERTIFY_INFO(const TPMS_CERTIFY_INFO& value,
                                   std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPM2B_NAME(value.name, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_NAME(value.qualified_name, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_CERTIFY_INFO(std::string* buffer,
                               TPMS_CERTIFY_INFO* value,
                               std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPM2B_NAME(buffer, &value->name, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_NAME(buffer, &value->qualified_name, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMS_QUOTE_INFO(const TPMS_QUOTE_INFO& value,
                                 std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPML_PCR_SELECTION(value.pcr_select, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_DIGEST(value.pcr_digest, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_QUOTE_INFO(std::string* buffer,
                             TPMS_QUOTE_INFO* value,
                             std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPML_PCR_SELECTION(buffer, &value->pcr_select, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_DIGEST(buffer, &value->pcr_digest, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMS_COMMAND_AUDIT_INFO(const TPMS_COMMAND_AUDIT_INFO& value,
                                         std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT64(value.audit_counter, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM_ALG_ID(value.digest_alg, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_DIGEST(value.audit_digest, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_DIGEST(value.command_digest, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_COMMAND_AUDIT_INFO(std::string* buffer,
                                     TPMS_COMMAND_AUDIT_INFO* value,
                                     std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT64(buffer, &value->audit_counter, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM_ALG_ID(buffer, &value->digest_alg, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_DIGEST(buffer, &value->audit_digest, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_DIGEST(buffer, &value->command_digest, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMS_SESSION_AUDIT_INFO(const TPMS_SESSION_AUDIT_INFO& value,
                                         std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_YES_NO(value.exclusive_session, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_DIGEST(value.session_digest, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_SESSION_AUDIT_INFO(std::string* buffer,
                                     TPMS_SESSION_AUDIT_INFO* value,
                                     std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_YES_NO(buffer, &value->exclusive_session, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_DIGEST(buffer, &value->session_digest, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMS_CREATION_INFO(const TPMS_CREATION_INFO& value,
                                    std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPM2B_NAME(value.object_name, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_DIGEST(value.creation_hash, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_CREATION_INFO(std::string* buffer,
                                TPMS_CREATION_INFO* value,
                                std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPM2B_NAME(buffer, &value->object_name, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_DIGEST(buffer, &value->creation_hash, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMS_NV_CERTIFY_INFO(const TPMS_NV_CERTIFY_INFO& value,
                                      std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPM2B_NAME(value.index_name, buffer);
  if (result) {
    return result;
  }

  result = Serialize_UINT16(value.offset, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_MAX_NV_BUFFER(value.nv_contents, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_NV_CERTIFY_INFO(std::string* buffer,
                                  TPMS_NV_CERTIFY_INFO* value,
                                  std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPM2B_NAME(buffer, &value->index_name, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_UINT16(buffer, &value->offset, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_MAX_NV_BUFFER(buffer, &value->nv_contents, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMU_ATTEST(const TPMU_ATTEST& value,
                             TPMI_ST_ATTEST selector,
                             std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  if (selector == TPM_ST_ATTEST_SESSION_AUDIT) {
    result = Serialize_TPMS_SESSION_AUDIT_INFO(value.session_audit, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ST_ATTEST_QUOTE) {
    result = Serialize_TPMS_QUOTE_INFO(value.quote, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ST_ATTEST_COMMAND_AUDIT) {
    result = Serialize_TPMS_COMMAND_AUDIT_INFO(value.command_audit, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ST_ATTEST_CERTIFY) {
    result = Serialize_TPMS_CERTIFY_INFO(value.certify, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ST_ATTEST_NV) {
    result = Serialize_TPMS_NV_CERTIFY_INFO(value.nv, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ST_ATTEST_TIME) {
    result = Serialize_TPMS_TIME_ATTEST_INFO(value.time, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ST_ATTEST_CREATION) {
    result = Serialize_TPMS_CREATION_INFO(value.creation, buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPMU_ATTEST(std::string* buffer,
                         TPMI_ST_ATTEST selector,
                         TPMU_ATTEST* value,
                         std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  if (selector == TPM_ST_ATTEST_SESSION_AUDIT) {
    result = Parse_TPMS_SESSION_AUDIT_INFO(buffer, &value->session_audit,
                                           value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ST_ATTEST_QUOTE) {
    result = Parse_TPMS_QUOTE_INFO(buffer, &value->quote, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ST_ATTEST_COMMAND_AUDIT) {
    result = Parse_TPMS_COMMAND_AUDIT_INFO(buffer, &value->command_audit,
                                           value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ST_ATTEST_CERTIFY) {
    result = Parse_TPMS_CERTIFY_INFO(buffer, &value->certify, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ST_ATTEST_NV) {
    result = Parse_TPMS_NV_CERTIFY_INFO(buffer, &value->nv, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ST_ATTEST_TIME) {
    result = Parse_TPMS_TIME_ATTEST_INFO(buffer, &value->time, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ST_ATTEST_CREATION) {
    result = Parse_TPMS_CREATION_INFO(buffer, &value->creation, value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Serialize_TPMS_ATTEST(const TPMS_ATTEST& value, std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPM_GENERATED(value.magic, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMI_ST_ATTEST(value.type, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_NAME(value.qualified_signer, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_DATA(value.extra_data, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMS_CLOCK_INFO(value.clock_info, buffer);
  if (result) {
    return result;
  }

  result = Serialize_UINT64(value.firmware_version, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMU_ATTEST(value.attested, value.type, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_ATTEST(std::string* buffer,
                         TPMS_ATTEST* value,
                         std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPM_GENERATED(buffer, &value->magic, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMI_ST_ATTEST(buffer, &value->type, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_NAME(buffer, &value->qualified_signer, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_DATA(buffer, &value->extra_data, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMS_CLOCK_INFO(buffer, &value->clock_info, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_UINT64(buffer, &value->firmware_version, value_bytes);
  if (result) {
    return result;
  }

  result =
      Parse_TPMU_ATTEST(buffer, value->type, &value->attested, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPM2B_ATTEST(const TPM2B_ATTEST& value, std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT16(value.size, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.attestation_data) < value.size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.size; ++i) {
    result = Serialize_BYTE(value.attestation_data[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPM2B_ATTEST(std::string* buffer,
                          TPM2B_ATTEST* value,
                          std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT16(buffer, &value->size, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->attestation_data) < value->size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->size; ++i) {
    result = Parse_BYTE(buffer, &value->attestation_data[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM2B_ATTEST Make_TPM2B_ATTEST(const std::string& bytes) {
  TPM2B_ATTEST tpm2b;
  CHECK(bytes.size() <= sizeof(tpm2b.attestation_data));
  memset(&tpm2b, 0, sizeof(TPM2B_ATTEST));
  tpm2b.size = bytes.size();
  memcpy(tpm2b.attestation_data, bytes.data(), bytes.size());
  return tpm2b;
}

std::string StringFrom_TPM2B_ATTEST(const TPM2B_ATTEST& tpm2b) {
  const char* char_buffer =
      reinterpret_cast<const char*>(tpm2b.attestation_data);
  return std::string(char_buffer, tpm2b.size);
}

TPM_RC Serialize_TPMS_AUTH_COMMAND(const TPMS_AUTH_COMMAND& value,
                                   std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_SH_AUTH_SESSION(value.session_handle, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_NONCE(value.nonce, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMA_SESSION(value.session_attributes, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_AUTH(value.hmac, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_AUTH_COMMAND(std::string* buffer,
                               TPMS_AUTH_COMMAND* value,
                               std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result =
      Parse_TPMI_SH_AUTH_SESSION(buffer, &value->session_handle, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_NONCE(buffer, &value->nonce, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMA_SESSION(buffer, &value->session_attributes, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_AUTH(buffer, &value->hmac, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMS_AUTH_RESPONSE(const TPMS_AUTH_RESPONSE& value,
                                    std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPM2B_NONCE(value.nonce, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMA_SESSION(value.session_attributes, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_AUTH(value.hmac, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_AUTH_RESPONSE(std::string* buffer,
                                TPMS_AUTH_RESPONSE* value,
                                std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPM2B_NONCE(buffer, &value->nonce, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMA_SESSION(buffer, &value->session_attributes, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_AUTH(buffer, &value->hmac, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMU_SYM_KEY_BITS(const TPMU_SYM_KEY_BITS& value,
                                   TPMI_ALG_SYM selector,
                                   std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  if (selector == TPM_ALG_NULL) {
    // Do nothing.
  }

  if (selector == TPM_ALG_SM4) {
    result = Serialize_TPMI_SM4_KEY_BITS(value.sm4, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_AES) {
    result = Serialize_TPMI_AES_KEY_BITS(value.aes, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_XOR) {
    result = Serialize_TPMI_ALG_HASH(value.xor_, buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPMU_SYM_KEY_BITS(std::string* buffer,
                               TPMI_ALG_SYM selector,
                               TPMU_SYM_KEY_BITS* value,
                               std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  if (selector == TPM_ALG_NULL) {
    // Do nothing.
  }

  if (selector == TPM_ALG_SM4) {
    result = Parse_TPMI_SM4_KEY_BITS(buffer, &value->sm4, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_AES) {
    result = Parse_TPMI_AES_KEY_BITS(buffer, &value->aes, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_XOR) {
    result = Parse_TPMI_ALG_HASH(buffer, &value->xor_, value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Serialize_TPMU_SYM_MODE(const TPMU_SYM_MODE& value,
                               TPMI_ALG_SYM selector,
                               std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  if (selector == TPM_ALG_NULL) {
    // Do nothing.
  }

  if (selector == TPM_ALG_SM4) {
    result = Serialize_TPMI_ALG_SYM_MODE(value.sm4, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_AES) {
    result = Serialize_TPMI_ALG_SYM_MODE(value.aes, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_XOR) {
    // Do nothing.
  }
  return result;
}

TPM_RC Parse_TPMU_SYM_MODE(std::string* buffer,
                           TPMI_ALG_SYM selector,
                           TPMU_SYM_MODE* value,
                           std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  if (selector == TPM_ALG_NULL) {
    // Do nothing.
  }

  if (selector == TPM_ALG_SM4) {
    result = Parse_TPMI_ALG_SYM_MODE(buffer, &value->sm4, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_AES) {
    result = Parse_TPMI_ALG_SYM_MODE(buffer, &value->aes, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_XOR) {
    // Do nothing.
  }
  return result;
}

TPM_RC Serialize_TPMU_SYM_DETAILS(const TPMU_SYM_DETAILS& value,
                                  TPMI_ALG_SYM selector,
                                  std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;
  return result;
}

TPM_RC Parse_TPMU_SYM_DETAILS(std::string* buffer,
                              TPMI_ALG_SYM selector,
                              TPMU_SYM_DETAILS* value,
                              std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;
  return result;
}

TPM_RC Serialize_TPMT_SYM_DEF(const TPMT_SYM_DEF& value, std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_ALG_SYM(value.algorithm, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMU_SYM_KEY_BITS(value.key_bits, value.algorithm, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMU_SYM_MODE(value.mode, value.algorithm, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMU_SYM_DETAILS(value.details, value.algorithm, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMT_SYM_DEF(std::string* buffer,
                          TPMT_SYM_DEF* value,
                          std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_ALG_SYM(buffer, &value->algorithm, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMU_SYM_KEY_BITS(buffer, value->algorithm, &value->key_bits,
                                   value_bytes);
  if (result) {
    return result;
  }

  result =
      Parse_TPMU_SYM_MODE(buffer, value->algorithm, &value->mode, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMU_SYM_DETAILS(buffer, value->algorithm, &value->details,
                                  value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMT_SYM_DEF_OBJECT(const TPMT_SYM_DEF_OBJECT& value,
                                     std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_ALG_SYM_OBJECT(value.algorithm, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMU_SYM_KEY_BITS(value.key_bits, value.algorithm, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMU_SYM_MODE(value.mode, value.algorithm, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMU_SYM_DETAILS(value.details, value.algorithm, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMT_SYM_DEF_OBJECT(std::string* buffer,
                                 TPMT_SYM_DEF_OBJECT* value,
                                 std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_ALG_SYM_OBJECT(buffer, &value->algorithm, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMU_SYM_KEY_BITS(buffer, value->algorithm, &value->key_bits,
                                   value_bytes);
  if (result) {
    return result;
  }

  result =
      Parse_TPMU_SYM_MODE(buffer, value->algorithm, &value->mode, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMU_SYM_DETAILS(buffer, value->algorithm, &value->details,
                                  value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPM2B_SYM_KEY(const TPM2B_SYM_KEY& value,
                               std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT16(value.size, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.buffer) < value.size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.size; ++i) {
    result = Serialize_BYTE(value.buffer[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPM2B_SYM_KEY(std::string* buffer,
                           TPM2B_SYM_KEY* value,
                           std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT16(buffer, &value->size, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->buffer) < value->size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->size; ++i) {
    result = Parse_BYTE(buffer, &value->buffer[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM2B_SYM_KEY Make_TPM2B_SYM_KEY(const std::string& bytes) {
  TPM2B_SYM_KEY tpm2b;
  CHECK(bytes.size() <= sizeof(tpm2b.buffer));
  memset(&tpm2b, 0, sizeof(TPM2B_SYM_KEY));
  tpm2b.size = bytes.size();
  memcpy(tpm2b.buffer, bytes.data(), bytes.size());
  return tpm2b;
}

std::string StringFrom_TPM2B_SYM_KEY(const TPM2B_SYM_KEY& tpm2b) {
  const char* char_buffer = reinterpret_cast<const char*>(tpm2b.buffer);
  return std::string(char_buffer, tpm2b.size);
}

TPM_RC Serialize_TPMS_SYMCIPHER_PARMS(const TPMS_SYMCIPHER_PARMS& value,
                                      std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMT_SYM_DEF_OBJECT(value.sym, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_SYMCIPHER_PARMS(std::string* buffer,
                                  TPMS_SYMCIPHER_PARMS* value,
                                  std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMT_SYM_DEF_OBJECT(buffer, &value->sym, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPM2B_SENSITIVE_DATA(const TPM2B_SENSITIVE_DATA& value,
                                      std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT16(value.size, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.buffer) < value.size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.size; ++i) {
    result = Serialize_BYTE(value.buffer[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPM2B_SENSITIVE_DATA(std::string* buffer,
                                  TPM2B_SENSITIVE_DATA* value,
                                  std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT16(buffer, &value->size, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->buffer) < value->size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->size; ++i) {
    result = Parse_BYTE(buffer, &value->buffer[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM2B_SENSITIVE_DATA Make_TPM2B_SENSITIVE_DATA(const std::string& bytes) {
  TPM2B_SENSITIVE_DATA tpm2b;
  CHECK(bytes.size() <= sizeof(tpm2b.buffer));
  memset(&tpm2b, 0, sizeof(TPM2B_SENSITIVE_DATA));
  tpm2b.size = bytes.size();
  memcpy(tpm2b.buffer, bytes.data(), bytes.size());
  return tpm2b;
}

std::string StringFrom_TPM2B_SENSITIVE_DATA(const TPM2B_SENSITIVE_DATA& tpm2b) {
  const char* char_buffer = reinterpret_cast<const char*>(tpm2b.buffer);
  return std::string(char_buffer, tpm2b.size);
}

TPM_RC Serialize_TPMS_SENSITIVE_CREATE(const TPMS_SENSITIVE_CREATE& value,
                                       std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPM2B_AUTH(value.user_auth, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_SENSITIVE_DATA(value.data, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_SENSITIVE_CREATE(std::string* buffer,
                                   TPMS_SENSITIVE_CREATE* value,
                                   std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPM2B_AUTH(buffer, &value->user_auth, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_SENSITIVE_DATA(buffer, &value->data, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPM2B_SENSITIVE_CREATE(const TPM2B_SENSITIVE_CREATE& value,
                                        std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  std::string field_bytes;
  result = Serialize_TPMS_SENSITIVE_CREATE(value.sensitive, &field_bytes);
  if (result) {
    return result;
  }
  std::string size_bytes;
  result = Serialize_UINT16(field_bytes.size(), &size_bytes);
  if (result) {
    return result;
  }
  buffer->append(size_bytes + field_bytes);
  return result;
}

TPM_RC Parse_TPM2B_SENSITIVE_CREATE(std::string* buffer,
                                    TPM2B_SENSITIVE_CREATE* value,
                                    std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT16(buffer, &value->size, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMS_SENSITIVE_CREATE(buffer, &value->sensitive, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM2B_SENSITIVE_CREATE Make_TPM2B_SENSITIVE_CREATE(
    const TPMS_SENSITIVE_CREATE& inner) {
  TPM2B_SENSITIVE_CREATE tpm2b;
  tpm2b.size = sizeof(TPMS_SENSITIVE_CREATE);
  tpm2b.sensitive = inner;
  return tpm2b;
}

TPM_RC Serialize_TPMS_SCHEME_XOR(const TPMS_SCHEME_XOR& value,
                                 std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_ALG_HASH(value.hash_alg, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMI_ALG_KDF(value.kdf, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_SCHEME_XOR(std::string* buffer,
                             TPMS_SCHEME_XOR* value,
                             std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_ALG_HASH(buffer, &value->hash_alg, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMI_ALG_KDF(buffer, &value->kdf, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMU_SCHEME_KEYEDHASH(const TPMU_SCHEME_KEYEDHASH& value,
                                       TPMI_ALG_KEYEDHASH_SCHEME selector,
                                       std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  if (selector == TPM_ALG_NULL) {
    // Do nothing.
  }

  if (selector == TPM_ALG_HMAC) {
    result = Serialize_TPMS_SCHEME_HMAC(value.hmac, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_XOR) {
    result = Serialize_TPMS_SCHEME_XOR(value.xor_, buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPMU_SCHEME_KEYEDHASH(std::string* buffer,
                                   TPMI_ALG_KEYEDHASH_SCHEME selector,
                                   TPMU_SCHEME_KEYEDHASH* value,
                                   std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  if (selector == TPM_ALG_NULL) {
    // Do nothing.
  }

  if (selector == TPM_ALG_HMAC) {
    result = Parse_TPMS_SCHEME_HMAC(buffer, &value->hmac, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_XOR) {
    result = Parse_TPMS_SCHEME_XOR(buffer, &value->xor_, value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Serialize_TPMT_KEYEDHASH_SCHEME(const TPMT_KEYEDHASH_SCHEME& value,
                                       std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_ALG_KEYEDHASH_SCHEME(value.scheme, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMU_SCHEME_KEYEDHASH(value.details, value.scheme, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMT_KEYEDHASH_SCHEME(std::string* buffer,
                                   TPMT_KEYEDHASH_SCHEME* value,
                                   std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_ALG_KEYEDHASH_SCHEME(buffer, &value->scheme, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMU_SCHEME_KEYEDHASH(buffer, value->scheme, &value->details,
                                       value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMS_SCHEME_ECDAA(const TPMS_SCHEME_ECDAA& value,
                                   std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_ALG_HASH(value.hash_alg, buffer);
  if (result) {
    return result;
  }

  result = Serialize_UINT16(value.count, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_SCHEME_ECDAA(std::string* buffer,
                               TPMS_SCHEME_ECDAA* value,
                               std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_ALG_HASH(buffer, &value->hash_alg, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_UINT16(buffer, &value->count, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMU_SIG_SCHEME(const TPMU_SIG_SCHEME& value,
                                 TPMI_ALG_SIG_SCHEME selector,
                                 std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  if (selector == TPM_ALG_HMAC) {
    result = Serialize_TPMS_SCHEME_HMAC(value.hmac, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_ECSCHNORR) {
    result = Serialize_TPMS_SCHEME_ECSCHNORR(value.ec_schnorr, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_RSAPSS) {
    result = Serialize_TPMS_SCHEME_RSAPSS(value.rsapss, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_ECDAA) {
    result = Serialize_TPMS_SCHEME_ECDAA(value.ecdaa, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_RSASSA) {
    result = Serialize_TPMS_SCHEME_RSASSA(value.rsassa, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_SM2) {
    result = Serialize_TPMS_SCHEME_SM2(value.sm2, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_ECDSA) {
    result = Serialize_TPMS_SCHEME_ECDSA(value.ecdsa, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_NULL) {
    // Do nothing.
  }
  return result;
}

TPM_RC Parse_TPMU_SIG_SCHEME(std::string* buffer,
                             TPMI_ALG_SIG_SCHEME selector,
                             TPMU_SIG_SCHEME* value,
                             std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  if (selector == TPM_ALG_HMAC) {
    result = Parse_TPMS_SCHEME_HMAC(buffer, &value->hmac, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_ECSCHNORR) {
    result =
        Parse_TPMS_SCHEME_ECSCHNORR(buffer, &value->ec_schnorr, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_RSAPSS) {
    result = Parse_TPMS_SCHEME_RSAPSS(buffer, &value->rsapss, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_ECDAA) {
    result = Parse_TPMS_SCHEME_ECDAA(buffer, &value->ecdaa, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_RSASSA) {
    result = Parse_TPMS_SCHEME_RSASSA(buffer, &value->rsassa, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_SM2) {
    result = Parse_TPMS_SCHEME_SM2(buffer, &value->sm2, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_ECDSA) {
    result = Parse_TPMS_SCHEME_ECDSA(buffer, &value->ecdsa, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_NULL) {
    // Do nothing.
  }
  return result;
}

TPM_RC Serialize_TPMT_SIG_SCHEME(const TPMT_SIG_SCHEME& value,
                                 std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_ALG_SIG_SCHEME(value.scheme, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMU_SIG_SCHEME(value.details, value.scheme, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMT_SIG_SCHEME(std::string* buffer,
                             TPMT_SIG_SCHEME* value,
                             std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_ALG_SIG_SCHEME(buffer, &value->scheme, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMU_SIG_SCHEME(buffer, value->scheme, &value->details,
                                 value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMS_SCHEME_OAEP(const TPMS_SCHEME_OAEP& value,
                                  std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_ALG_HASH(value.hash_alg, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_SCHEME_OAEP(std::string* buffer,
                              TPMS_SCHEME_OAEP* value,
                              std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_ALG_HASH(buffer, &value->hash_alg, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMS_SCHEME_ECDH(const TPMS_SCHEME_ECDH& value,
                                  std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_ALG_HASH(value.hash_alg, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_SCHEME_ECDH(std::string* buffer,
                              TPMS_SCHEME_ECDH* value,
                              std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_ALG_HASH(buffer, &value->hash_alg, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMS_SCHEME_MGF1(const TPMS_SCHEME_MGF1& value,
                                  std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_ALG_HASH(value.hash_alg, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_SCHEME_MGF1(std::string* buffer,
                              TPMS_SCHEME_MGF1* value,
                              std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_ALG_HASH(buffer, &value->hash_alg, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMS_SCHEME_KDF1_SP800_56a(
    const TPMS_SCHEME_KDF1_SP800_56a& value,
    std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_ALG_HASH(value.hash_alg, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_SCHEME_KDF1_SP800_56a(std::string* buffer,
                                        TPMS_SCHEME_KDF1_SP800_56a* value,
                                        std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_ALG_HASH(buffer, &value->hash_alg, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMS_SCHEME_KDF2(const TPMS_SCHEME_KDF2& value,
                                  std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_ALG_HASH(value.hash_alg, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_SCHEME_KDF2(std::string* buffer,
                              TPMS_SCHEME_KDF2* value,
                              std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_ALG_HASH(buffer, &value->hash_alg, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMS_SCHEME_KDF1_SP800_108(
    const TPMS_SCHEME_KDF1_SP800_108& value,
    std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_ALG_HASH(value.hash_alg, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_SCHEME_KDF1_SP800_108(std::string* buffer,
                                        TPMS_SCHEME_KDF1_SP800_108* value,
                                        std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_ALG_HASH(buffer, &value->hash_alg, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMU_KDF_SCHEME(const TPMU_KDF_SCHEME& value,
                                 TPMI_ALG_KDF selector,
                                 std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  if (selector == TPM_ALG_KDF1_SP800_56a) {
    result = Serialize_TPMS_SCHEME_KDF1_SP800_56a(value.kdf1_sp800_56a, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_MGF1) {
    result = Serialize_TPMS_SCHEME_MGF1(value.mgf1, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_KDF1_SP800_108) {
    result = Serialize_TPMS_SCHEME_KDF1_SP800_108(value.kdf1_sp800_108, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_KDF2) {
    result = Serialize_TPMS_SCHEME_KDF2(value.kdf2, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_NULL) {
    // Do nothing.
  }
  return result;
}

TPM_RC Parse_TPMU_KDF_SCHEME(std::string* buffer,
                             TPMI_ALG_KDF selector,
                             TPMU_KDF_SCHEME* value,
                             std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  if (selector == TPM_ALG_KDF1_SP800_56a) {
    result = Parse_TPMS_SCHEME_KDF1_SP800_56a(buffer, &value->kdf1_sp800_56a,
                                              value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_MGF1) {
    result = Parse_TPMS_SCHEME_MGF1(buffer, &value->mgf1, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_KDF1_SP800_108) {
    result = Parse_TPMS_SCHEME_KDF1_SP800_108(buffer, &value->kdf1_sp800_108,
                                              value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_KDF2) {
    result = Parse_TPMS_SCHEME_KDF2(buffer, &value->kdf2, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_NULL) {
    // Do nothing.
  }
  return result;
}

TPM_RC Serialize_TPMT_KDF_SCHEME(const TPMT_KDF_SCHEME& value,
                                 std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_ALG_KDF(value.scheme, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMU_KDF_SCHEME(value.details, value.scheme, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMT_KDF_SCHEME(std::string* buffer,
                             TPMT_KDF_SCHEME* value,
                             std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_ALG_KDF(buffer, &value->scheme, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMU_KDF_SCHEME(buffer, value->scheme, &value->details,
                                 value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMU_ASYM_SCHEME(const TPMU_ASYM_SCHEME& value,
                                  TPMI_ALG_ASYM_SCHEME selector,
                                  std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  if (selector == TPM_ALG_RSAES) {
    // Do nothing.
  }

  if (selector == TPM_ALG_ECSCHNORR) {
    result = Serialize_TPMS_SCHEME_ECSCHNORR(value.ec_schnorr, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_NULL) {
    // Do nothing.
  }

  if (selector == TPM_ALG_ECDH) {
    result = Serialize_TPMS_SCHEME_ECDH(value.ecdh, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_OAEP) {
    result = Serialize_TPMS_SCHEME_OAEP(value.oaep, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_RSAPSS) {
    result = Serialize_TPMS_SCHEME_RSAPSS(value.rsapss, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_ECDAA) {
    result = Serialize_TPMS_SCHEME_ECDAA(value.ecdaa, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_RSASSA) {
    result = Serialize_TPMS_SCHEME_RSASSA(value.rsassa, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_SM2) {
    result = Serialize_TPMS_SCHEME_SM2(value.sm2, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_ECDSA) {
    result = Serialize_TPMS_SCHEME_ECDSA(value.ecdsa, buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPMU_ASYM_SCHEME(std::string* buffer,
                              TPMI_ALG_ASYM_SCHEME selector,
                              TPMU_ASYM_SCHEME* value,
                              std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  if (selector == TPM_ALG_RSAES) {
    // Do nothing.
  }

  if (selector == TPM_ALG_ECSCHNORR) {
    result =
        Parse_TPMS_SCHEME_ECSCHNORR(buffer, &value->ec_schnorr, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_NULL) {
    // Do nothing.
  }

  if (selector == TPM_ALG_ECDH) {
    result = Parse_TPMS_SCHEME_ECDH(buffer, &value->ecdh, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_OAEP) {
    result = Parse_TPMS_SCHEME_OAEP(buffer, &value->oaep, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_RSAPSS) {
    result = Parse_TPMS_SCHEME_RSAPSS(buffer, &value->rsapss, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_ECDAA) {
    result = Parse_TPMS_SCHEME_ECDAA(buffer, &value->ecdaa, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_RSASSA) {
    result = Parse_TPMS_SCHEME_RSASSA(buffer, &value->rsassa, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_SM2) {
    result = Parse_TPMS_SCHEME_SM2(buffer, &value->sm2, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_ECDSA) {
    result = Parse_TPMS_SCHEME_ECDSA(buffer, &value->ecdsa, value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Serialize_TPMT_ASYM_SCHEME(const TPMT_ASYM_SCHEME& value,
                                  std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_ALG_ASYM_SCHEME(value.scheme, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMU_ASYM_SCHEME(value.details, value.scheme, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMT_ASYM_SCHEME(std::string* buffer,
                              TPMT_ASYM_SCHEME* value,
                              std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_ALG_ASYM_SCHEME(buffer, &value->scheme, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMU_ASYM_SCHEME(buffer, value->scheme, &value->details,
                                  value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMT_RSA_SCHEME(const TPMT_RSA_SCHEME& value,
                                 std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_ALG_RSA_SCHEME(value.scheme, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMU_ASYM_SCHEME(value.details, value.scheme, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMT_RSA_SCHEME(std::string* buffer,
                             TPMT_RSA_SCHEME* value,
                             std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_ALG_RSA_SCHEME(buffer, &value->scheme, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMU_ASYM_SCHEME(buffer, value->scheme, &value->details,
                                  value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMT_RSA_DECRYPT(const TPMT_RSA_DECRYPT& value,
                                  std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_ALG_RSA_DECRYPT(value.scheme, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMU_ASYM_SCHEME(value.details, value.scheme, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMT_RSA_DECRYPT(std::string* buffer,
                              TPMT_RSA_DECRYPT* value,
                              std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_ALG_RSA_DECRYPT(buffer, &value->scheme, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMU_ASYM_SCHEME(buffer, value->scheme, &value->details,
                                  value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPM2B_PUBLIC_KEY_RSA(const TPM2B_PUBLIC_KEY_RSA& value,
                                      std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT16(value.size, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.buffer) < value.size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.size; ++i) {
    result = Serialize_BYTE(value.buffer[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPM2B_PUBLIC_KEY_RSA(std::string* buffer,
                                  TPM2B_PUBLIC_KEY_RSA* value,
                                  std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT16(buffer, &value->size, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->buffer) < value->size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->size; ++i) {
    result = Parse_BYTE(buffer, &value->buffer[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM2B_PUBLIC_KEY_RSA Make_TPM2B_PUBLIC_KEY_RSA(const std::string& bytes) {
  TPM2B_PUBLIC_KEY_RSA tpm2b;
  CHECK(bytes.size() <= sizeof(tpm2b.buffer));
  memset(&tpm2b, 0, sizeof(TPM2B_PUBLIC_KEY_RSA));
  tpm2b.size = bytes.size();
  memcpy(tpm2b.buffer, bytes.data(), bytes.size());
  return tpm2b;
}

std::string StringFrom_TPM2B_PUBLIC_KEY_RSA(const TPM2B_PUBLIC_KEY_RSA& tpm2b) {
  const char* char_buffer = reinterpret_cast<const char*>(tpm2b.buffer);
  return std::string(char_buffer, tpm2b.size);
}

TPM_RC Serialize_TPM2B_PRIVATE_KEY_RSA(const TPM2B_PRIVATE_KEY_RSA& value,
                                       std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT16(value.size, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.buffer) < value.size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.size; ++i) {
    result = Serialize_BYTE(value.buffer[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPM2B_PRIVATE_KEY_RSA(std::string* buffer,
                                   TPM2B_PRIVATE_KEY_RSA* value,
                                   std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT16(buffer, &value->size, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->buffer) < value->size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->size; ++i) {
    result = Parse_BYTE(buffer, &value->buffer[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM2B_PRIVATE_KEY_RSA Make_TPM2B_PRIVATE_KEY_RSA(const std::string& bytes) {
  TPM2B_PRIVATE_KEY_RSA tpm2b;
  CHECK(bytes.size() <= sizeof(tpm2b.buffer));
  memset(&tpm2b, 0, sizeof(TPM2B_PRIVATE_KEY_RSA));
  tpm2b.size = bytes.size();
  memcpy(tpm2b.buffer, bytes.data(), bytes.size());
  return tpm2b;
}

std::string StringFrom_TPM2B_PRIVATE_KEY_RSA(
    const TPM2B_PRIVATE_KEY_RSA& tpm2b) {
  const char* char_buffer = reinterpret_cast<const char*>(tpm2b.buffer);
  return std::string(char_buffer, tpm2b.size);
}

TPM_RC Serialize_TPM2B_ECC_PARAMETER(const TPM2B_ECC_PARAMETER& value,
                                     std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT16(value.size, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.buffer) < value.size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.size; ++i) {
    result = Serialize_BYTE(value.buffer[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPM2B_ECC_PARAMETER(std::string* buffer,
                                 TPM2B_ECC_PARAMETER* value,
                                 std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT16(buffer, &value->size, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->buffer) < value->size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->size; ++i) {
    result = Parse_BYTE(buffer, &value->buffer[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM2B_ECC_PARAMETER Make_TPM2B_ECC_PARAMETER(const std::string& bytes) {
  TPM2B_ECC_PARAMETER tpm2b;
  CHECK(bytes.size() <= sizeof(tpm2b.buffer));
  memset(&tpm2b, 0, sizeof(TPM2B_ECC_PARAMETER));
  tpm2b.size = bytes.size();
  memcpy(tpm2b.buffer, bytes.data(), bytes.size());
  return tpm2b;
}

std::string StringFrom_TPM2B_ECC_PARAMETER(const TPM2B_ECC_PARAMETER& tpm2b) {
  const char* char_buffer = reinterpret_cast<const char*>(tpm2b.buffer);
  return std::string(char_buffer, tpm2b.size);
}

TPM_RC Serialize_TPMS_ECC_POINT(const TPMS_ECC_POINT& value,
                                std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPM2B_ECC_PARAMETER(value.x, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_ECC_PARAMETER(value.y, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_ECC_POINT(std::string* buffer,
                            TPMS_ECC_POINT* value,
                            std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPM2B_ECC_PARAMETER(buffer, &value->x, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_ECC_PARAMETER(buffer, &value->y, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPM2B_ECC_POINT(const TPM2B_ECC_POINT& value,
                                 std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  std::string field_bytes;
  result = Serialize_TPMS_ECC_POINT(value.point, &field_bytes);
  if (result) {
    return result;
  }
  std::string size_bytes;
  result = Serialize_UINT16(field_bytes.size(), &size_bytes);
  if (result) {
    return result;
  }
  buffer->append(size_bytes + field_bytes);
  return result;
}

TPM_RC Parse_TPM2B_ECC_POINT(std::string* buffer,
                             TPM2B_ECC_POINT* value,
                             std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT16(buffer, &value->size, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMS_ECC_POINT(buffer, &value->point, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM2B_ECC_POINT Make_TPM2B_ECC_POINT(const TPMS_ECC_POINT& inner) {
  TPM2B_ECC_POINT tpm2b;
  tpm2b.size = sizeof(TPMS_ECC_POINT);
  tpm2b.point = inner;
  return tpm2b;
}

TPM_RC Serialize_TPMT_ECC_SCHEME(const TPMT_ECC_SCHEME& value,
                                 std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_ALG_ECC_SCHEME(value.scheme, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMU_SIG_SCHEME(value.details, value.scheme, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMT_ECC_SCHEME(std::string* buffer,
                             TPMT_ECC_SCHEME* value,
                             std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_ALG_ECC_SCHEME(buffer, &value->scheme, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMU_SIG_SCHEME(buffer, value->scheme, &value->details,
                                 value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMS_ALGORITHM_DETAIL_ECC(
    const TPMS_ALGORITHM_DETAIL_ECC& value,
    std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPM_ECC_CURVE(value.curve_id, buffer);
  if (result) {
    return result;
  }

  result = Serialize_UINT16(value.key_size, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMT_KDF_SCHEME(value.kdf, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMT_ECC_SCHEME(value.sign, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_ECC_PARAMETER(value.p, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_ECC_PARAMETER(value.a, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_ECC_PARAMETER(value.b, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_ECC_PARAMETER(value.g_x, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_ECC_PARAMETER(value.g_y, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_ECC_PARAMETER(value.n, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_ECC_PARAMETER(value.h, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_ALGORITHM_DETAIL_ECC(std::string* buffer,
                                       TPMS_ALGORITHM_DETAIL_ECC* value,
                                       std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPM_ECC_CURVE(buffer, &value->curve_id, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_UINT16(buffer, &value->key_size, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMT_KDF_SCHEME(buffer, &value->kdf, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMT_ECC_SCHEME(buffer, &value->sign, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_ECC_PARAMETER(buffer, &value->p, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_ECC_PARAMETER(buffer, &value->a, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_ECC_PARAMETER(buffer, &value->b, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_ECC_PARAMETER(buffer, &value->g_x, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_ECC_PARAMETER(buffer, &value->g_y, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_ECC_PARAMETER(buffer, &value->n, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_ECC_PARAMETER(buffer, &value->h, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMS_SIGNATURE_RSASSA(const TPMS_SIGNATURE_RSASSA& value,
                                       std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_ALG_HASH(value.hash, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_PUBLIC_KEY_RSA(value.sig, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_SIGNATURE_RSASSA(std::string* buffer,
                                   TPMS_SIGNATURE_RSASSA* value,
                                   std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_ALG_HASH(buffer, &value->hash, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_PUBLIC_KEY_RSA(buffer, &value->sig, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMS_SIGNATURE_RSAPSS(const TPMS_SIGNATURE_RSAPSS& value,
                                       std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_ALG_HASH(value.hash, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_PUBLIC_KEY_RSA(value.sig, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_SIGNATURE_RSAPSS(std::string* buffer,
                                   TPMS_SIGNATURE_RSAPSS* value,
                                   std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_ALG_HASH(buffer, &value->hash, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_PUBLIC_KEY_RSA(buffer, &value->sig, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMS_SIGNATURE_ECDSA(const TPMS_SIGNATURE_ECDSA& value,
                                      std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_ALG_HASH(value.hash, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_ECC_PARAMETER(value.signature_r, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_ECC_PARAMETER(value.signature_s, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_SIGNATURE_ECDSA(std::string* buffer,
                                  TPMS_SIGNATURE_ECDSA* value,
                                  std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_ALG_HASH(buffer, &value->hash, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_ECC_PARAMETER(buffer, &value->signature_r, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_ECC_PARAMETER(buffer, &value->signature_s, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMU_SIGNATURE(const TPMU_SIGNATURE& value,
                                TPMI_ALG_SIG_SCHEME selector,
                                std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  if (selector == TPM_ALG_HMAC) {
    result = Serialize_TPMT_HA(value.hmac, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_ECSCHNORR) {
    result = Serialize_TPMS_SIGNATURE_ECDSA(value.ecschnorr, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_RSAPSS) {
    result = Serialize_TPMS_SIGNATURE_RSAPSS(value.rsapss, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_ECDAA) {
    result = Serialize_TPMS_SIGNATURE_ECDSA(value.ecdaa, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_RSASSA) {
    result = Serialize_TPMS_SIGNATURE_RSASSA(value.rsassa, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_SM2) {
    result = Serialize_TPMS_SIGNATURE_ECDSA(value.sm2, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_ECDSA) {
    result = Serialize_TPMS_SIGNATURE_ECDSA(value.ecdsa, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_NULL) {
    // Do nothing.
  }
  return result;
}

TPM_RC Parse_TPMU_SIGNATURE(std::string* buffer,
                            TPMI_ALG_SIG_SCHEME selector,
                            TPMU_SIGNATURE* value,
                            std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  if (selector == TPM_ALG_HMAC) {
    result = Parse_TPMT_HA(buffer, &value->hmac, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_ECSCHNORR) {
    result = Parse_TPMS_SIGNATURE_ECDSA(buffer, &value->ecschnorr, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_RSAPSS) {
    result = Parse_TPMS_SIGNATURE_RSAPSS(buffer, &value->rsapss, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_ECDAA) {
    result = Parse_TPMS_SIGNATURE_ECDSA(buffer, &value->ecdaa, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_RSASSA) {
    result = Parse_TPMS_SIGNATURE_RSASSA(buffer, &value->rsassa, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_SM2) {
    result = Parse_TPMS_SIGNATURE_ECDSA(buffer, &value->sm2, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_ECDSA) {
    result = Parse_TPMS_SIGNATURE_ECDSA(buffer, &value->ecdsa, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_NULL) {
    // Do nothing.
  }
  return result;
}

TPM_RC Serialize_TPMT_SIGNATURE(const TPMT_SIGNATURE& value,
                                std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_ALG_SIG_SCHEME(value.sig_alg, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMU_SIGNATURE(value.signature, value.sig_alg, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMT_SIGNATURE(std::string* buffer,
                            TPMT_SIGNATURE* value,
                            std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_ALG_SIG_SCHEME(buffer, &value->sig_alg, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMU_SIGNATURE(buffer, value->sig_alg, &value->signature,
                                value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPM2B_ENCRYPTED_SECRET(const TPM2B_ENCRYPTED_SECRET& value,
                                        std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT16(value.size, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.secret) < value.size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.size; ++i) {
    result = Serialize_BYTE(value.secret[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPM2B_ENCRYPTED_SECRET(std::string* buffer,
                                    TPM2B_ENCRYPTED_SECRET* value,
                                    std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT16(buffer, &value->size, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->secret) < value->size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->size; ++i) {
    result = Parse_BYTE(buffer, &value->secret[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM2B_ENCRYPTED_SECRET Make_TPM2B_ENCRYPTED_SECRET(const std::string& bytes) {
  TPM2B_ENCRYPTED_SECRET tpm2b;
  CHECK(bytes.size() <= sizeof(tpm2b.secret));
  memset(&tpm2b, 0, sizeof(TPM2B_ENCRYPTED_SECRET));
  tpm2b.size = bytes.size();
  memcpy(tpm2b.secret, bytes.data(), bytes.size());
  return tpm2b;
}

std::string StringFrom_TPM2B_ENCRYPTED_SECRET(
    const TPM2B_ENCRYPTED_SECRET& tpm2b) {
  const char* char_buffer = reinterpret_cast<const char*>(tpm2b.secret);
  return std::string(char_buffer, tpm2b.size);
}

TPM_RC Serialize_TPMS_KEYEDHASH_PARMS(const TPMS_KEYEDHASH_PARMS& value,
                                      std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMT_KEYEDHASH_SCHEME(value.scheme, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_KEYEDHASH_PARMS(std::string* buffer,
                                  TPMS_KEYEDHASH_PARMS* value,
                                  std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMT_KEYEDHASH_SCHEME(buffer, &value->scheme, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMS_ASYM_PARMS(const TPMS_ASYM_PARMS& value,
                                 std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMT_SYM_DEF_OBJECT(value.symmetric, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMT_ASYM_SCHEME(value.scheme, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_ASYM_PARMS(std::string* buffer,
                             TPMS_ASYM_PARMS* value,
                             std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMT_SYM_DEF_OBJECT(buffer, &value->symmetric, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMT_ASYM_SCHEME(buffer, &value->scheme, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMS_RSA_PARMS(const TPMS_RSA_PARMS& value,
                                std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMT_SYM_DEF_OBJECT(value.symmetric, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMT_RSA_SCHEME(value.scheme, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMI_RSA_KEY_BITS(value.key_bits, buffer);
  if (result) {
    return result;
  }

  result = Serialize_UINT32(value.exponent, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_RSA_PARMS(std::string* buffer,
                            TPMS_RSA_PARMS* value,
                            std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMT_SYM_DEF_OBJECT(buffer, &value->symmetric, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMT_RSA_SCHEME(buffer, &value->scheme, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMI_RSA_KEY_BITS(buffer, &value->key_bits, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_UINT32(buffer, &value->exponent, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMS_ECC_PARMS(const TPMS_ECC_PARMS& value,
                                std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMT_SYM_DEF_OBJECT(value.symmetric, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMT_ECC_SCHEME(value.scheme, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMI_ECC_CURVE(value.curve_id, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMT_KDF_SCHEME(value.kdf, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_ECC_PARMS(std::string* buffer,
                            TPMS_ECC_PARMS* value,
                            std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMT_SYM_DEF_OBJECT(buffer, &value->symmetric, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMT_ECC_SCHEME(buffer, &value->scheme, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMI_ECC_CURVE(buffer, &value->curve_id, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMT_KDF_SCHEME(buffer, &value->kdf, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMU_PUBLIC_PARMS(const TPMU_PUBLIC_PARMS& value,
                                   TPMI_ALG_PUBLIC selector,
                                   std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  if (selector == TPM_ALG_KEYEDHASH) {
    result = Serialize_TPMS_KEYEDHASH_PARMS(value.keyed_hash_detail, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_RSA) {
    result = Serialize_TPMS_RSA_PARMS(value.rsa_detail, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_SYMCIPHER) {
    result = Serialize_TPMS_SYMCIPHER_PARMS(value.sym_detail, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_ECC) {
    result = Serialize_TPMS_ECC_PARMS(value.ecc_detail, buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPMU_PUBLIC_PARMS(std::string* buffer,
                               TPMI_ALG_PUBLIC selector,
                               TPMU_PUBLIC_PARMS* value,
                               std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  if (selector == TPM_ALG_KEYEDHASH) {
    result = Parse_TPMS_KEYEDHASH_PARMS(buffer, &value->keyed_hash_detail,
                                        value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_RSA) {
    result = Parse_TPMS_RSA_PARMS(buffer, &value->rsa_detail, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_SYMCIPHER) {
    result =
        Parse_TPMS_SYMCIPHER_PARMS(buffer, &value->sym_detail, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_ECC) {
    result = Parse_TPMS_ECC_PARMS(buffer, &value->ecc_detail, value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Serialize_TPMT_PUBLIC_PARMS(const TPMT_PUBLIC_PARMS& value,
                                   std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_ALG_PUBLIC(value.type, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMU_PUBLIC_PARMS(value.parameters, value.type, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMT_PUBLIC_PARMS(std::string* buffer,
                               TPMT_PUBLIC_PARMS* value,
                               std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_ALG_PUBLIC(buffer, &value->type, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMU_PUBLIC_PARMS(buffer, value->type, &value->parameters,
                                   value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMU_PUBLIC_ID(const TPMU_PUBLIC_ID& value,
                                TPMI_ALG_PUBLIC selector,
                                std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  if (selector == TPM_ALG_KEYEDHASH) {
    result = Serialize_TPM2B_DIGEST(value.keyed_hash, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_RSA) {
    result = Serialize_TPM2B_PUBLIC_KEY_RSA(value.rsa, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_SYMCIPHER) {
    result = Serialize_TPM2B_DIGEST(value.sym, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_ECC) {
    result = Serialize_TPMS_ECC_POINT(value.ecc, buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPMU_PUBLIC_ID(std::string* buffer,
                            TPMI_ALG_PUBLIC selector,
                            TPMU_PUBLIC_ID* value,
                            std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  if (selector == TPM_ALG_KEYEDHASH) {
    result = Parse_TPM2B_DIGEST(buffer, &value->keyed_hash, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_RSA) {
    result = Parse_TPM2B_PUBLIC_KEY_RSA(buffer, &value->rsa, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_SYMCIPHER) {
    result = Parse_TPM2B_DIGEST(buffer, &value->sym, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_ECC) {
    result = Parse_TPMS_ECC_POINT(buffer, &value->ecc, value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Serialize_TPMT_PUBLIC(const TPMT_PUBLIC& value, std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_ALG_PUBLIC(value.type, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMI_ALG_HASH(value.name_alg, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMA_OBJECT(value.object_attributes, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_DIGEST(value.auth_policy, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMU_PUBLIC_PARMS(value.parameters, value.type, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMU_PUBLIC_ID(value.unique, value.type, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMT_PUBLIC(std::string* buffer,
                         TPMT_PUBLIC* value,
                         std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_ALG_PUBLIC(buffer, &value->type, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMI_ALG_HASH(buffer, &value->name_alg, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMA_OBJECT(buffer, &value->object_attributes, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_DIGEST(buffer, &value->auth_policy, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMU_PUBLIC_PARMS(buffer, value->type, &value->parameters,
                                   value_bytes);
  if (result) {
    return result;
  }

  result =
      Parse_TPMU_PUBLIC_ID(buffer, value->type, &value->unique, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPM2B_PUBLIC(const TPM2B_PUBLIC& value, std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  std::string field_bytes;
  result = Serialize_TPMT_PUBLIC(value.public_area, &field_bytes);
  if (result) {
    return result;
  }
  std::string size_bytes;
  result = Serialize_UINT16(field_bytes.size(), &size_bytes);
  if (result) {
    return result;
  }
  buffer->append(size_bytes + field_bytes);
  return result;
}

TPM_RC Parse_TPM2B_PUBLIC(std::string* buffer,
                          TPM2B_PUBLIC* value,
                          std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT16(buffer, &value->size, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMT_PUBLIC(buffer, &value->public_area, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM2B_PUBLIC Make_TPM2B_PUBLIC(const TPMT_PUBLIC& inner) {
  TPM2B_PUBLIC tpm2b;
  tpm2b.size = sizeof(TPMT_PUBLIC);
  tpm2b.public_area = inner;
  return tpm2b;
}

TPM_RC Serialize_TPM2B_PRIVATE_VENDOR_SPECIFIC(
    const TPM2B_PRIVATE_VENDOR_SPECIFIC& value,
    std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT16(value.size, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.buffer) < value.size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.size; ++i) {
    result = Serialize_BYTE(value.buffer[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPM2B_PRIVATE_VENDOR_SPECIFIC(std::string* buffer,
                                           TPM2B_PRIVATE_VENDOR_SPECIFIC* value,
                                           std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT16(buffer, &value->size, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->buffer) < value->size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->size; ++i) {
    result = Parse_BYTE(buffer, &value->buffer[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM2B_PRIVATE_VENDOR_SPECIFIC Make_TPM2B_PRIVATE_VENDOR_SPECIFIC(
    const std::string& bytes) {
  TPM2B_PRIVATE_VENDOR_SPECIFIC tpm2b;
  CHECK(bytes.size() <= sizeof(tpm2b.buffer));
  memset(&tpm2b, 0, sizeof(TPM2B_PRIVATE_VENDOR_SPECIFIC));
  tpm2b.size = bytes.size();
  memcpy(tpm2b.buffer, bytes.data(), bytes.size());
  return tpm2b;
}

std::string StringFrom_TPM2B_PRIVATE_VENDOR_SPECIFIC(
    const TPM2B_PRIVATE_VENDOR_SPECIFIC& tpm2b) {
  const char* char_buffer = reinterpret_cast<const char*>(tpm2b.buffer);
  return std::string(char_buffer, tpm2b.size);
}

TPM_RC Serialize_TPMU_SENSITIVE_COMPOSITE(const TPMU_SENSITIVE_COMPOSITE& value,
                                          TPMI_ALG_PUBLIC selector,
                                          std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  if (selector == TPM_ALG_KEYEDHASH) {
    result = Serialize_TPM2B_SENSITIVE_DATA(value.bits, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_RSA) {
    result = Serialize_TPM2B_PRIVATE_KEY_RSA(value.rsa, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_SYMCIPHER) {
    result = Serialize_TPM2B_SYM_KEY(value.sym, buffer);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_ECC) {
    result = Serialize_TPM2B_ECC_PARAMETER(value.ecc, buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPMU_SENSITIVE_COMPOSITE(std::string* buffer,
                                      TPMI_ALG_PUBLIC selector,
                                      TPMU_SENSITIVE_COMPOSITE* value,
                                      std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  if (selector == TPM_ALG_KEYEDHASH) {
    result = Parse_TPM2B_SENSITIVE_DATA(buffer, &value->bits, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_RSA) {
    result = Parse_TPM2B_PRIVATE_KEY_RSA(buffer, &value->rsa, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_SYMCIPHER) {
    result = Parse_TPM2B_SYM_KEY(buffer, &value->sym, value_bytes);
    if (result) {
      return result;
    }
  }

  if (selector == TPM_ALG_ECC) {
    result = Parse_TPM2B_ECC_PARAMETER(buffer, &value->ecc, value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Serialize_TPMT_SENSITIVE(const TPMT_SENSITIVE& value,
                                std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_ALG_PUBLIC(value.sensitive_type, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_AUTH(value.auth_value, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_DIGEST(value.seed_value, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMU_SENSITIVE_COMPOSITE(value.sensitive,
                                              value.sensitive_type, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMT_SENSITIVE(std::string* buffer,
                            TPMT_SENSITIVE* value,
                            std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_ALG_PUBLIC(buffer, &value->sensitive_type, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_AUTH(buffer, &value->auth_value, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_DIGEST(buffer, &value->seed_value, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMU_SENSITIVE_COMPOSITE(buffer, value->sensitive_type,
                                          &value->sensitive, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPM2B_SENSITIVE(const TPM2B_SENSITIVE& value,
                                 std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  std::string field_bytes;
  result = Serialize_TPMT_SENSITIVE(value.sensitive_area, &field_bytes);
  if (result) {
    return result;
  }
  std::string size_bytes;
  result = Serialize_UINT16(field_bytes.size(), &size_bytes);
  if (result) {
    return result;
  }
  buffer->append(size_bytes + field_bytes);
  return result;
}

TPM_RC Parse_TPM2B_SENSITIVE(std::string* buffer,
                             TPM2B_SENSITIVE* value,
                             std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT16(buffer, &value->size, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMT_SENSITIVE(buffer, &value->sensitive_area, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM2B_SENSITIVE Make_TPM2B_SENSITIVE(const TPMT_SENSITIVE& inner) {
  TPM2B_SENSITIVE tpm2b;
  tpm2b.size = sizeof(TPMT_SENSITIVE);
  tpm2b.sensitive_area = inner;
  return tpm2b;
}

TPM_RC Serialize__PRIVATE(const _PRIVATE& value, std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPM2B_DIGEST(value.integrity_outer, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_DIGEST(value.integrity_inner, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMT_SENSITIVE(value.sensitive, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse__PRIVATE(std::string* buffer,
                      _PRIVATE* value,
                      std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPM2B_DIGEST(buffer, &value->integrity_outer, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_DIGEST(buffer, &value->integrity_inner, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMT_SENSITIVE(buffer, &value->sensitive, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPM2B_PRIVATE(const TPM2B_PRIVATE& value,
                               std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT16(value.size, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.buffer) < value.size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.size; ++i) {
    result = Serialize_BYTE(value.buffer[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPM2B_PRIVATE(std::string* buffer,
                           TPM2B_PRIVATE* value,
                           std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT16(buffer, &value->size, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->buffer) < value->size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->size; ++i) {
    result = Parse_BYTE(buffer, &value->buffer[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM2B_PRIVATE Make_TPM2B_PRIVATE(const std::string& bytes) {
  TPM2B_PRIVATE tpm2b;
  CHECK(bytes.size() <= sizeof(tpm2b.buffer));
  memset(&tpm2b, 0, sizeof(TPM2B_PRIVATE));
  tpm2b.size = bytes.size();
  memcpy(tpm2b.buffer, bytes.data(), bytes.size());
  return tpm2b;
}

std::string StringFrom_TPM2B_PRIVATE(const TPM2B_PRIVATE& tpm2b) {
  const char* char_buffer = reinterpret_cast<const char*>(tpm2b.buffer);
  return std::string(char_buffer, tpm2b.size);
}

TPM_RC Serialize__ID_OBJECT(const _ID_OBJECT& value, std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPM2B_DIGEST(value.integrity_hmac, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_DIGEST(value.enc_identity, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse__ID_OBJECT(std::string* buffer,
                        _ID_OBJECT* value,
                        std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPM2B_DIGEST(buffer, &value->integrity_hmac, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_DIGEST(buffer, &value->enc_identity, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPM2B_ID_OBJECT(const TPM2B_ID_OBJECT& value,
                                 std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT16(value.size, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.credential) < value.size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.size; ++i) {
    result = Serialize_BYTE(value.credential[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPM2B_ID_OBJECT(std::string* buffer,
                             TPM2B_ID_OBJECT* value,
                             std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT16(buffer, &value->size, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->credential) < value->size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->size; ++i) {
    result = Parse_BYTE(buffer, &value->credential[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM2B_ID_OBJECT Make_TPM2B_ID_OBJECT(const std::string& bytes) {
  TPM2B_ID_OBJECT tpm2b;
  CHECK(bytes.size() <= sizeof(tpm2b.credential));
  memset(&tpm2b, 0, sizeof(TPM2B_ID_OBJECT));
  tpm2b.size = bytes.size();
  memcpy(tpm2b.credential, bytes.data(), bytes.size());
  return tpm2b;
}

std::string StringFrom_TPM2B_ID_OBJECT(const TPM2B_ID_OBJECT& tpm2b) {
  const char* char_buffer = reinterpret_cast<const char*>(tpm2b.credential);
  return std::string(char_buffer, tpm2b.size);
}

TPM_RC Serialize_TPMS_NV_PUBLIC(const TPMS_NV_PUBLIC& value,
                                std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPMI_RH_NV_INDEX(value.nv_index, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMI_ALG_HASH(value.name_alg, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMA_NV(value.attributes, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_DIGEST(value.auth_policy, buffer);
  if (result) {
    return result;
  }

  result = Serialize_UINT16(value.data_size, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_NV_PUBLIC(std::string* buffer,
                            TPMS_NV_PUBLIC* value,
                            std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPMI_RH_NV_INDEX(buffer, &value->nv_index, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMI_ALG_HASH(buffer, &value->name_alg, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMA_NV(buffer, &value->attributes, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_DIGEST(buffer, &value->auth_policy, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_UINT16(buffer, &value->data_size, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPM2B_NV_PUBLIC(const TPM2B_NV_PUBLIC& value,
                                 std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  std::string field_bytes;
  result = Serialize_TPMS_NV_PUBLIC(value.nv_public, &field_bytes);
  if (result) {
    return result;
  }
  std::string size_bytes;
  result = Serialize_UINT16(field_bytes.size(), &size_bytes);
  if (result) {
    return result;
  }
  buffer->append(size_bytes + field_bytes);
  return result;
}

TPM_RC Parse_TPM2B_NV_PUBLIC(std::string* buffer,
                             TPM2B_NV_PUBLIC* value,
                             std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT16(buffer, &value->size, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMS_NV_PUBLIC(buffer, &value->nv_public, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM2B_NV_PUBLIC Make_TPM2B_NV_PUBLIC(const TPMS_NV_PUBLIC& inner) {
  TPM2B_NV_PUBLIC tpm2b;
  tpm2b.size = sizeof(TPMS_NV_PUBLIC);
  tpm2b.nv_public = inner;
  return tpm2b;
}

TPM_RC Serialize_TPM2B_CONTEXT_SENSITIVE(const TPM2B_CONTEXT_SENSITIVE& value,
                                         std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT16(value.size, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.buffer) < value.size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.size; ++i) {
    result = Serialize_BYTE(value.buffer[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPM2B_CONTEXT_SENSITIVE(std::string* buffer,
                                     TPM2B_CONTEXT_SENSITIVE* value,
                                     std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT16(buffer, &value->size, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->buffer) < value->size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->size; ++i) {
    result = Parse_BYTE(buffer, &value->buffer[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM2B_CONTEXT_SENSITIVE Make_TPM2B_CONTEXT_SENSITIVE(const std::string& bytes) {
  TPM2B_CONTEXT_SENSITIVE tpm2b;
  CHECK(bytes.size() <= sizeof(tpm2b.buffer));
  memset(&tpm2b, 0, sizeof(TPM2B_CONTEXT_SENSITIVE));
  tpm2b.size = bytes.size();
  memcpy(tpm2b.buffer, bytes.data(), bytes.size());
  return tpm2b;
}

std::string StringFrom_TPM2B_CONTEXT_SENSITIVE(
    const TPM2B_CONTEXT_SENSITIVE& tpm2b) {
  const char* char_buffer = reinterpret_cast<const char*>(tpm2b.buffer);
  return std::string(char_buffer, tpm2b.size);
}

TPM_RC Serialize_TPMS_CONTEXT_DATA(const TPMS_CONTEXT_DATA& value,
                                   std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPM2B_DIGEST(value.integrity, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_CONTEXT_SENSITIVE(value.encrypted, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_CONTEXT_DATA(std::string* buffer,
                               TPMS_CONTEXT_DATA* value,
                               std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPM2B_DIGEST(buffer, &value->integrity, value_bytes);
  if (result) {
    return result;
  }

  result =
      Parse_TPM2B_CONTEXT_SENSITIVE(buffer, &value->encrypted, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPM2B_CONTEXT_DATA(const TPM2B_CONTEXT_DATA& value,
                                    std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT16(value.size, buffer);
  if (result) {
    return result;
  }

  if (arraysize(value.buffer) < value.size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value.size; ++i) {
    result = Serialize_BYTE(value.buffer[i], buffer);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM_RC Parse_TPM2B_CONTEXT_DATA(std::string* buffer,
                                TPM2B_CONTEXT_DATA* value,
                                std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT16(buffer, &value->size, value_bytes);
  if (result) {
    return result;
  }

  if (arraysize(value->buffer) < value->size) {
    return TPM_RC_INSUFFICIENT;
  }
  for (uint32_t i = 0; i < value->size; ++i) {
    result = Parse_BYTE(buffer, &value->buffer[i], value_bytes);
    if (result) {
      return result;
    }
  }
  return result;
}

TPM2B_CONTEXT_DATA Make_TPM2B_CONTEXT_DATA(const std::string& bytes) {
  TPM2B_CONTEXT_DATA tpm2b;
  CHECK(bytes.size() <= sizeof(tpm2b.buffer));
  memset(&tpm2b, 0, sizeof(TPM2B_CONTEXT_DATA));
  tpm2b.size = bytes.size();
  memcpy(tpm2b.buffer, bytes.data(), bytes.size());
  return tpm2b;
}

std::string StringFrom_TPM2B_CONTEXT_DATA(const TPM2B_CONTEXT_DATA& tpm2b) {
  const char* char_buffer = reinterpret_cast<const char*>(tpm2b.buffer);
  return std::string(char_buffer, tpm2b.size);
}

TPM_RC Serialize_TPMS_CONTEXT(const TPMS_CONTEXT& value, std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_UINT64(value.sequence, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMI_DH_CONTEXT(value.saved_handle, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMI_RH_HIERARCHY(value.hierarchy, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_CONTEXT_DATA(value.context_blob, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_CONTEXT(std::string* buffer,
                          TPMS_CONTEXT* value,
                          std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT64(buffer, &value->sequence, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMI_DH_CONTEXT(buffer, &value->saved_handle, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMI_RH_HIERARCHY(buffer, &value->hierarchy, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_CONTEXT_DATA(buffer, &value->context_blob, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPMS_CREATION_DATA(const TPMS_CREATION_DATA& value,
                                    std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Serialize_TPML_PCR_SELECTION(value.pcr_select, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_DIGEST(value.pcr_digest, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPMA_LOCALITY(value.locality, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM_ALG_ID(value.parent_name_alg, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_NAME(value.parent_name, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_NAME(value.parent_qualified_name, buffer);
  if (result) {
    return result;
  }

  result = Serialize_TPM2B_DATA(value.outside_info, buffer);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Parse_TPMS_CREATION_DATA(std::string* buffer,
                                TPMS_CREATION_DATA* value,
                                std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_TPML_PCR_SELECTION(buffer, &value->pcr_select, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_DIGEST(buffer, &value->pcr_digest, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMA_LOCALITY(buffer, &value->locality, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM_ALG_ID(buffer, &value->parent_name_alg, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_NAME(buffer, &value->parent_name, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_NAME(buffer, &value->parent_qualified_name, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPM2B_DATA(buffer, &value->outside_info, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM_RC Serialize_TPM2B_CREATION_DATA(const TPM2B_CREATION_DATA& value,
                                     std::string* buffer) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  std::string field_bytes;
  result = Serialize_TPMS_CREATION_DATA(value.creation_data, &field_bytes);
  if (result) {
    return result;
  }
  std::string size_bytes;
  result = Serialize_UINT16(field_bytes.size(), &size_bytes);
  if (result) {
    return result;
  }
  buffer->append(size_bytes + field_bytes);
  return result;
}

TPM_RC Parse_TPM2B_CREATION_DATA(std::string* buffer,
                                 TPM2B_CREATION_DATA* value,
                                 std::string* value_bytes) {
  TPM_RC result = TPM_RC_SUCCESS;
  VLOG(3) << __func__;

  result = Parse_UINT16(buffer, &value->size, value_bytes);
  if (result) {
    return result;
  }

  result = Parse_TPMS_CREATION_DATA(buffer, &value->creation_data, value_bytes);
  if (result) {
    return result;
  }
  return result;
}

TPM2B_CREATION_DATA Make_TPM2B_CREATION_DATA(const TPMS_CREATION_DATA& inner) {
  TPM2B_CREATION_DATA tpm2b;
  tpm2b.size = sizeof(TPMS_CREATION_DATA);
  tpm2b.creation_data = inner;
  return tpm2b;
}

TPM_RC Tpm::SerializeCommand_Startup(
    const TPM_SU& startup_type,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_Startup;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string startup_type_bytes;
  rc = Serialize_TPM_SU(startup_type, &startup_type_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(startup_type_bytes.data(), startup_type_bytes.size());
  parameter_section_bytes += startup_type_bytes;
  command_size += startup_type_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_Startup(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_Startup;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void StartupErrorCallback(const Tpm::StartupResponse& callback,
                          TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void StartupResponseParser(const Tpm::StartupResponse& callback,
                           AuthorizationDelegate* authorization_delegate,
                           const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(StartupErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_Startup(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::Startup(const TPM_SU& startup_type,
                  AuthorizationDelegate* authorization_delegate,
                  const StartupResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(StartupErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(StartupResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc =
      SerializeCommand_Startup(startup_type, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::StartupSync(const TPM_SU& startup_type,
                        AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc =
      SerializeCommand_Startup(startup_type, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_Startup(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_Shutdown(
    const TPM_SU& shutdown_type,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_Shutdown;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string shutdown_type_bytes;
  rc = Serialize_TPM_SU(shutdown_type, &shutdown_type_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(shutdown_type_bytes.data(), shutdown_type_bytes.size());
  parameter_section_bytes += shutdown_type_bytes;
  command_size += shutdown_type_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_Shutdown(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_Shutdown;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void ShutdownErrorCallback(const Tpm::ShutdownResponse& callback,
                           TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void ShutdownResponseParser(const Tpm::ShutdownResponse& callback,
                            AuthorizationDelegate* authorization_delegate,
                            const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ShutdownErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_Shutdown(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::Shutdown(const TPM_SU& shutdown_type,
                   AuthorizationDelegate* authorization_delegate,
                   const ShutdownResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ShutdownErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(ShutdownResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_Shutdown(shutdown_type, &command,
                                        authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::ShutdownSync(const TPM_SU& shutdown_type,
                         AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_Shutdown(shutdown_type, &command,
                                        authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_Shutdown(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_SelfTest(
    const TPMI_YES_NO& full_test,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_SelfTest;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string full_test_bytes;
  rc = Serialize_TPMI_YES_NO(full_test, &full_test_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(full_test_bytes.data(), full_test_bytes.size());
  parameter_section_bytes += full_test_bytes;
  command_size += full_test_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_SelfTest(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_SelfTest;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void SelfTestErrorCallback(const Tpm::SelfTestResponse& callback,
                           TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void SelfTestResponseParser(const Tpm::SelfTestResponse& callback,
                            AuthorizationDelegate* authorization_delegate,
                            const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(SelfTestErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_SelfTest(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::SelfTest(const TPMI_YES_NO& full_test,
                   AuthorizationDelegate* authorization_delegate,
                   const SelfTestResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(SelfTestErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(SelfTestResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc =
      SerializeCommand_SelfTest(full_test, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::SelfTestSync(const TPMI_YES_NO& full_test,
                         AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc =
      SerializeCommand_SelfTest(full_test, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_SelfTest(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_IncrementalSelfTest(
    const TPML_ALG& to_test,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_IncrementalSelfTest;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string to_test_bytes;
  rc = Serialize_TPML_ALG(to_test, &to_test_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(to_test_bytes.data(), to_test_bytes.size());
  parameter_section_bytes += to_test_bytes;
  command_size += to_test_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_IncrementalSelfTest(
    const std::string& response,
    TPML_ALG* to_do_list,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_IncrementalSelfTest;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string to_do_list_bytes;
  rc = Parse_TPML_ALG(&buffer, to_do_list, &to_do_list_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  return TPM_RC_SUCCESS;
}

void IncrementalSelfTestErrorCallback(
    const Tpm::IncrementalSelfTestResponse& callback,
    TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPML_ALG());
}

void IncrementalSelfTestResponseParser(
    const Tpm::IncrementalSelfTestResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(IncrementalSelfTestErrorCallback, callback);
  TPML_ALG to_do_list;
  TPM_RC rc = Tpm::ParseResponse_IncrementalSelfTest(response, &to_do_list,
                                                     authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, to_do_list);
}

void Tpm::IncrementalSelfTest(const TPML_ALG& to_test,
                              AuthorizationDelegate* authorization_delegate,
                              const IncrementalSelfTestResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(IncrementalSelfTestErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      IncrementalSelfTestResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_IncrementalSelfTest(to_test, &command,
                                                   authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::IncrementalSelfTestSync(
    const TPML_ALG& to_test,
    TPML_ALG* to_do_list,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_IncrementalSelfTest(to_test, &command,
                                                   authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_IncrementalSelfTest(response, to_do_list,
                                         authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_GetTestResult(
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_GetTestResult;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_GetTestResult(
    const std::string& response,
    TPM2B_MAX_BUFFER* out_data,
    TPM_RC* test_result,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_GetTestResult;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string out_data_bytes;
  rc = Parse_TPM2B_MAX_BUFFER(&buffer, out_data, &out_data_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string test_result_bytes;
  rc = Parse_TPM_RC(&buffer, test_result, &test_result_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = out_data_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    out_data_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_MAX_BUFFER(&out_data_bytes, out_data, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void GetTestResultErrorCallback(const Tpm::GetTestResultResponse& callback,
                                TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_MAX_BUFFER(), TPM_RC());
}

void GetTestResultResponseParser(const Tpm::GetTestResultResponse& callback,
                                 AuthorizationDelegate* authorization_delegate,
                                 const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(GetTestResultErrorCallback, callback);
  TPM2B_MAX_BUFFER out_data;
  TPM_RC test_result;
  TPM_RC rc = Tpm::ParseResponse_GetTestResult(
      response, &out_data, &test_result, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, out_data, test_result);
}

void Tpm::GetTestResult(AuthorizationDelegate* authorization_delegate,
                        const GetTestResultResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(GetTestResultErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(GetTestResultResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_GetTestResult(&command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::GetTestResultSync(TPM2B_MAX_BUFFER* out_data,
                              TPM_RC* test_result,
                              AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_GetTestResult(&command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_GetTestResult(response, out_data, test_result,
                                   authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_StartAuthSession(
    const TPMI_DH_OBJECT& tpm_key,
    const std::string& tpm_key_name,
    const TPMI_DH_ENTITY& bind,
    const std::string& bind_name,
    const TPM2B_NONCE& nonce_caller,
    const TPM2B_ENCRYPTED_SECRET& encrypted_salt,
    const TPM_SE& session_type,
    const TPMT_SYM_DEF& symmetric,
    const TPMI_ALG_HASH& auth_hash,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_StartAuthSession;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string tpm_key_bytes;
  rc = Serialize_TPMI_DH_OBJECT(tpm_key, &tpm_key_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string bind_bytes;
  rc = Serialize_TPMI_DH_ENTITY(bind, &bind_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string nonce_caller_bytes;
  rc = Serialize_TPM2B_NONCE(nonce_caller, &nonce_caller_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string encrypted_salt_bytes;
  rc = Serialize_TPM2B_ENCRYPTED_SECRET(encrypted_salt, &encrypted_salt_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string session_type_bytes;
  rc = Serialize_TPM_SE(session_type, &session_type_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string symmetric_bytes;
  rc = Serialize_TPMT_SYM_DEF(symmetric, &symmetric_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_hash_bytes;
  rc = Serialize_TPMI_ALG_HASH(auth_hash, &auth_hash_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = nonce_caller_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    nonce_caller_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(tpm_key_name.data(), tpm_key_name.size());
  handle_section_bytes += tpm_key_bytes;
  command_size += tpm_key_bytes.size();
  hash->Update(bind_name.data(), bind_name.size());
  handle_section_bytes += bind_bytes;
  command_size += bind_bytes.size();
  hash->Update(nonce_caller_bytes.data(), nonce_caller_bytes.size());
  parameter_section_bytes += nonce_caller_bytes;
  command_size += nonce_caller_bytes.size();
  hash->Update(encrypted_salt_bytes.data(), encrypted_salt_bytes.size());
  parameter_section_bytes += encrypted_salt_bytes;
  command_size += encrypted_salt_bytes.size();
  hash->Update(session_type_bytes.data(), session_type_bytes.size());
  parameter_section_bytes += session_type_bytes;
  command_size += session_type_bytes.size();
  hash->Update(symmetric_bytes.data(), symmetric_bytes.size());
  parameter_section_bytes += symmetric_bytes;
  command_size += symmetric_bytes.size();
  hash->Update(auth_hash_bytes.data(), auth_hash_bytes.size());
  parameter_section_bytes += auth_hash_bytes;
  command_size += auth_hash_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_StartAuthSession(
    const std::string& response,
    TPMI_SH_AUTH_SESSION* session_handle,
    TPM2B_NONCE* nonce_tpm,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  std::string session_handle_bytes;
  rc = Parse_TPMI_SH_AUTH_SESSION(&buffer, session_handle,
                                  &session_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_CC command_code = TPM_CC_StartAuthSession;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string nonce_tpm_bytes;
  rc = Parse_TPM2B_NONCE(&buffer, nonce_tpm, &nonce_tpm_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = nonce_tpm_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    nonce_tpm_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_NONCE(&nonce_tpm_bytes, nonce_tpm, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void StartAuthSessionErrorCallback(
    const Tpm::StartAuthSessionResponse& callback,
    TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPMI_SH_AUTH_SESSION(), TPM2B_NONCE());
}

void StartAuthSessionResponseParser(
    const Tpm::StartAuthSessionResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(StartAuthSessionErrorCallback, callback);
  TPMI_SH_AUTH_SESSION session_handle;
  TPM2B_NONCE nonce_tpm;
  TPM_RC rc = Tpm::ParseResponse_StartAuthSession(
      response, &session_handle, &nonce_tpm, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, session_handle, nonce_tpm);
}

void Tpm::StartAuthSession(const TPMI_DH_OBJECT& tpm_key,
                           const std::string& tpm_key_name,
                           const TPMI_DH_ENTITY& bind,
                           const std::string& bind_name,
                           const TPM2B_NONCE& nonce_caller,
                           const TPM2B_ENCRYPTED_SECRET& encrypted_salt,
                           const TPM_SE& session_type,
                           const TPMT_SYM_DEF& symmetric,
                           const TPMI_ALG_HASH& auth_hash,
                           AuthorizationDelegate* authorization_delegate,
                           const StartAuthSessionResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(StartAuthSessionErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      StartAuthSessionResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_StartAuthSession(
      tpm_key, tpm_key_name, bind, bind_name, nonce_caller, encrypted_salt,
      session_type, symmetric, auth_hash, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::StartAuthSessionSync(
    const TPMI_DH_OBJECT& tpm_key,
    const std::string& tpm_key_name,
    const TPMI_DH_ENTITY& bind,
    const std::string& bind_name,
    const TPM2B_NONCE& nonce_caller,
    const TPM2B_ENCRYPTED_SECRET& encrypted_salt,
    const TPM_SE& session_type,
    const TPMT_SYM_DEF& symmetric,
    const TPMI_ALG_HASH& auth_hash,
    TPMI_SH_AUTH_SESSION* session_handle,
    TPM2B_NONCE* nonce_tpm,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_StartAuthSession(
      tpm_key, tpm_key_name, bind, bind_name, nonce_caller, encrypted_salt,
      session_type, symmetric, auth_hash, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_StartAuthSession(response, session_handle, nonce_tpm,
                                      authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_PolicyRestart(
    const TPMI_SH_POLICY& session_handle,
    const std::string& session_handle_name,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_PolicyRestart;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string session_handle_bytes;
  rc = Serialize_TPMI_SH_POLICY(session_handle, &session_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(session_handle_name.data(), session_handle_name.size());
  handle_section_bytes += session_handle_bytes;
  command_size += session_handle_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_PolicyRestart(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_PolicyRestart;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void PolicyRestartErrorCallback(const Tpm::PolicyRestartResponse& callback,
                                TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void PolicyRestartResponseParser(const Tpm::PolicyRestartResponse& callback,
                                 AuthorizationDelegate* authorization_delegate,
                                 const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyRestartErrorCallback, callback);
  TPM_RC rc =
      Tpm::ParseResponse_PolicyRestart(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::PolicyRestart(const TPMI_SH_POLICY& session_handle,
                        const std::string& session_handle_name,
                        AuthorizationDelegate* authorization_delegate,
                        const PolicyRestartResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyRestartErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(PolicyRestartResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyRestart(
      session_handle, session_handle_name, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::PolicyRestartSync(const TPMI_SH_POLICY& session_handle,
                              const std::string& session_handle_name,
                              AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyRestart(
      session_handle, session_handle_name, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_PolicyRestart(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_Create(
    const TPMI_DH_OBJECT& parent_handle,
    const std::string& parent_handle_name,
    const TPM2B_SENSITIVE_CREATE& in_sensitive,
    const TPM2B_PUBLIC& in_public,
    const TPM2B_DATA& outside_info,
    const TPML_PCR_SELECTION& creation_pcr,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_Create;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string parent_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(parent_handle, &parent_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string in_sensitive_bytes;
  rc = Serialize_TPM2B_SENSITIVE_CREATE(in_sensitive, &in_sensitive_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string in_public_bytes;
  rc = Serialize_TPM2B_PUBLIC(in_public, &in_public_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string outside_info_bytes;
  rc = Serialize_TPM2B_DATA(outside_info, &outside_info_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string creation_pcr_bytes;
  rc = Serialize_TPML_PCR_SELECTION(creation_pcr, &creation_pcr_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = in_sensitive_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    in_sensitive_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(parent_handle_name.data(), parent_handle_name.size());
  handle_section_bytes += parent_handle_bytes;
  command_size += parent_handle_bytes.size();
  hash->Update(in_sensitive_bytes.data(), in_sensitive_bytes.size());
  parameter_section_bytes += in_sensitive_bytes;
  command_size += in_sensitive_bytes.size();
  hash->Update(in_public_bytes.data(), in_public_bytes.size());
  parameter_section_bytes += in_public_bytes;
  command_size += in_public_bytes.size();
  hash->Update(outside_info_bytes.data(), outside_info_bytes.size());
  parameter_section_bytes += outside_info_bytes;
  command_size += outside_info_bytes.size();
  hash->Update(creation_pcr_bytes.data(), creation_pcr_bytes.size());
  parameter_section_bytes += creation_pcr_bytes;
  command_size += creation_pcr_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_Create(
    const std::string& response,
    TPM2B_PRIVATE* out_private,
    TPM2B_PUBLIC* out_public,
    TPM2B_CREATION_DATA* creation_data,
    TPM2B_DIGEST* creation_hash,
    TPMT_TK_CREATION* creation_ticket,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_Create;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string out_private_bytes;
  rc = Parse_TPM2B_PRIVATE(&buffer, out_private, &out_private_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string out_public_bytes;
  rc = Parse_TPM2B_PUBLIC(&buffer, out_public, &out_public_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string creation_data_bytes;
  rc = Parse_TPM2B_CREATION_DATA(&buffer, creation_data, &creation_data_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string creation_hash_bytes;
  rc = Parse_TPM2B_DIGEST(&buffer, creation_hash, &creation_hash_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string creation_ticket_bytes;
  rc = Parse_TPMT_TK_CREATION(&buffer, creation_ticket, &creation_ticket_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = out_private_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    out_private_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_PRIVATE(&out_private_bytes, out_private, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void CreateErrorCallback(const Tpm::CreateResponse& callback,
                         TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_PRIVATE(), TPM2B_PUBLIC(),
               TPM2B_CREATION_DATA(), TPM2B_DIGEST(), TPMT_TK_CREATION());
}

void CreateResponseParser(const Tpm::CreateResponse& callback,
                          AuthorizationDelegate* authorization_delegate,
                          const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(CreateErrorCallback, callback);
  TPM2B_PRIVATE out_private;
  TPM2B_PUBLIC out_public;
  TPM2B_CREATION_DATA creation_data;
  TPM2B_DIGEST creation_hash;
  TPMT_TK_CREATION creation_ticket;
  TPM_RC rc = Tpm::ParseResponse_Create(
      response, &out_private, &out_public, &creation_data, &creation_hash,
      &creation_ticket, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, out_private, out_public, creation_data, creation_hash,
               creation_ticket);
}

void Tpm::Create(const TPMI_DH_OBJECT& parent_handle,
                 const std::string& parent_handle_name,
                 const TPM2B_SENSITIVE_CREATE& in_sensitive,
                 const TPM2B_PUBLIC& in_public,
                 const TPM2B_DATA& outside_info,
                 const TPML_PCR_SELECTION& creation_pcr,
                 AuthorizationDelegate* authorization_delegate,
                 const CreateResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(CreateErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(CreateResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_Create(
      parent_handle, parent_handle_name, in_sensitive, in_public, outside_info,
      creation_pcr, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::CreateSync(const TPMI_DH_OBJECT& parent_handle,
                       const std::string& parent_handle_name,
                       const TPM2B_SENSITIVE_CREATE& in_sensitive,
                       const TPM2B_PUBLIC& in_public,
                       const TPM2B_DATA& outside_info,
                       const TPML_PCR_SELECTION& creation_pcr,
                       TPM2B_PRIVATE* out_private,
                       TPM2B_PUBLIC* out_public,
                       TPM2B_CREATION_DATA* creation_data,
                       TPM2B_DIGEST* creation_hash,
                       TPMT_TK_CREATION* creation_ticket,
                       AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_Create(
      parent_handle, parent_handle_name, in_sensitive, in_public, outside_info,
      creation_pcr, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_Create(response, out_private, out_public, creation_data,
                            creation_hash, creation_ticket,
                            authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_Load(
    const TPMI_DH_OBJECT& parent_handle,
    const std::string& parent_handle_name,
    const TPM2B_PRIVATE& in_private,
    const TPM2B_PUBLIC& in_public,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_Load;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string parent_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(parent_handle, &parent_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string in_private_bytes;
  rc = Serialize_TPM2B_PRIVATE(in_private, &in_private_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string in_public_bytes;
  rc = Serialize_TPM2B_PUBLIC(in_public, &in_public_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = in_private_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    in_private_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(parent_handle_name.data(), parent_handle_name.size());
  handle_section_bytes += parent_handle_bytes;
  command_size += parent_handle_bytes.size();
  hash->Update(in_private_bytes.data(), in_private_bytes.size());
  parameter_section_bytes += in_private_bytes;
  command_size += in_private_bytes.size();
  hash->Update(in_public_bytes.data(), in_public_bytes.size());
  parameter_section_bytes += in_public_bytes;
  command_size += in_public_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_Load(const std::string& response,
                               TPM_HANDLE* object_handle,
                               TPM2B_NAME* name,
                               AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  std::string object_handle_bytes;
  rc = Parse_TPM_HANDLE(&buffer, object_handle, &object_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_CC command_code = TPM_CC_Load;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string name_bytes;
  rc = Parse_TPM2B_NAME(&buffer, name, &name_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = name_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    name_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_NAME(&name_bytes, name, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void LoadErrorCallback(const Tpm::LoadResponse& callback,
                       TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM_HANDLE(), TPM2B_NAME());
}

void LoadResponseParser(const Tpm::LoadResponse& callback,
                        AuthorizationDelegate* authorization_delegate,
                        const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(LoadErrorCallback, callback);
  TPM_HANDLE object_handle;
  TPM2B_NAME name;
  TPM_RC rc = Tpm::ParseResponse_Load(response, &object_handle, &name,
                                      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, object_handle, name);
}

void Tpm::Load(const TPMI_DH_OBJECT& parent_handle,
               const std::string& parent_handle_name,
               const TPM2B_PRIVATE& in_private,
               const TPM2B_PUBLIC& in_public,
               AuthorizationDelegate* authorization_delegate,
               const LoadResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(LoadErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(LoadResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc =
      SerializeCommand_Load(parent_handle, parent_handle_name, in_private,
                            in_public, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::LoadSync(const TPMI_DH_OBJECT& parent_handle,
                     const std::string& parent_handle_name,
                     const TPM2B_PRIVATE& in_private,
                     const TPM2B_PUBLIC& in_public,
                     TPM_HANDLE* object_handle,
                     TPM2B_NAME* name,
                     AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc =
      SerializeCommand_Load(parent_handle, parent_handle_name, in_private,
                            in_public, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc =
      ParseResponse_Load(response, object_handle, name, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_LoadExternal(
    const TPM2B_SENSITIVE& in_private,
    const TPM2B_PUBLIC& in_public,
    const TPMI_RH_HIERARCHY& hierarchy,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_LoadExternal;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string in_private_bytes;
  rc = Serialize_TPM2B_SENSITIVE(in_private, &in_private_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string in_public_bytes;
  rc = Serialize_TPM2B_PUBLIC(in_public, &in_public_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string hierarchy_bytes;
  rc = Serialize_TPMI_RH_HIERARCHY(hierarchy, &hierarchy_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = in_private_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    in_private_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(in_private_bytes.data(), in_private_bytes.size());
  parameter_section_bytes += in_private_bytes;
  command_size += in_private_bytes.size();
  hash->Update(in_public_bytes.data(), in_public_bytes.size());
  parameter_section_bytes += in_public_bytes;
  command_size += in_public_bytes.size();
  hash->Update(hierarchy_bytes.data(), hierarchy_bytes.size());
  parameter_section_bytes += hierarchy_bytes;
  command_size += hierarchy_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_LoadExternal(
    const std::string& response,
    TPM_HANDLE* object_handle,
    TPM2B_NAME* name,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  std::string object_handle_bytes;
  rc = Parse_TPM_HANDLE(&buffer, object_handle, &object_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_CC command_code = TPM_CC_LoadExternal;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string name_bytes;
  rc = Parse_TPM2B_NAME(&buffer, name, &name_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = name_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    name_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_NAME(&name_bytes, name, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void LoadExternalErrorCallback(const Tpm::LoadExternalResponse& callback,
                               TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM_HANDLE(), TPM2B_NAME());
}

void LoadExternalResponseParser(const Tpm::LoadExternalResponse& callback,
                                AuthorizationDelegate* authorization_delegate,
                                const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(LoadExternalErrorCallback, callback);
  TPM_HANDLE object_handle;
  TPM2B_NAME name;
  TPM_RC rc = Tpm::ParseResponse_LoadExternal(response, &object_handle, &name,
                                              authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, object_handle, name);
}

void Tpm::LoadExternal(const TPM2B_SENSITIVE& in_private,
                       const TPM2B_PUBLIC& in_public,
                       const TPMI_RH_HIERARCHY& hierarchy,
                       AuthorizationDelegate* authorization_delegate,
                       const LoadExternalResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(LoadExternalErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(LoadExternalResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_LoadExternal(in_private, in_public, hierarchy,
                                            &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::LoadExternalSync(const TPM2B_SENSITIVE& in_private,
                             const TPM2B_PUBLIC& in_public,
                             const TPMI_RH_HIERARCHY& hierarchy,
                             TPM_HANDLE* object_handle,
                             TPM2B_NAME* name,
                             AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_LoadExternal(in_private, in_public, hierarchy,
                                            &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_LoadExternal(response, object_handle, name,
                                  authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_ReadPublic(
    const TPMI_DH_OBJECT& object_handle,
    const std::string& object_handle_name,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_ReadPublic;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string object_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(object_handle, &object_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(object_handle_name.data(), object_handle_name.size());
  handle_section_bytes += object_handle_bytes;
  command_size += object_handle_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_ReadPublic(
    const std::string& response,
    TPM2B_PUBLIC* out_public,
    TPM2B_NAME* name,
    TPM2B_NAME* qualified_name,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_ReadPublic;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string out_public_bytes;
  rc = Parse_TPM2B_PUBLIC(&buffer, out_public, &out_public_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string name_bytes;
  rc = Parse_TPM2B_NAME(&buffer, name, &name_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string qualified_name_bytes;
  rc = Parse_TPM2B_NAME(&buffer, qualified_name, &qualified_name_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = out_public_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    out_public_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_PUBLIC(&out_public_bytes, out_public, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void ReadPublicErrorCallback(const Tpm::ReadPublicResponse& callback,
                             TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_PUBLIC(), TPM2B_NAME(), TPM2B_NAME());
}

void ReadPublicResponseParser(const Tpm::ReadPublicResponse& callback,
                              AuthorizationDelegate* authorization_delegate,
                              const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ReadPublicErrorCallback, callback);
  TPM2B_PUBLIC out_public;
  TPM2B_NAME name;
  TPM2B_NAME qualified_name;
  TPM_RC rc = Tpm::ParseResponse_ReadPublic(
      response, &out_public, &name, &qualified_name, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, out_public, name, qualified_name);
}

void Tpm::ReadPublic(const TPMI_DH_OBJECT& object_handle,
                     const std::string& object_handle_name,
                     AuthorizationDelegate* authorization_delegate,
                     const ReadPublicResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ReadPublicErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(ReadPublicResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_ReadPublic(object_handle, object_handle_name,
                                          &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::ReadPublicSync(const TPMI_DH_OBJECT& object_handle,
                           const std::string& object_handle_name,
                           TPM2B_PUBLIC* out_public,
                           TPM2B_NAME* name,
                           TPM2B_NAME* qualified_name,
                           AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_ReadPublic(object_handle, object_handle_name,
                                          &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_ReadPublic(response, out_public, name, qualified_name,
                                authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_ActivateCredential(
    const TPMI_DH_OBJECT& activate_handle,
    const std::string& activate_handle_name,
    const TPMI_DH_OBJECT& key_handle,
    const std::string& key_handle_name,
    const TPM2B_ID_OBJECT& credential_blob,
    const TPM2B_ENCRYPTED_SECRET& secret,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_ActivateCredential;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string activate_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(activate_handle, &activate_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string key_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(key_handle, &key_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string credential_blob_bytes;
  rc = Serialize_TPM2B_ID_OBJECT(credential_blob, &credential_blob_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string secret_bytes;
  rc = Serialize_TPM2B_ENCRYPTED_SECRET(secret, &secret_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = credential_blob_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    credential_blob_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(activate_handle_name.data(), activate_handle_name.size());
  handle_section_bytes += activate_handle_bytes;
  command_size += activate_handle_bytes.size();
  hash->Update(key_handle_name.data(), key_handle_name.size());
  handle_section_bytes += key_handle_bytes;
  command_size += key_handle_bytes.size();
  hash->Update(credential_blob_bytes.data(), credential_blob_bytes.size());
  parameter_section_bytes += credential_blob_bytes;
  command_size += credential_blob_bytes.size();
  hash->Update(secret_bytes.data(), secret_bytes.size());
  parameter_section_bytes += secret_bytes;
  command_size += secret_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_ActivateCredential(
    const std::string& response,
    TPM2B_DIGEST* cert_info,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_ActivateCredential;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string cert_info_bytes;
  rc = Parse_TPM2B_DIGEST(&buffer, cert_info, &cert_info_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = cert_info_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    cert_info_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_DIGEST(&cert_info_bytes, cert_info, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void ActivateCredentialErrorCallback(
    const Tpm::ActivateCredentialResponse& callback,
    TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_DIGEST());
}

void ActivateCredentialResponseParser(
    const Tpm::ActivateCredentialResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ActivateCredentialErrorCallback, callback);
  TPM2B_DIGEST cert_info;
  TPM_RC rc = Tpm::ParseResponse_ActivateCredential(response, &cert_info,
                                                    authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, cert_info);
}

void Tpm::ActivateCredential(const TPMI_DH_OBJECT& activate_handle,
                             const std::string& activate_handle_name,
                             const TPMI_DH_OBJECT& key_handle,
                             const std::string& key_handle_name,
                             const TPM2B_ID_OBJECT& credential_blob,
                             const TPM2B_ENCRYPTED_SECRET& secret,
                             AuthorizationDelegate* authorization_delegate,
                             const ActivateCredentialResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ActivateCredentialErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      ActivateCredentialResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_ActivateCredential(
      activate_handle, activate_handle_name, key_handle, key_handle_name,
      credential_blob, secret, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::ActivateCredentialSync(
    const TPMI_DH_OBJECT& activate_handle,
    const std::string& activate_handle_name,
    const TPMI_DH_OBJECT& key_handle,
    const std::string& key_handle_name,
    const TPM2B_ID_OBJECT& credential_blob,
    const TPM2B_ENCRYPTED_SECRET& secret,
    TPM2B_DIGEST* cert_info,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_ActivateCredential(
      activate_handle, activate_handle_name, key_handle, key_handle_name,
      credential_blob, secret, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_ActivateCredential(response, cert_info,
                                        authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_MakeCredential(
    const TPMI_DH_OBJECT& handle,
    const std::string& handle_name,
    const TPM2B_DIGEST& credential,
    const TPM2B_NAME& object_name,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_MakeCredential;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(handle, &handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string credential_bytes;
  rc = Serialize_TPM2B_DIGEST(credential, &credential_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string object_name_bytes;
  rc = Serialize_TPM2B_NAME(object_name, &object_name_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = credential_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    credential_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(handle_name.data(), handle_name.size());
  handle_section_bytes += handle_bytes;
  command_size += handle_bytes.size();
  hash->Update(credential_bytes.data(), credential_bytes.size());
  parameter_section_bytes += credential_bytes;
  command_size += credential_bytes.size();
  hash->Update(object_name_bytes.data(), object_name_bytes.size());
  parameter_section_bytes += object_name_bytes;
  command_size += object_name_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_MakeCredential(
    const std::string& response,
    TPM2B_ID_OBJECT* credential_blob,
    TPM2B_ENCRYPTED_SECRET* secret,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_MakeCredential;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string credential_blob_bytes;
  rc = Parse_TPM2B_ID_OBJECT(&buffer, credential_blob, &credential_blob_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string secret_bytes;
  rc = Parse_TPM2B_ENCRYPTED_SECRET(&buffer, secret, &secret_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = credential_blob_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    credential_blob_bytes.replace(2, std::string::npos, tmp);
    rc =
        Parse_TPM2B_ID_OBJECT(&credential_blob_bytes, credential_blob, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void MakeCredentialErrorCallback(const Tpm::MakeCredentialResponse& callback,
                                 TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_ID_OBJECT(), TPM2B_ENCRYPTED_SECRET());
}

void MakeCredentialResponseParser(const Tpm::MakeCredentialResponse& callback,
                                  AuthorizationDelegate* authorization_delegate,
                                  const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(MakeCredentialErrorCallback, callback);
  TPM2B_ID_OBJECT credential_blob;
  TPM2B_ENCRYPTED_SECRET secret;
  TPM_RC rc = Tpm::ParseResponse_MakeCredential(
      response, &credential_blob, &secret, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, credential_blob, secret);
}

void Tpm::MakeCredential(const TPMI_DH_OBJECT& handle,
                         const std::string& handle_name,
                         const TPM2B_DIGEST& credential,
                         const TPM2B_NAME& object_name,
                         AuthorizationDelegate* authorization_delegate,
                         const MakeCredentialResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(MakeCredentialErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      MakeCredentialResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_MakeCredential(handle, handle_name, credential,
                                              object_name, &command,
                                              authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::MakeCredentialSync(const TPMI_DH_OBJECT& handle,
                               const std::string& handle_name,
                               const TPM2B_DIGEST& credential,
                               const TPM2B_NAME& object_name,
                               TPM2B_ID_OBJECT* credential_blob,
                               TPM2B_ENCRYPTED_SECRET* secret,
                               AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_MakeCredential(handle, handle_name, credential,
                                              object_name, &command,
                                              authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_MakeCredential(response, credential_blob, secret,
                                    authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_Unseal(
    const TPMI_DH_OBJECT& item_handle,
    const std::string& item_handle_name,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_Unseal;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string item_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(item_handle, &item_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(item_handle_name.data(), item_handle_name.size());
  handle_section_bytes += item_handle_bytes;
  command_size += item_handle_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_Unseal(
    const std::string& response,
    TPM2B_SENSITIVE_DATA* out_data,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_Unseal;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string out_data_bytes;
  rc = Parse_TPM2B_SENSITIVE_DATA(&buffer, out_data, &out_data_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = out_data_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    out_data_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_SENSITIVE_DATA(&out_data_bytes, out_data, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void UnsealErrorCallback(const Tpm::UnsealResponse& callback,
                         TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_SENSITIVE_DATA());
}

void UnsealResponseParser(const Tpm::UnsealResponse& callback,
                          AuthorizationDelegate* authorization_delegate,
                          const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(UnsealErrorCallback, callback);
  TPM2B_SENSITIVE_DATA out_data;
  TPM_RC rc =
      Tpm::ParseResponse_Unseal(response, &out_data, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, out_data);
}

void Tpm::Unseal(const TPMI_DH_OBJECT& item_handle,
                 const std::string& item_handle_name,
                 AuthorizationDelegate* authorization_delegate,
                 const UnsealResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(UnsealErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(UnsealResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_Unseal(item_handle, item_handle_name, &command,
                                      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::UnsealSync(const TPMI_DH_OBJECT& item_handle,
                       const std::string& item_handle_name,
                       TPM2B_SENSITIVE_DATA* out_data,
                       AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_Unseal(item_handle, item_handle_name, &command,
                                      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_Unseal(response, out_data, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_ObjectChangeAuth(
    const TPMI_DH_OBJECT& object_handle,
    const std::string& object_handle_name,
    const TPMI_DH_OBJECT& parent_handle,
    const std::string& parent_handle_name,
    const TPM2B_AUTH& new_auth,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_ObjectChangeAuth;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string object_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(object_handle, &object_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string parent_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(parent_handle, &parent_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string new_auth_bytes;
  rc = Serialize_TPM2B_AUTH(new_auth, &new_auth_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = new_auth_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    new_auth_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(object_handle_name.data(), object_handle_name.size());
  handle_section_bytes += object_handle_bytes;
  command_size += object_handle_bytes.size();
  hash->Update(parent_handle_name.data(), parent_handle_name.size());
  handle_section_bytes += parent_handle_bytes;
  command_size += parent_handle_bytes.size();
  hash->Update(new_auth_bytes.data(), new_auth_bytes.size());
  parameter_section_bytes += new_auth_bytes;
  command_size += new_auth_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_ObjectChangeAuth(
    const std::string& response,
    TPM2B_PRIVATE* out_private,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_ObjectChangeAuth;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string out_private_bytes;
  rc = Parse_TPM2B_PRIVATE(&buffer, out_private, &out_private_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = out_private_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    out_private_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_PRIVATE(&out_private_bytes, out_private, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void ObjectChangeAuthErrorCallback(
    const Tpm::ObjectChangeAuthResponse& callback,
    TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_PRIVATE());
}

void ObjectChangeAuthResponseParser(
    const Tpm::ObjectChangeAuthResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ObjectChangeAuthErrorCallback, callback);
  TPM2B_PRIVATE out_private;
  TPM_RC rc = Tpm::ParseResponse_ObjectChangeAuth(response, &out_private,
                                                  authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, out_private);
}

void Tpm::ObjectChangeAuth(const TPMI_DH_OBJECT& object_handle,
                           const std::string& object_handle_name,
                           const TPMI_DH_OBJECT& parent_handle,
                           const std::string& parent_handle_name,
                           const TPM2B_AUTH& new_auth,
                           AuthorizationDelegate* authorization_delegate,
                           const ObjectChangeAuthResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ObjectChangeAuthErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      ObjectChangeAuthResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_ObjectChangeAuth(
      object_handle, object_handle_name, parent_handle, parent_handle_name,
      new_auth, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::ObjectChangeAuthSync(
    const TPMI_DH_OBJECT& object_handle,
    const std::string& object_handle_name,
    const TPMI_DH_OBJECT& parent_handle,
    const std::string& parent_handle_name,
    const TPM2B_AUTH& new_auth,
    TPM2B_PRIVATE* out_private,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_ObjectChangeAuth(
      object_handle, object_handle_name, parent_handle, parent_handle_name,
      new_auth, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_ObjectChangeAuth(response, out_private,
                                      authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_Duplicate(
    const TPMI_DH_OBJECT& object_handle,
    const std::string& object_handle_name,
    const TPMI_DH_OBJECT& new_parent_handle,
    const std::string& new_parent_handle_name,
    const TPM2B_DATA& encryption_key_in,
    const TPMT_SYM_DEF_OBJECT& symmetric_alg,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_Duplicate;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string object_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(object_handle, &object_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string new_parent_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(new_parent_handle, &new_parent_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string encryption_key_in_bytes;
  rc = Serialize_TPM2B_DATA(encryption_key_in, &encryption_key_in_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string symmetric_alg_bytes;
  rc = Serialize_TPMT_SYM_DEF_OBJECT(symmetric_alg, &symmetric_alg_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = encryption_key_in_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    encryption_key_in_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(object_handle_name.data(), object_handle_name.size());
  handle_section_bytes += object_handle_bytes;
  command_size += object_handle_bytes.size();
  hash->Update(new_parent_handle_name.data(), new_parent_handle_name.size());
  handle_section_bytes += new_parent_handle_bytes;
  command_size += new_parent_handle_bytes.size();
  hash->Update(encryption_key_in_bytes.data(), encryption_key_in_bytes.size());
  parameter_section_bytes += encryption_key_in_bytes;
  command_size += encryption_key_in_bytes.size();
  hash->Update(symmetric_alg_bytes.data(), symmetric_alg_bytes.size());
  parameter_section_bytes += symmetric_alg_bytes;
  command_size += symmetric_alg_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_Duplicate(
    const std::string& response,
    TPM2B_DATA* encryption_key_out,
    TPM2B_PRIVATE* duplicate,
    TPM2B_ENCRYPTED_SECRET* out_sym_seed,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_Duplicate;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string encryption_key_out_bytes;
  rc = Parse_TPM2B_DATA(&buffer, encryption_key_out, &encryption_key_out_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string duplicate_bytes;
  rc = Parse_TPM2B_PRIVATE(&buffer, duplicate, &duplicate_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string out_sym_seed_bytes;
  rc = Parse_TPM2B_ENCRYPTED_SECRET(&buffer, out_sym_seed, &out_sym_seed_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = encryption_key_out_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    encryption_key_out_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_DATA(&encryption_key_out_bytes, encryption_key_out,
                          nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void DuplicateErrorCallback(const Tpm::DuplicateResponse& callback,
                            TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_DATA(), TPM2B_PRIVATE(),
               TPM2B_ENCRYPTED_SECRET());
}

void DuplicateResponseParser(const Tpm::DuplicateResponse& callback,
                             AuthorizationDelegate* authorization_delegate,
                             const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(DuplicateErrorCallback, callback);
  TPM2B_DATA encryption_key_out;
  TPM2B_PRIVATE duplicate;
  TPM2B_ENCRYPTED_SECRET out_sym_seed;
  TPM_RC rc =
      Tpm::ParseResponse_Duplicate(response, &encryption_key_out, &duplicate,
                                   &out_sym_seed, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, encryption_key_out, duplicate, out_sym_seed);
}

void Tpm::Duplicate(const TPMI_DH_OBJECT& object_handle,
                    const std::string& object_handle_name,
                    const TPMI_DH_OBJECT& new_parent_handle,
                    const std::string& new_parent_handle_name,
                    const TPM2B_DATA& encryption_key_in,
                    const TPMT_SYM_DEF_OBJECT& symmetric_alg,
                    AuthorizationDelegate* authorization_delegate,
                    const DuplicateResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(DuplicateErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(DuplicateResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_Duplicate(
      object_handle, object_handle_name, new_parent_handle,
      new_parent_handle_name, encryption_key_in, symmetric_alg, &command,
      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::DuplicateSync(const TPMI_DH_OBJECT& object_handle,
                          const std::string& object_handle_name,
                          const TPMI_DH_OBJECT& new_parent_handle,
                          const std::string& new_parent_handle_name,
                          const TPM2B_DATA& encryption_key_in,
                          const TPMT_SYM_DEF_OBJECT& symmetric_alg,
                          TPM2B_DATA* encryption_key_out,
                          TPM2B_PRIVATE* duplicate,
                          TPM2B_ENCRYPTED_SECRET* out_sym_seed,
                          AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_Duplicate(
      object_handle, object_handle_name, new_parent_handle,
      new_parent_handle_name, encryption_key_in, symmetric_alg, &command,
      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_Duplicate(response, encryption_key_out, duplicate,
                               out_sym_seed, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_Rewrap(
    const TPMI_DH_OBJECT& old_parent,
    const std::string& old_parent_name,
    const TPMI_DH_OBJECT& new_parent,
    const std::string& new_parent_name,
    const TPM2B_PRIVATE& in_duplicate,
    const TPM2B_NAME& name,
    const TPM2B_ENCRYPTED_SECRET& in_sym_seed,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_Rewrap;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string old_parent_bytes;
  rc = Serialize_TPMI_DH_OBJECT(old_parent, &old_parent_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string new_parent_bytes;
  rc = Serialize_TPMI_DH_OBJECT(new_parent, &new_parent_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string in_duplicate_bytes;
  rc = Serialize_TPM2B_PRIVATE(in_duplicate, &in_duplicate_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string name_bytes;
  rc = Serialize_TPM2B_NAME(name, &name_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string in_sym_seed_bytes;
  rc = Serialize_TPM2B_ENCRYPTED_SECRET(in_sym_seed, &in_sym_seed_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = in_duplicate_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    in_duplicate_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(old_parent_name.data(), old_parent_name.size());
  handle_section_bytes += old_parent_bytes;
  command_size += old_parent_bytes.size();
  hash->Update(new_parent_name.data(), new_parent_name.size());
  handle_section_bytes += new_parent_bytes;
  command_size += new_parent_bytes.size();
  hash->Update(in_duplicate_bytes.data(), in_duplicate_bytes.size());
  parameter_section_bytes += in_duplicate_bytes;
  command_size += in_duplicate_bytes.size();
  hash->Update(name_bytes.data(), name_bytes.size());
  parameter_section_bytes += name_bytes;
  command_size += name_bytes.size();
  hash->Update(in_sym_seed_bytes.data(), in_sym_seed_bytes.size());
  parameter_section_bytes += in_sym_seed_bytes;
  command_size += in_sym_seed_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_Rewrap(
    const std::string& response,
    TPM2B_PRIVATE* out_duplicate,
    TPM2B_ENCRYPTED_SECRET* out_sym_seed,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_Rewrap;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string out_duplicate_bytes;
  rc = Parse_TPM2B_PRIVATE(&buffer, out_duplicate, &out_duplicate_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string out_sym_seed_bytes;
  rc = Parse_TPM2B_ENCRYPTED_SECRET(&buffer, out_sym_seed, &out_sym_seed_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = out_duplicate_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    out_duplicate_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_PRIVATE(&out_duplicate_bytes, out_duplicate, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void RewrapErrorCallback(const Tpm::RewrapResponse& callback,
                         TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_PRIVATE(), TPM2B_ENCRYPTED_SECRET());
}

void RewrapResponseParser(const Tpm::RewrapResponse& callback,
                          AuthorizationDelegate* authorization_delegate,
                          const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(RewrapErrorCallback, callback);
  TPM2B_PRIVATE out_duplicate;
  TPM2B_ENCRYPTED_SECRET out_sym_seed;
  TPM_RC rc = Tpm::ParseResponse_Rewrap(response, &out_duplicate, &out_sym_seed,
                                        authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, out_duplicate, out_sym_seed);
}

void Tpm::Rewrap(const TPMI_DH_OBJECT& old_parent,
                 const std::string& old_parent_name,
                 const TPMI_DH_OBJECT& new_parent,
                 const std::string& new_parent_name,
                 const TPM2B_PRIVATE& in_duplicate,
                 const TPM2B_NAME& name,
                 const TPM2B_ENCRYPTED_SECRET& in_sym_seed,
                 AuthorizationDelegate* authorization_delegate,
                 const RewrapResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(RewrapErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(RewrapResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_Rewrap(
      old_parent, old_parent_name, new_parent, new_parent_name, in_duplicate,
      name, in_sym_seed, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::RewrapSync(const TPMI_DH_OBJECT& old_parent,
                       const std::string& old_parent_name,
                       const TPMI_DH_OBJECT& new_parent,
                       const std::string& new_parent_name,
                       const TPM2B_PRIVATE& in_duplicate,
                       const TPM2B_NAME& name,
                       const TPM2B_ENCRYPTED_SECRET& in_sym_seed,
                       TPM2B_PRIVATE* out_duplicate,
                       TPM2B_ENCRYPTED_SECRET* out_sym_seed,
                       AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_Rewrap(
      old_parent, old_parent_name, new_parent, new_parent_name, in_duplicate,
      name, in_sym_seed, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_Rewrap(response, out_duplicate, out_sym_seed,
                            authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_Import(
    const TPMI_DH_OBJECT& parent_handle,
    const std::string& parent_handle_name,
    const TPM2B_DATA& encryption_key,
    const TPM2B_PUBLIC& object_public,
    const TPM2B_PRIVATE& duplicate,
    const TPM2B_ENCRYPTED_SECRET& in_sym_seed,
    const TPMT_SYM_DEF_OBJECT& symmetric_alg,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_Import;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string parent_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(parent_handle, &parent_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string encryption_key_bytes;
  rc = Serialize_TPM2B_DATA(encryption_key, &encryption_key_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string object_public_bytes;
  rc = Serialize_TPM2B_PUBLIC(object_public, &object_public_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string duplicate_bytes;
  rc = Serialize_TPM2B_PRIVATE(duplicate, &duplicate_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string in_sym_seed_bytes;
  rc = Serialize_TPM2B_ENCRYPTED_SECRET(in_sym_seed, &in_sym_seed_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string symmetric_alg_bytes;
  rc = Serialize_TPMT_SYM_DEF_OBJECT(symmetric_alg, &symmetric_alg_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = encryption_key_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    encryption_key_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(parent_handle_name.data(), parent_handle_name.size());
  handle_section_bytes += parent_handle_bytes;
  command_size += parent_handle_bytes.size();
  hash->Update(encryption_key_bytes.data(), encryption_key_bytes.size());
  parameter_section_bytes += encryption_key_bytes;
  command_size += encryption_key_bytes.size();
  hash->Update(object_public_bytes.data(), object_public_bytes.size());
  parameter_section_bytes += object_public_bytes;
  command_size += object_public_bytes.size();
  hash->Update(duplicate_bytes.data(), duplicate_bytes.size());
  parameter_section_bytes += duplicate_bytes;
  command_size += duplicate_bytes.size();
  hash->Update(in_sym_seed_bytes.data(), in_sym_seed_bytes.size());
  parameter_section_bytes += in_sym_seed_bytes;
  command_size += in_sym_seed_bytes.size();
  hash->Update(symmetric_alg_bytes.data(), symmetric_alg_bytes.size());
  parameter_section_bytes += symmetric_alg_bytes;
  command_size += symmetric_alg_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_Import(
    const std::string& response,
    TPM2B_PRIVATE* out_private,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_Import;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string out_private_bytes;
  rc = Parse_TPM2B_PRIVATE(&buffer, out_private, &out_private_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = out_private_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    out_private_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_PRIVATE(&out_private_bytes, out_private, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void ImportErrorCallback(const Tpm::ImportResponse& callback,
                         TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_PRIVATE());
}

void ImportResponseParser(const Tpm::ImportResponse& callback,
                          AuthorizationDelegate* authorization_delegate,
                          const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ImportErrorCallback, callback);
  TPM2B_PRIVATE out_private;
  TPM_RC rc =
      Tpm::ParseResponse_Import(response, &out_private, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, out_private);
}

void Tpm::Import(const TPMI_DH_OBJECT& parent_handle,
                 const std::string& parent_handle_name,
                 const TPM2B_DATA& encryption_key,
                 const TPM2B_PUBLIC& object_public,
                 const TPM2B_PRIVATE& duplicate,
                 const TPM2B_ENCRYPTED_SECRET& in_sym_seed,
                 const TPMT_SYM_DEF_OBJECT& symmetric_alg,
                 AuthorizationDelegate* authorization_delegate,
                 const ImportResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ImportErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(ImportResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_Import(
      parent_handle, parent_handle_name, encryption_key, object_public,
      duplicate, in_sym_seed, symmetric_alg, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::ImportSync(const TPMI_DH_OBJECT& parent_handle,
                       const std::string& parent_handle_name,
                       const TPM2B_DATA& encryption_key,
                       const TPM2B_PUBLIC& object_public,
                       const TPM2B_PRIVATE& duplicate,
                       const TPM2B_ENCRYPTED_SECRET& in_sym_seed,
                       const TPMT_SYM_DEF_OBJECT& symmetric_alg,
                       TPM2B_PRIVATE* out_private,
                       AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_Import(
      parent_handle, parent_handle_name, encryption_key, object_public,
      duplicate, in_sym_seed, symmetric_alg, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_Import(response, out_private, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_RSA_Encrypt(
    const TPMI_DH_OBJECT& key_handle,
    const std::string& key_handle_name,
    const TPM2B_PUBLIC_KEY_RSA& message,
    const TPMT_RSA_DECRYPT& in_scheme,
    const TPM2B_DATA& label,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_RSA_Encrypt;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string key_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(key_handle, &key_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string message_bytes;
  rc = Serialize_TPM2B_PUBLIC_KEY_RSA(message, &message_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string in_scheme_bytes;
  rc = Serialize_TPMT_RSA_DECRYPT(in_scheme, &in_scheme_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string label_bytes;
  rc = Serialize_TPM2B_DATA(label, &label_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = message_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    message_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(key_handle_name.data(), key_handle_name.size());
  handle_section_bytes += key_handle_bytes;
  command_size += key_handle_bytes.size();
  hash->Update(message_bytes.data(), message_bytes.size());
  parameter_section_bytes += message_bytes;
  command_size += message_bytes.size();
  hash->Update(in_scheme_bytes.data(), in_scheme_bytes.size());
  parameter_section_bytes += in_scheme_bytes;
  command_size += in_scheme_bytes.size();
  hash->Update(label_bytes.data(), label_bytes.size());
  parameter_section_bytes += label_bytes;
  command_size += label_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_RSA_Encrypt(
    const std::string& response,
    TPM2B_PUBLIC_KEY_RSA* out_data,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_RSA_Encrypt;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string out_data_bytes;
  rc = Parse_TPM2B_PUBLIC_KEY_RSA(&buffer, out_data, &out_data_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = out_data_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    out_data_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_PUBLIC_KEY_RSA(&out_data_bytes, out_data, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void RSA_EncryptErrorCallback(const Tpm::RSA_EncryptResponse& callback,
                              TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_PUBLIC_KEY_RSA());
}

void RSA_EncryptResponseParser(const Tpm::RSA_EncryptResponse& callback,
                               AuthorizationDelegate* authorization_delegate,
                               const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(RSA_EncryptErrorCallback, callback);
  TPM2B_PUBLIC_KEY_RSA out_data;
  TPM_RC rc = Tpm::ParseResponse_RSA_Encrypt(response, &out_data,
                                             authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, out_data);
}

void Tpm::RSA_Encrypt(const TPMI_DH_OBJECT& key_handle,
                      const std::string& key_handle_name,
                      const TPM2B_PUBLIC_KEY_RSA& message,
                      const TPMT_RSA_DECRYPT& in_scheme,
                      const TPM2B_DATA& label,
                      AuthorizationDelegate* authorization_delegate,
                      const RSA_EncryptResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(RSA_EncryptErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(RSA_EncryptResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_RSA_Encrypt(key_handle, key_handle_name, message,
                                           in_scheme, label, &command,
                                           authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::RSA_EncryptSync(const TPMI_DH_OBJECT& key_handle,
                            const std::string& key_handle_name,
                            const TPM2B_PUBLIC_KEY_RSA& message,
                            const TPMT_RSA_DECRYPT& in_scheme,
                            const TPM2B_DATA& label,
                            TPM2B_PUBLIC_KEY_RSA* out_data,
                            AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_RSA_Encrypt(key_handle, key_handle_name, message,
                                           in_scheme, label, &command,
                                           authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_RSA_Encrypt(response, out_data, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_RSA_Decrypt(
    const TPMI_DH_OBJECT& key_handle,
    const std::string& key_handle_name,
    const TPM2B_PUBLIC_KEY_RSA& cipher_text,
    const TPMT_RSA_DECRYPT& in_scheme,
    const TPM2B_DATA& label,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_RSA_Decrypt;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string key_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(key_handle, &key_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string cipher_text_bytes;
  rc = Serialize_TPM2B_PUBLIC_KEY_RSA(cipher_text, &cipher_text_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string in_scheme_bytes;
  rc = Serialize_TPMT_RSA_DECRYPT(in_scheme, &in_scheme_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string label_bytes;
  rc = Serialize_TPM2B_DATA(label, &label_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = cipher_text_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    cipher_text_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(key_handle_name.data(), key_handle_name.size());
  handle_section_bytes += key_handle_bytes;
  command_size += key_handle_bytes.size();
  hash->Update(cipher_text_bytes.data(), cipher_text_bytes.size());
  parameter_section_bytes += cipher_text_bytes;
  command_size += cipher_text_bytes.size();
  hash->Update(in_scheme_bytes.data(), in_scheme_bytes.size());
  parameter_section_bytes += in_scheme_bytes;
  command_size += in_scheme_bytes.size();
  hash->Update(label_bytes.data(), label_bytes.size());
  parameter_section_bytes += label_bytes;
  command_size += label_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_RSA_Decrypt(
    const std::string& response,
    TPM2B_PUBLIC_KEY_RSA* message,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_RSA_Decrypt;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string message_bytes;
  rc = Parse_TPM2B_PUBLIC_KEY_RSA(&buffer, message, &message_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = message_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    message_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_PUBLIC_KEY_RSA(&message_bytes, message, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void RSA_DecryptErrorCallback(const Tpm::RSA_DecryptResponse& callback,
                              TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_PUBLIC_KEY_RSA());
}

void RSA_DecryptResponseParser(const Tpm::RSA_DecryptResponse& callback,
                               AuthorizationDelegate* authorization_delegate,
                               const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(RSA_DecryptErrorCallback, callback);
  TPM2B_PUBLIC_KEY_RSA message;
  TPM_RC rc = Tpm::ParseResponse_RSA_Decrypt(response, &message,
                                             authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, message);
}

void Tpm::RSA_Decrypt(const TPMI_DH_OBJECT& key_handle,
                      const std::string& key_handle_name,
                      const TPM2B_PUBLIC_KEY_RSA& cipher_text,
                      const TPMT_RSA_DECRYPT& in_scheme,
                      const TPM2B_DATA& label,
                      AuthorizationDelegate* authorization_delegate,
                      const RSA_DecryptResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(RSA_DecryptErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(RSA_DecryptResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_RSA_Decrypt(key_handle, key_handle_name,
                                           cipher_text, in_scheme, label,
                                           &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::RSA_DecryptSync(const TPMI_DH_OBJECT& key_handle,
                            const std::string& key_handle_name,
                            const TPM2B_PUBLIC_KEY_RSA& cipher_text,
                            const TPMT_RSA_DECRYPT& in_scheme,
                            const TPM2B_DATA& label,
                            TPM2B_PUBLIC_KEY_RSA* message,
                            AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_RSA_Decrypt(key_handle, key_handle_name,
                                           cipher_text, in_scheme, label,
                                           &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_RSA_Decrypt(response, message, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_ECDH_KeyGen(
    const TPMI_DH_OBJECT& key_handle,
    const std::string& key_handle_name,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_ECDH_KeyGen;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string key_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(key_handle, &key_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(key_handle_name.data(), key_handle_name.size());
  handle_section_bytes += key_handle_bytes;
  command_size += key_handle_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_ECDH_KeyGen(
    const std::string& response,
    TPM2B_ECC_POINT* z_point,
    TPM2B_ECC_POINT* pub_point,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_ECDH_KeyGen;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string z_point_bytes;
  rc = Parse_TPM2B_ECC_POINT(&buffer, z_point, &z_point_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string pub_point_bytes;
  rc = Parse_TPM2B_ECC_POINT(&buffer, pub_point, &pub_point_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = z_point_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    z_point_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_ECC_POINT(&z_point_bytes, z_point, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void ECDH_KeyGenErrorCallback(const Tpm::ECDH_KeyGenResponse& callback,
                              TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_ECC_POINT(), TPM2B_ECC_POINT());
}

void ECDH_KeyGenResponseParser(const Tpm::ECDH_KeyGenResponse& callback,
                               AuthorizationDelegate* authorization_delegate,
                               const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ECDH_KeyGenErrorCallback, callback);
  TPM2B_ECC_POINT z_point;
  TPM2B_ECC_POINT pub_point;
  TPM_RC rc = Tpm::ParseResponse_ECDH_KeyGen(response, &z_point, &pub_point,
                                             authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, z_point, pub_point);
}

void Tpm::ECDH_KeyGen(const TPMI_DH_OBJECT& key_handle,
                      const std::string& key_handle_name,
                      AuthorizationDelegate* authorization_delegate,
                      const ECDH_KeyGenResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ECDH_KeyGenErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(ECDH_KeyGenResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_ECDH_KeyGen(key_handle, key_handle_name,
                                           &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::ECDH_KeyGenSync(const TPMI_DH_OBJECT& key_handle,
                            const std::string& key_handle_name,
                            TPM2B_ECC_POINT* z_point,
                            TPM2B_ECC_POINT* pub_point,
                            AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_ECDH_KeyGen(key_handle, key_handle_name,
                                           &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_ECDH_KeyGen(response, z_point, pub_point,
                                 authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_ECDH_ZGen(
    const TPMI_DH_OBJECT& key_handle,
    const std::string& key_handle_name,
    const TPM2B_ECC_POINT& in_point,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_ECDH_ZGen;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string key_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(key_handle, &key_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string in_point_bytes;
  rc = Serialize_TPM2B_ECC_POINT(in_point, &in_point_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = in_point_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    in_point_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(key_handle_name.data(), key_handle_name.size());
  handle_section_bytes += key_handle_bytes;
  command_size += key_handle_bytes.size();
  hash->Update(in_point_bytes.data(), in_point_bytes.size());
  parameter_section_bytes += in_point_bytes;
  command_size += in_point_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_ECDH_ZGen(
    const std::string& response,
    TPM2B_ECC_POINT* out_point,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_ECDH_ZGen;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string out_point_bytes;
  rc = Parse_TPM2B_ECC_POINT(&buffer, out_point, &out_point_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = out_point_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    out_point_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_ECC_POINT(&out_point_bytes, out_point, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void ECDH_ZGenErrorCallback(const Tpm::ECDH_ZGenResponse& callback,
                            TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_ECC_POINT());
}

void ECDH_ZGenResponseParser(const Tpm::ECDH_ZGenResponse& callback,
                             AuthorizationDelegate* authorization_delegate,
                             const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ECDH_ZGenErrorCallback, callback);
  TPM2B_ECC_POINT out_point;
  TPM_RC rc = Tpm::ParseResponse_ECDH_ZGen(response, &out_point,
                                           authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, out_point);
}

void Tpm::ECDH_ZGen(const TPMI_DH_OBJECT& key_handle,
                    const std::string& key_handle_name,
                    const TPM2B_ECC_POINT& in_point,
                    AuthorizationDelegate* authorization_delegate,
                    const ECDH_ZGenResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ECDH_ZGenErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(ECDH_ZGenResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_ECDH_ZGen(key_handle, key_handle_name, in_point,
                                         &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::ECDH_ZGenSync(const TPMI_DH_OBJECT& key_handle,
                          const std::string& key_handle_name,
                          const TPM2B_ECC_POINT& in_point,
                          TPM2B_ECC_POINT* out_point,
                          AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_ECDH_ZGen(key_handle, key_handle_name, in_point,
                                         &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_ECDH_ZGen(response, out_point, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_ECC_Parameters(
    const TPMI_ECC_CURVE& curve_id,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_ECC_Parameters;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string curve_id_bytes;
  rc = Serialize_TPMI_ECC_CURVE(curve_id, &curve_id_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(curve_id_bytes.data(), curve_id_bytes.size());
  parameter_section_bytes += curve_id_bytes;
  command_size += curve_id_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_ECC_Parameters(
    const std::string& response,
    TPMS_ALGORITHM_DETAIL_ECC* parameters,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_ECC_Parameters;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string parameters_bytes;
  rc = Parse_TPMS_ALGORITHM_DETAIL_ECC(&buffer, parameters, &parameters_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  return TPM_RC_SUCCESS;
}

void ECC_ParametersErrorCallback(const Tpm::ECC_ParametersResponse& callback,
                                 TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPMS_ALGORITHM_DETAIL_ECC());
}

void ECC_ParametersResponseParser(const Tpm::ECC_ParametersResponse& callback,
                                  AuthorizationDelegate* authorization_delegate,
                                  const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ECC_ParametersErrorCallback, callback);
  TPMS_ALGORITHM_DETAIL_ECC parameters;
  TPM_RC rc = Tpm::ParseResponse_ECC_Parameters(response, &parameters,
                                                authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, parameters);
}

void Tpm::ECC_Parameters(const TPMI_ECC_CURVE& curve_id,
                         AuthorizationDelegate* authorization_delegate,
                         const ECC_ParametersResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ECC_ParametersErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      ECC_ParametersResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_ECC_Parameters(curve_id, &command,
                                              authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::ECC_ParametersSync(const TPMI_ECC_CURVE& curve_id,
                               TPMS_ALGORITHM_DETAIL_ECC* parameters,
                               AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_ECC_Parameters(curve_id, &command,
                                              authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_ECC_Parameters(response, parameters,
                                    authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_ZGen_2Phase(
    const TPMI_DH_OBJECT& key_a,
    const std::string& key_a_name,
    const TPM2B_ECC_POINT& in_qs_b,
    const TPM2B_ECC_POINT& in_qe_b,
    const TPMI_ECC_KEY_EXCHANGE& in_scheme,
    const UINT16& counter,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_ZGen_2Phase;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string key_a_bytes;
  rc = Serialize_TPMI_DH_OBJECT(key_a, &key_a_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string in_qs_b_bytes;
  rc = Serialize_TPM2B_ECC_POINT(in_qs_b, &in_qs_b_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string in_qe_b_bytes;
  rc = Serialize_TPM2B_ECC_POINT(in_qe_b, &in_qe_b_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string in_scheme_bytes;
  rc = Serialize_TPMI_ECC_KEY_EXCHANGE(in_scheme, &in_scheme_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string counter_bytes;
  rc = Serialize_UINT16(counter, &counter_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = in_qs_b_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    in_qs_b_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(key_a_name.data(), key_a_name.size());
  handle_section_bytes += key_a_bytes;
  command_size += key_a_bytes.size();
  hash->Update(in_qs_b_bytes.data(), in_qs_b_bytes.size());
  parameter_section_bytes += in_qs_b_bytes;
  command_size += in_qs_b_bytes.size();
  hash->Update(in_qe_b_bytes.data(), in_qe_b_bytes.size());
  parameter_section_bytes += in_qe_b_bytes;
  command_size += in_qe_b_bytes.size();
  hash->Update(in_scheme_bytes.data(), in_scheme_bytes.size());
  parameter_section_bytes += in_scheme_bytes;
  command_size += in_scheme_bytes.size();
  hash->Update(counter_bytes.data(), counter_bytes.size());
  parameter_section_bytes += counter_bytes;
  command_size += counter_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_ZGen_2Phase(
    const std::string& response,
    TPM2B_ECC_POINT* out_z1,
    TPM2B_ECC_POINT* out_z2,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_ZGen_2Phase;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string out_z1_bytes;
  rc = Parse_TPM2B_ECC_POINT(&buffer, out_z1, &out_z1_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string out_z2_bytes;
  rc = Parse_TPM2B_ECC_POINT(&buffer, out_z2, &out_z2_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = out_z1_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    out_z1_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_ECC_POINT(&out_z1_bytes, out_z1, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void ZGen_2PhaseErrorCallback(const Tpm::ZGen_2PhaseResponse& callback,
                              TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_ECC_POINT(), TPM2B_ECC_POINT());
}

void ZGen_2PhaseResponseParser(const Tpm::ZGen_2PhaseResponse& callback,
                               AuthorizationDelegate* authorization_delegate,
                               const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ZGen_2PhaseErrorCallback, callback);
  TPM2B_ECC_POINT out_z1;
  TPM2B_ECC_POINT out_z2;
  TPM_RC rc = Tpm::ParseResponse_ZGen_2Phase(response, &out_z1, &out_z2,
                                             authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, out_z1, out_z2);
}

void Tpm::ZGen_2Phase(const TPMI_DH_OBJECT& key_a,
                      const std::string& key_a_name,
                      const TPM2B_ECC_POINT& in_qs_b,
                      const TPM2B_ECC_POINT& in_qe_b,
                      const TPMI_ECC_KEY_EXCHANGE& in_scheme,
                      const UINT16& counter,
                      AuthorizationDelegate* authorization_delegate,
                      const ZGen_2PhaseResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ZGen_2PhaseErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(ZGen_2PhaseResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_ZGen_2Phase(key_a, key_a_name, in_qs_b, in_qe_b,
                                           in_scheme, counter, &command,
                                           authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::ZGen_2PhaseSync(const TPMI_DH_OBJECT& key_a,
                            const std::string& key_a_name,
                            const TPM2B_ECC_POINT& in_qs_b,
                            const TPM2B_ECC_POINT& in_qe_b,
                            const TPMI_ECC_KEY_EXCHANGE& in_scheme,
                            const UINT16& counter,
                            TPM2B_ECC_POINT* out_z1,
                            TPM2B_ECC_POINT* out_z2,
                            AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_ZGen_2Phase(key_a, key_a_name, in_qs_b, in_qe_b,
                                           in_scheme, counter, &command,
                                           authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_ZGen_2Phase(response, out_z1, out_z2,
                                 authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_EncryptDecrypt(
    const TPMI_DH_OBJECT& key_handle,
    const std::string& key_handle_name,
    const TPMI_YES_NO& decrypt,
    const TPMI_ALG_SYM_MODE& mode,
    const TPM2B_IV& iv_in,
    const TPM2B_MAX_BUFFER& in_data,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_EncryptDecrypt;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string key_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(key_handle, &key_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string decrypt_bytes;
  rc = Serialize_TPMI_YES_NO(decrypt, &decrypt_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string mode_bytes;
  rc = Serialize_TPMI_ALG_SYM_MODE(mode, &mode_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string iv_in_bytes;
  rc = Serialize_TPM2B_IV(iv_in, &iv_in_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string in_data_bytes;
  rc = Serialize_TPM2B_MAX_BUFFER(in_data, &in_data_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(key_handle_name.data(), key_handle_name.size());
  handle_section_bytes += key_handle_bytes;
  command_size += key_handle_bytes.size();
  hash->Update(decrypt_bytes.data(), decrypt_bytes.size());
  parameter_section_bytes += decrypt_bytes;
  command_size += decrypt_bytes.size();
  hash->Update(mode_bytes.data(), mode_bytes.size());
  parameter_section_bytes += mode_bytes;
  command_size += mode_bytes.size();
  hash->Update(iv_in_bytes.data(), iv_in_bytes.size());
  parameter_section_bytes += iv_in_bytes;
  command_size += iv_in_bytes.size();
  hash->Update(in_data_bytes.data(), in_data_bytes.size());
  parameter_section_bytes += in_data_bytes;
  command_size += in_data_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_EncryptDecrypt(
    const std::string& response,
    TPM2B_MAX_BUFFER* out_data,
    TPM2B_IV* iv_out,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_EncryptDecrypt;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string out_data_bytes;
  rc = Parse_TPM2B_MAX_BUFFER(&buffer, out_data, &out_data_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string iv_out_bytes;
  rc = Parse_TPM2B_IV(&buffer, iv_out, &iv_out_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = out_data_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    out_data_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_MAX_BUFFER(&out_data_bytes, out_data, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void EncryptDecryptErrorCallback(const Tpm::EncryptDecryptResponse& callback,
                                 TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_MAX_BUFFER(), TPM2B_IV());
}

void EncryptDecryptResponseParser(const Tpm::EncryptDecryptResponse& callback,
                                  AuthorizationDelegate* authorization_delegate,
                                  const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(EncryptDecryptErrorCallback, callback);
  TPM2B_MAX_BUFFER out_data;
  TPM2B_IV iv_out;
  TPM_RC rc = Tpm::ParseResponse_EncryptDecrypt(response, &out_data, &iv_out,
                                                authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, out_data, iv_out);
}

void Tpm::EncryptDecrypt(const TPMI_DH_OBJECT& key_handle,
                         const std::string& key_handle_name,
                         const TPMI_YES_NO& decrypt,
                         const TPMI_ALG_SYM_MODE& mode,
                         const TPM2B_IV& iv_in,
                         const TPM2B_MAX_BUFFER& in_data,
                         AuthorizationDelegate* authorization_delegate,
                         const EncryptDecryptResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(EncryptDecryptErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      EncryptDecryptResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_EncryptDecrypt(key_handle, key_handle_name,
                                              decrypt, mode, iv_in, in_data,
                                              &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::EncryptDecryptSync(const TPMI_DH_OBJECT& key_handle,
                               const std::string& key_handle_name,
                               const TPMI_YES_NO& decrypt,
                               const TPMI_ALG_SYM_MODE& mode,
                               const TPM2B_IV& iv_in,
                               const TPM2B_MAX_BUFFER& in_data,
                               TPM2B_MAX_BUFFER* out_data,
                               TPM2B_IV* iv_out,
                               AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_EncryptDecrypt(key_handle, key_handle_name,
                                              decrypt, mode, iv_in, in_data,
                                              &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_EncryptDecrypt(response, out_data, iv_out,
                                    authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_Hash(
    const TPM2B_MAX_BUFFER& data,
    const TPMI_ALG_HASH& hash_alg,
    const TPMI_RH_HIERARCHY& hierarchy,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_Hash;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string data_bytes;
  rc = Serialize_TPM2B_MAX_BUFFER(data, &data_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string hash_alg_bytes;
  rc = Serialize_TPMI_ALG_HASH(hash_alg, &hash_alg_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string hierarchy_bytes;
  rc = Serialize_TPMI_RH_HIERARCHY(hierarchy, &hierarchy_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = data_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    data_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(data_bytes.data(), data_bytes.size());
  parameter_section_bytes += data_bytes;
  command_size += data_bytes.size();
  hash->Update(hash_alg_bytes.data(), hash_alg_bytes.size());
  parameter_section_bytes += hash_alg_bytes;
  command_size += hash_alg_bytes.size();
  hash->Update(hierarchy_bytes.data(), hierarchy_bytes.size());
  parameter_section_bytes += hierarchy_bytes;
  command_size += hierarchy_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_Hash(const std::string& response,
                               TPM2B_DIGEST* out_hash,
                               TPMT_TK_HASHCHECK* validation,
                               AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_Hash;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string out_hash_bytes;
  rc = Parse_TPM2B_DIGEST(&buffer, out_hash, &out_hash_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string validation_bytes;
  rc = Parse_TPMT_TK_HASHCHECK(&buffer, validation, &validation_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = out_hash_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    out_hash_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_DIGEST(&out_hash_bytes, out_hash, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void HashErrorCallback(const Tpm::HashResponse& callback,
                       TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_DIGEST(), TPMT_TK_HASHCHECK());
}

void HashResponseParser(const Tpm::HashResponse& callback,
                        AuthorizationDelegate* authorization_delegate,
                        const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(HashErrorCallback, callback);
  TPM2B_DIGEST out_hash;
  TPMT_TK_HASHCHECK validation;
  TPM_RC rc = Tpm::ParseResponse_Hash(response, &out_hash, &validation,
                                      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, out_hash, validation);
}

void Tpm::Hash(const TPM2B_MAX_BUFFER& data,
               const TPMI_ALG_HASH& hash_alg,
               const TPMI_RH_HIERARCHY& hierarchy,
               AuthorizationDelegate* authorization_delegate,
               const HashResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(HashErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(HashResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_Hash(data, hash_alg, hierarchy, &command,
                                    authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::HashSync(const TPM2B_MAX_BUFFER& data,
                     const TPMI_ALG_HASH& hash_alg,
                     const TPMI_RH_HIERARCHY& hierarchy,
                     TPM2B_DIGEST* out_hash,
                     TPMT_TK_HASHCHECK* validation,
                     AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_Hash(data, hash_alg, hierarchy, &command,
                                    authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_Hash(response, out_hash, validation,
                          authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_HMAC(
    const TPMI_DH_OBJECT& handle,
    const std::string& handle_name,
    const TPM2B_MAX_BUFFER& buffer,
    const TPMI_ALG_HASH& hash_alg,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_HMAC;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(handle, &handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string buffer_bytes;
  rc = Serialize_TPM2B_MAX_BUFFER(buffer, &buffer_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string hash_alg_bytes;
  rc = Serialize_TPMI_ALG_HASH(hash_alg, &hash_alg_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = buffer_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    buffer_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(handle_name.data(), handle_name.size());
  handle_section_bytes += handle_bytes;
  command_size += handle_bytes.size();
  hash->Update(buffer_bytes.data(), buffer_bytes.size());
  parameter_section_bytes += buffer_bytes;
  command_size += buffer_bytes.size();
  hash->Update(hash_alg_bytes.data(), hash_alg_bytes.size());
  parameter_section_bytes += hash_alg_bytes;
  command_size += hash_alg_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_HMAC(const std::string& response,
                               TPM2B_DIGEST* out_hmac,
                               AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_HMAC;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string out_hmac_bytes;
  rc = Parse_TPM2B_DIGEST(&buffer, out_hmac, &out_hmac_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = out_hmac_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    out_hmac_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_DIGEST(&out_hmac_bytes, out_hmac, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void HMACErrorCallback(const Tpm::HMACResponse& callback,
                       TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_DIGEST());
}

void HMACResponseParser(const Tpm::HMACResponse& callback,
                        AuthorizationDelegate* authorization_delegate,
                        const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(HMACErrorCallback, callback);
  TPM2B_DIGEST out_hmac;
  TPM_RC rc =
      Tpm::ParseResponse_HMAC(response, &out_hmac, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, out_hmac);
}

void Tpm::HMAC(const TPMI_DH_OBJECT& handle,
               const std::string& handle_name,
               const TPM2B_MAX_BUFFER& buffer,
               const TPMI_ALG_HASH& hash_alg,
               AuthorizationDelegate* authorization_delegate,
               const HMACResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(HMACErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(HMACResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_HMAC(handle, handle_name, buffer, hash_alg,
                                    &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::HMACSync(const TPMI_DH_OBJECT& handle,
                     const std::string& handle_name,
                     const TPM2B_MAX_BUFFER& buffer,
                     const TPMI_ALG_HASH& hash_alg,
                     TPM2B_DIGEST* out_hmac,
                     AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_HMAC(handle, handle_name, buffer, hash_alg,
                                    &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_HMAC(response, out_hmac, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_GetRandom(
    const UINT16& bytes_requested,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_GetRandom;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string bytes_requested_bytes;
  rc = Serialize_UINT16(bytes_requested, &bytes_requested_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(bytes_requested_bytes.data(), bytes_requested_bytes.size());
  parameter_section_bytes += bytes_requested_bytes;
  command_size += bytes_requested_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_GetRandom(
    const std::string& response,
    TPM2B_DIGEST* random_bytes,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_GetRandom;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string random_bytes_bytes;
  rc = Parse_TPM2B_DIGEST(&buffer, random_bytes, &random_bytes_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = random_bytes_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    random_bytes_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_DIGEST(&random_bytes_bytes, random_bytes, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void GetRandomErrorCallback(const Tpm::GetRandomResponse& callback,
                            TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_DIGEST());
}

void GetRandomResponseParser(const Tpm::GetRandomResponse& callback,
                             AuthorizationDelegate* authorization_delegate,
                             const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(GetRandomErrorCallback, callback);
  TPM2B_DIGEST random_bytes;
  TPM_RC rc = Tpm::ParseResponse_GetRandom(response, &random_bytes,
                                           authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, random_bytes);
}

void Tpm::GetRandom(const UINT16& bytes_requested,
                    AuthorizationDelegate* authorization_delegate,
                    const GetRandomResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(GetRandomErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(GetRandomResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_GetRandom(bytes_requested, &command,
                                         authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::GetRandomSync(const UINT16& bytes_requested,
                          TPM2B_DIGEST* random_bytes,
                          AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_GetRandom(bytes_requested, &command,
                                         authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_GetRandom(response, random_bytes, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_StirRandom(
    const TPM2B_SENSITIVE_DATA& in_data,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_StirRandom;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string in_data_bytes;
  rc = Serialize_TPM2B_SENSITIVE_DATA(in_data, &in_data_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = in_data_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    in_data_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(in_data_bytes.data(), in_data_bytes.size());
  parameter_section_bytes += in_data_bytes;
  command_size += in_data_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_StirRandom(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_StirRandom;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void StirRandomErrorCallback(const Tpm::StirRandomResponse& callback,
                             TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void StirRandomResponseParser(const Tpm::StirRandomResponse& callback,
                              AuthorizationDelegate* authorization_delegate,
                              const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(StirRandomErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_StirRandom(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::StirRandom(const TPM2B_SENSITIVE_DATA& in_data,
                     AuthorizationDelegate* authorization_delegate,
                     const StirRandomResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(StirRandomErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(StirRandomResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc =
      SerializeCommand_StirRandom(in_data, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::StirRandomSync(const TPM2B_SENSITIVE_DATA& in_data,
                           AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc =
      SerializeCommand_StirRandom(in_data, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_StirRandom(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_HMAC_Start(
    const TPMI_DH_OBJECT& handle,
    const std::string& handle_name,
    const TPM2B_AUTH& auth,
    const TPMI_ALG_HASH& hash_alg,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_HMAC_Start;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(handle, &handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_bytes;
  rc = Serialize_TPM2B_AUTH(auth, &auth_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string hash_alg_bytes;
  rc = Serialize_TPMI_ALG_HASH(hash_alg, &hash_alg_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = auth_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    auth_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(handle_name.data(), handle_name.size());
  handle_section_bytes += handle_bytes;
  command_size += handle_bytes.size();
  hash->Update(auth_bytes.data(), auth_bytes.size());
  parameter_section_bytes += auth_bytes;
  command_size += auth_bytes.size();
  hash->Update(hash_alg_bytes.data(), hash_alg_bytes.size());
  parameter_section_bytes += hash_alg_bytes;
  command_size += hash_alg_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_HMAC_Start(
    const std::string& response,
    TPMI_DH_OBJECT* sequence_handle,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  std::string sequence_handle_bytes;
  rc = Parse_TPMI_DH_OBJECT(&buffer, sequence_handle, &sequence_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_CC command_code = TPM_CC_HMAC_Start;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void HMAC_StartErrorCallback(const Tpm::HMAC_StartResponse& callback,
                             TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPMI_DH_OBJECT());
}

void HMAC_StartResponseParser(const Tpm::HMAC_StartResponse& callback,
                              AuthorizationDelegate* authorization_delegate,
                              const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(HMAC_StartErrorCallback, callback);
  TPMI_DH_OBJECT sequence_handle;
  TPM_RC rc = Tpm::ParseResponse_HMAC_Start(response, &sequence_handle,
                                            authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, sequence_handle);
}

void Tpm::HMAC_Start(const TPMI_DH_OBJECT& handle,
                     const std::string& handle_name,
                     const TPM2B_AUTH& auth,
                     const TPMI_ALG_HASH& hash_alg,
                     AuthorizationDelegate* authorization_delegate,
                     const HMAC_StartResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(HMAC_StartErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(HMAC_StartResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_HMAC_Start(handle, handle_name, auth, hash_alg,
                                          &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::HMAC_StartSync(const TPMI_DH_OBJECT& handle,
                           const std::string& handle_name,
                           const TPM2B_AUTH& auth,
                           const TPMI_ALG_HASH& hash_alg,
                           TPMI_DH_OBJECT* sequence_handle,
                           AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_HMAC_Start(handle, handle_name, auth, hash_alg,
                                          &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_HMAC_Start(response, sequence_handle,
                                authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_HashSequenceStart(
    const TPM2B_AUTH& auth,
    const TPMI_ALG_HASH& hash_alg,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_HashSequenceStart;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_bytes;
  rc = Serialize_TPM2B_AUTH(auth, &auth_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string hash_alg_bytes;
  rc = Serialize_TPMI_ALG_HASH(hash_alg, &hash_alg_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = auth_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    auth_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(auth_bytes.data(), auth_bytes.size());
  parameter_section_bytes += auth_bytes;
  command_size += auth_bytes.size();
  hash->Update(hash_alg_bytes.data(), hash_alg_bytes.size());
  parameter_section_bytes += hash_alg_bytes;
  command_size += hash_alg_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_HashSequenceStart(
    const std::string& response,
    TPMI_DH_OBJECT* sequence_handle,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  std::string sequence_handle_bytes;
  rc = Parse_TPMI_DH_OBJECT(&buffer, sequence_handle, &sequence_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_CC command_code = TPM_CC_HashSequenceStart;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void HashSequenceStartErrorCallback(
    const Tpm::HashSequenceStartResponse& callback,
    TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPMI_DH_OBJECT());
}

void HashSequenceStartResponseParser(
    const Tpm::HashSequenceStartResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(HashSequenceStartErrorCallback, callback);
  TPMI_DH_OBJECT sequence_handle;
  TPM_RC rc = Tpm::ParseResponse_HashSequenceStart(response, &sequence_handle,
                                                   authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, sequence_handle);
}

void Tpm::HashSequenceStart(const TPM2B_AUTH& auth,
                            const TPMI_ALG_HASH& hash_alg,
                            AuthorizationDelegate* authorization_delegate,
                            const HashSequenceStartResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(HashSequenceStartErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      HashSequenceStartResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_HashSequenceStart(auth, hash_alg, &command,
                                                 authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::HashSequenceStartSync(
    const TPM2B_AUTH& auth,
    const TPMI_ALG_HASH& hash_alg,
    TPMI_DH_OBJECT* sequence_handle,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_HashSequenceStart(auth, hash_alg, &command,
                                                 authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_HashSequenceStart(response, sequence_handle,
                                       authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_SequenceUpdate(
    const TPMI_DH_OBJECT& sequence_handle,
    const std::string& sequence_handle_name,
    const TPM2B_MAX_BUFFER& buffer,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_SequenceUpdate;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string sequence_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(sequence_handle, &sequence_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string buffer_bytes;
  rc = Serialize_TPM2B_MAX_BUFFER(buffer, &buffer_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = buffer_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    buffer_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(sequence_handle_name.data(), sequence_handle_name.size());
  handle_section_bytes += sequence_handle_bytes;
  command_size += sequence_handle_bytes.size();
  hash->Update(buffer_bytes.data(), buffer_bytes.size());
  parameter_section_bytes += buffer_bytes;
  command_size += buffer_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_SequenceUpdate(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_SequenceUpdate;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void SequenceUpdateErrorCallback(const Tpm::SequenceUpdateResponse& callback,
                                 TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void SequenceUpdateResponseParser(const Tpm::SequenceUpdateResponse& callback,
                                  AuthorizationDelegate* authorization_delegate,
                                  const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(SequenceUpdateErrorCallback, callback);
  TPM_RC rc =
      Tpm::ParseResponse_SequenceUpdate(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::SequenceUpdate(const TPMI_DH_OBJECT& sequence_handle,
                         const std::string& sequence_handle_name,
                         const TPM2B_MAX_BUFFER& buffer,
                         AuthorizationDelegate* authorization_delegate,
                         const SequenceUpdateResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(SequenceUpdateErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      SequenceUpdateResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc =
      SerializeCommand_SequenceUpdate(sequence_handle, sequence_handle_name,
                                      buffer, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::SequenceUpdateSync(const TPMI_DH_OBJECT& sequence_handle,
                               const std::string& sequence_handle_name,
                               const TPM2B_MAX_BUFFER& buffer,
                               AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc =
      SerializeCommand_SequenceUpdate(sequence_handle, sequence_handle_name,
                                      buffer, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_SequenceUpdate(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_SequenceComplete(
    const TPMI_DH_OBJECT& sequence_handle,
    const std::string& sequence_handle_name,
    const TPM2B_MAX_BUFFER& buffer,
    const TPMI_RH_HIERARCHY& hierarchy,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_SequenceComplete;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string sequence_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(sequence_handle, &sequence_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string buffer_bytes;
  rc = Serialize_TPM2B_MAX_BUFFER(buffer, &buffer_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string hierarchy_bytes;
  rc = Serialize_TPMI_RH_HIERARCHY(hierarchy, &hierarchy_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = buffer_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    buffer_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(sequence_handle_name.data(), sequence_handle_name.size());
  handle_section_bytes += sequence_handle_bytes;
  command_size += sequence_handle_bytes.size();
  hash->Update(buffer_bytes.data(), buffer_bytes.size());
  parameter_section_bytes += buffer_bytes;
  command_size += buffer_bytes.size();
  hash->Update(hierarchy_bytes.data(), hierarchy_bytes.size());
  parameter_section_bytes += hierarchy_bytes;
  command_size += hierarchy_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_SequenceComplete(
    const std::string& response,
    TPM2B_DIGEST* result,
    TPMT_TK_HASHCHECK* validation,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_SequenceComplete;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string result_bytes;
  rc = Parse_TPM2B_DIGEST(&buffer, result, &result_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string validation_bytes;
  rc = Parse_TPMT_TK_HASHCHECK(&buffer, validation, &validation_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = result_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    result_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_DIGEST(&result_bytes, result, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void SequenceCompleteErrorCallback(
    const Tpm::SequenceCompleteResponse& callback,
    TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_DIGEST(), TPMT_TK_HASHCHECK());
}

void SequenceCompleteResponseParser(
    const Tpm::SequenceCompleteResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(SequenceCompleteErrorCallback, callback);
  TPM2B_DIGEST result;
  TPMT_TK_HASHCHECK validation;
  TPM_RC rc = Tpm::ParseResponse_SequenceComplete(
      response, &result, &validation, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, result, validation);
}

void Tpm::SequenceComplete(const TPMI_DH_OBJECT& sequence_handle,
                           const std::string& sequence_handle_name,
                           const TPM2B_MAX_BUFFER& buffer,
                           const TPMI_RH_HIERARCHY& hierarchy,
                           AuthorizationDelegate* authorization_delegate,
                           const SequenceCompleteResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(SequenceCompleteErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      SequenceCompleteResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_SequenceComplete(
      sequence_handle, sequence_handle_name, buffer, hierarchy, &command,
      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::SequenceCompleteSync(
    const TPMI_DH_OBJECT& sequence_handle,
    const std::string& sequence_handle_name,
    const TPM2B_MAX_BUFFER& buffer,
    const TPMI_RH_HIERARCHY& hierarchy,
    TPM2B_DIGEST* result,
    TPMT_TK_HASHCHECK* validation,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_SequenceComplete(
      sequence_handle, sequence_handle_name, buffer, hierarchy, &command,
      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_SequenceComplete(response, result, validation,
                                      authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_EventSequenceComplete(
    const TPMI_DH_PCR& pcr_handle,
    const std::string& pcr_handle_name,
    const TPMI_DH_OBJECT& sequence_handle,
    const std::string& sequence_handle_name,
    const TPM2B_MAX_BUFFER& buffer,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_EventSequenceComplete;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string pcr_handle_bytes;
  rc = Serialize_TPMI_DH_PCR(pcr_handle, &pcr_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string sequence_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(sequence_handle, &sequence_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string buffer_bytes;
  rc = Serialize_TPM2B_MAX_BUFFER(buffer, &buffer_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = buffer_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    buffer_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(pcr_handle_name.data(), pcr_handle_name.size());
  handle_section_bytes += pcr_handle_bytes;
  command_size += pcr_handle_bytes.size();
  hash->Update(sequence_handle_name.data(), sequence_handle_name.size());
  handle_section_bytes += sequence_handle_bytes;
  command_size += sequence_handle_bytes.size();
  hash->Update(buffer_bytes.data(), buffer_bytes.size());
  parameter_section_bytes += buffer_bytes;
  command_size += buffer_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_EventSequenceComplete(
    const std::string& response,
    TPML_DIGEST_VALUES* results,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_EventSequenceComplete;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string results_bytes;
  rc = Parse_TPML_DIGEST_VALUES(&buffer, results, &results_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  return TPM_RC_SUCCESS;
}

void EventSequenceCompleteErrorCallback(
    const Tpm::EventSequenceCompleteResponse& callback,
    TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPML_DIGEST_VALUES());
}

void EventSequenceCompleteResponseParser(
    const Tpm::EventSequenceCompleteResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(EventSequenceCompleteErrorCallback, callback);
  TPML_DIGEST_VALUES results;
  TPM_RC rc = Tpm::ParseResponse_EventSequenceComplete(response, &results,
                                                       authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, results);
}

void Tpm::EventSequenceComplete(const TPMI_DH_PCR& pcr_handle,
                                const std::string& pcr_handle_name,
                                const TPMI_DH_OBJECT& sequence_handle,
                                const std::string& sequence_handle_name,
                                const TPM2B_MAX_BUFFER& buffer,
                                AuthorizationDelegate* authorization_delegate,
                                const EventSequenceCompleteResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(EventSequenceCompleteErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      EventSequenceCompleteResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_EventSequenceComplete(
      pcr_handle, pcr_handle_name, sequence_handle, sequence_handle_name,
      buffer, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::EventSequenceCompleteSync(
    const TPMI_DH_PCR& pcr_handle,
    const std::string& pcr_handle_name,
    const TPMI_DH_OBJECT& sequence_handle,
    const std::string& sequence_handle_name,
    const TPM2B_MAX_BUFFER& buffer,
    TPML_DIGEST_VALUES* results,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_EventSequenceComplete(
      pcr_handle, pcr_handle_name, sequence_handle, sequence_handle_name,
      buffer, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_EventSequenceComplete(response, results,
                                           authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_Certify(
    const TPMI_DH_OBJECT& object_handle,
    const std::string& object_handle_name,
    const TPMI_DH_OBJECT& sign_handle,
    const std::string& sign_handle_name,
    const TPM2B_DATA& qualifying_data,
    const TPMT_SIG_SCHEME& in_scheme,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_Certify;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string object_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(object_handle, &object_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string sign_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(sign_handle, &sign_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string qualifying_data_bytes;
  rc = Serialize_TPM2B_DATA(qualifying_data, &qualifying_data_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string in_scheme_bytes;
  rc = Serialize_TPMT_SIG_SCHEME(in_scheme, &in_scheme_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = qualifying_data_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    qualifying_data_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(object_handle_name.data(), object_handle_name.size());
  handle_section_bytes += object_handle_bytes;
  command_size += object_handle_bytes.size();
  hash->Update(sign_handle_name.data(), sign_handle_name.size());
  handle_section_bytes += sign_handle_bytes;
  command_size += sign_handle_bytes.size();
  hash->Update(qualifying_data_bytes.data(), qualifying_data_bytes.size());
  parameter_section_bytes += qualifying_data_bytes;
  command_size += qualifying_data_bytes.size();
  hash->Update(in_scheme_bytes.data(), in_scheme_bytes.size());
  parameter_section_bytes += in_scheme_bytes;
  command_size += in_scheme_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_Certify(
    const std::string& response,
    TPM2B_ATTEST* certify_info,
    TPMT_SIGNATURE* signature,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_Certify;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string certify_info_bytes;
  rc = Parse_TPM2B_ATTEST(&buffer, certify_info, &certify_info_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string signature_bytes;
  rc = Parse_TPMT_SIGNATURE(&buffer, signature, &signature_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = certify_info_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    certify_info_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_ATTEST(&certify_info_bytes, certify_info, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void CertifyErrorCallback(const Tpm::CertifyResponse& callback,
                          TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_ATTEST(), TPMT_SIGNATURE());
}

void CertifyResponseParser(const Tpm::CertifyResponse& callback,
                           AuthorizationDelegate* authorization_delegate,
                           const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(CertifyErrorCallback, callback);
  TPM2B_ATTEST certify_info;
  TPMT_SIGNATURE signature;
  TPM_RC rc = Tpm::ParseResponse_Certify(response, &certify_info, &signature,
                                         authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, certify_info, signature);
}

void Tpm::Certify(const TPMI_DH_OBJECT& object_handle,
                  const std::string& object_handle_name,
                  const TPMI_DH_OBJECT& sign_handle,
                  const std::string& sign_handle_name,
                  const TPM2B_DATA& qualifying_data,
                  const TPMT_SIG_SCHEME& in_scheme,
                  AuthorizationDelegate* authorization_delegate,
                  const CertifyResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(CertifyErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(CertifyResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_Certify(
      object_handle, object_handle_name, sign_handle, sign_handle_name,
      qualifying_data, in_scheme, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::CertifySync(const TPMI_DH_OBJECT& object_handle,
                        const std::string& object_handle_name,
                        const TPMI_DH_OBJECT& sign_handle,
                        const std::string& sign_handle_name,
                        const TPM2B_DATA& qualifying_data,
                        const TPMT_SIG_SCHEME& in_scheme,
                        TPM2B_ATTEST* certify_info,
                        TPMT_SIGNATURE* signature,
                        AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_Certify(
      object_handle, object_handle_name, sign_handle, sign_handle_name,
      qualifying_data, in_scheme, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_Certify(response, certify_info, signature,
                             authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_CertifyCreation(
    const TPMI_DH_OBJECT& sign_handle,
    const std::string& sign_handle_name,
    const TPMI_DH_OBJECT& object_handle,
    const std::string& object_handle_name,
    const TPM2B_DATA& qualifying_data,
    const TPM2B_DIGEST& creation_hash,
    const TPMT_SIG_SCHEME& in_scheme,
    const TPMT_TK_CREATION& creation_ticket,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_CertifyCreation;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string sign_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(sign_handle, &sign_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string object_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(object_handle, &object_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string qualifying_data_bytes;
  rc = Serialize_TPM2B_DATA(qualifying_data, &qualifying_data_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string creation_hash_bytes;
  rc = Serialize_TPM2B_DIGEST(creation_hash, &creation_hash_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string in_scheme_bytes;
  rc = Serialize_TPMT_SIG_SCHEME(in_scheme, &in_scheme_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string creation_ticket_bytes;
  rc = Serialize_TPMT_TK_CREATION(creation_ticket, &creation_ticket_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = qualifying_data_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    qualifying_data_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(sign_handle_name.data(), sign_handle_name.size());
  handle_section_bytes += sign_handle_bytes;
  command_size += sign_handle_bytes.size();
  hash->Update(object_handle_name.data(), object_handle_name.size());
  handle_section_bytes += object_handle_bytes;
  command_size += object_handle_bytes.size();
  hash->Update(qualifying_data_bytes.data(), qualifying_data_bytes.size());
  parameter_section_bytes += qualifying_data_bytes;
  command_size += qualifying_data_bytes.size();
  hash->Update(creation_hash_bytes.data(), creation_hash_bytes.size());
  parameter_section_bytes += creation_hash_bytes;
  command_size += creation_hash_bytes.size();
  hash->Update(in_scheme_bytes.data(), in_scheme_bytes.size());
  parameter_section_bytes += in_scheme_bytes;
  command_size += in_scheme_bytes.size();
  hash->Update(creation_ticket_bytes.data(), creation_ticket_bytes.size());
  parameter_section_bytes += creation_ticket_bytes;
  command_size += creation_ticket_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_CertifyCreation(
    const std::string& response,
    TPM2B_ATTEST* certify_info,
    TPMT_SIGNATURE* signature,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_CertifyCreation;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string certify_info_bytes;
  rc = Parse_TPM2B_ATTEST(&buffer, certify_info, &certify_info_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string signature_bytes;
  rc = Parse_TPMT_SIGNATURE(&buffer, signature, &signature_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = certify_info_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    certify_info_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_ATTEST(&certify_info_bytes, certify_info, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void CertifyCreationErrorCallback(const Tpm::CertifyCreationResponse& callback,
                                  TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_ATTEST(), TPMT_SIGNATURE());
}

void CertifyCreationResponseParser(
    const Tpm::CertifyCreationResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(CertifyCreationErrorCallback, callback);
  TPM2B_ATTEST certify_info;
  TPMT_SIGNATURE signature;
  TPM_RC rc = Tpm::ParseResponse_CertifyCreation(
      response, &certify_info, &signature, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, certify_info, signature);
}

void Tpm::CertifyCreation(const TPMI_DH_OBJECT& sign_handle,
                          const std::string& sign_handle_name,
                          const TPMI_DH_OBJECT& object_handle,
                          const std::string& object_handle_name,
                          const TPM2B_DATA& qualifying_data,
                          const TPM2B_DIGEST& creation_hash,
                          const TPMT_SIG_SCHEME& in_scheme,
                          const TPMT_TK_CREATION& creation_ticket,
                          AuthorizationDelegate* authorization_delegate,
                          const CertifyCreationResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(CertifyCreationErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      CertifyCreationResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_CertifyCreation(
      sign_handle, sign_handle_name, object_handle, object_handle_name,
      qualifying_data, creation_hash, in_scheme, creation_ticket, &command,
      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::CertifyCreationSync(const TPMI_DH_OBJECT& sign_handle,
                                const std::string& sign_handle_name,
                                const TPMI_DH_OBJECT& object_handle,
                                const std::string& object_handle_name,
                                const TPM2B_DATA& qualifying_data,
                                const TPM2B_DIGEST& creation_hash,
                                const TPMT_SIG_SCHEME& in_scheme,
                                const TPMT_TK_CREATION& creation_ticket,
                                TPM2B_ATTEST* certify_info,
                                TPMT_SIGNATURE* signature,
                                AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_CertifyCreation(
      sign_handle, sign_handle_name, object_handle, object_handle_name,
      qualifying_data, creation_hash, in_scheme, creation_ticket, &command,
      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_CertifyCreation(response, certify_info, signature,
                                     authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_Quote(
    const TPMI_DH_OBJECT& sign_handle,
    const std::string& sign_handle_name,
    const TPM2B_DATA& qualifying_data,
    const TPMT_SIG_SCHEME& in_scheme,
    const TPML_PCR_SELECTION& pcrselect,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_Quote;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string sign_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(sign_handle, &sign_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string qualifying_data_bytes;
  rc = Serialize_TPM2B_DATA(qualifying_data, &qualifying_data_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string in_scheme_bytes;
  rc = Serialize_TPMT_SIG_SCHEME(in_scheme, &in_scheme_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string pcrselect_bytes;
  rc = Serialize_TPML_PCR_SELECTION(pcrselect, &pcrselect_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = qualifying_data_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    qualifying_data_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(sign_handle_name.data(), sign_handle_name.size());
  handle_section_bytes += sign_handle_bytes;
  command_size += sign_handle_bytes.size();
  hash->Update(qualifying_data_bytes.data(), qualifying_data_bytes.size());
  parameter_section_bytes += qualifying_data_bytes;
  command_size += qualifying_data_bytes.size();
  hash->Update(in_scheme_bytes.data(), in_scheme_bytes.size());
  parameter_section_bytes += in_scheme_bytes;
  command_size += in_scheme_bytes.size();
  hash->Update(pcrselect_bytes.data(), pcrselect_bytes.size());
  parameter_section_bytes += pcrselect_bytes;
  command_size += pcrselect_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_Quote(const std::string& response,
                                TPM2B_ATTEST* quoted,
                                TPMT_SIGNATURE* signature,
                                AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_Quote;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string quoted_bytes;
  rc = Parse_TPM2B_ATTEST(&buffer, quoted, &quoted_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string signature_bytes;
  rc = Parse_TPMT_SIGNATURE(&buffer, signature, &signature_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = quoted_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    quoted_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_ATTEST(&quoted_bytes, quoted, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void QuoteErrorCallback(const Tpm::QuoteResponse& callback,
                        TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_ATTEST(), TPMT_SIGNATURE());
}

void QuoteResponseParser(const Tpm::QuoteResponse& callback,
                         AuthorizationDelegate* authorization_delegate,
                         const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(QuoteErrorCallback, callback);
  TPM2B_ATTEST quoted;
  TPMT_SIGNATURE signature;
  TPM_RC rc = Tpm::ParseResponse_Quote(response, &quoted, &signature,
                                       authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, quoted, signature);
}

void Tpm::Quote(const TPMI_DH_OBJECT& sign_handle,
                const std::string& sign_handle_name,
                const TPM2B_DATA& qualifying_data,
                const TPMT_SIG_SCHEME& in_scheme,
                const TPML_PCR_SELECTION& pcrselect,
                AuthorizationDelegate* authorization_delegate,
                const QuoteResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(QuoteErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(QuoteResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_Quote(sign_handle, sign_handle_name,
                                     qualifying_data, in_scheme, pcrselect,
                                     &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::QuoteSync(const TPMI_DH_OBJECT& sign_handle,
                      const std::string& sign_handle_name,
                      const TPM2B_DATA& qualifying_data,
                      const TPMT_SIG_SCHEME& in_scheme,
                      const TPML_PCR_SELECTION& pcrselect,
                      TPM2B_ATTEST* quoted,
                      TPMT_SIGNATURE* signature,
                      AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_Quote(sign_handle, sign_handle_name,
                                     qualifying_data, in_scheme, pcrselect,
                                     &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_Quote(response, quoted, signature, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_GetSessionAuditDigest(
    const TPMI_RH_ENDORSEMENT& privacy_admin_handle,
    const std::string& privacy_admin_handle_name,
    const TPMI_DH_OBJECT& sign_handle,
    const std::string& sign_handle_name,
    const TPMI_SH_HMAC& session_handle,
    const std::string& session_handle_name,
    const TPM2B_DATA& qualifying_data,
    const TPMT_SIG_SCHEME& in_scheme,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_GetSessionAuditDigest;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string privacy_admin_handle_bytes;
  rc = Serialize_TPMI_RH_ENDORSEMENT(privacy_admin_handle,
                                     &privacy_admin_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string sign_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(sign_handle, &sign_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string session_handle_bytes;
  rc = Serialize_TPMI_SH_HMAC(session_handle, &session_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string qualifying_data_bytes;
  rc = Serialize_TPM2B_DATA(qualifying_data, &qualifying_data_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string in_scheme_bytes;
  rc = Serialize_TPMT_SIG_SCHEME(in_scheme, &in_scheme_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = qualifying_data_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    qualifying_data_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(privacy_admin_handle_name.data(),
               privacy_admin_handle_name.size());
  handle_section_bytes += privacy_admin_handle_bytes;
  command_size += privacy_admin_handle_bytes.size();
  hash->Update(sign_handle_name.data(), sign_handle_name.size());
  handle_section_bytes += sign_handle_bytes;
  command_size += sign_handle_bytes.size();
  hash->Update(session_handle_name.data(), session_handle_name.size());
  handle_section_bytes += session_handle_bytes;
  command_size += session_handle_bytes.size();
  hash->Update(qualifying_data_bytes.data(), qualifying_data_bytes.size());
  parameter_section_bytes += qualifying_data_bytes;
  command_size += qualifying_data_bytes.size();
  hash->Update(in_scheme_bytes.data(), in_scheme_bytes.size());
  parameter_section_bytes += in_scheme_bytes;
  command_size += in_scheme_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_GetSessionAuditDigest(
    const std::string& response,
    TPM2B_ATTEST* audit_info,
    TPMT_SIGNATURE* signature,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_GetSessionAuditDigest;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string audit_info_bytes;
  rc = Parse_TPM2B_ATTEST(&buffer, audit_info, &audit_info_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string signature_bytes;
  rc = Parse_TPMT_SIGNATURE(&buffer, signature, &signature_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = audit_info_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    audit_info_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_ATTEST(&audit_info_bytes, audit_info, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void GetSessionAuditDigestErrorCallback(
    const Tpm::GetSessionAuditDigestResponse& callback,
    TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_ATTEST(), TPMT_SIGNATURE());
}

void GetSessionAuditDigestResponseParser(
    const Tpm::GetSessionAuditDigestResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(GetSessionAuditDigestErrorCallback, callback);
  TPM2B_ATTEST audit_info;
  TPMT_SIGNATURE signature;
  TPM_RC rc = Tpm::ParseResponse_GetSessionAuditDigest(
      response, &audit_info, &signature, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, audit_info, signature);
}

void Tpm::GetSessionAuditDigest(const TPMI_RH_ENDORSEMENT& privacy_admin_handle,
                                const std::string& privacy_admin_handle_name,
                                const TPMI_DH_OBJECT& sign_handle,
                                const std::string& sign_handle_name,
                                const TPMI_SH_HMAC& session_handle,
                                const std::string& session_handle_name,
                                const TPM2B_DATA& qualifying_data,
                                const TPMT_SIG_SCHEME& in_scheme,
                                AuthorizationDelegate* authorization_delegate,
                                const GetSessionAuditDigestResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(GetSessionAuditDigestErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      GetSessionAuditDigestResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_GetSessionAuditDigest(
      privacy_admin_handle, privacy_admin_handle_name, sign_handle,
      sign_handle_name, session_handle, session_handle_name, qualifying_data,
      in_scheme, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::GetSessionAuditDigestSync(
    const TPMI_RH_ENDORSEMENT& privacy_admin_handle,
    const std::string& privacy_admin_handle_name,
    const TPMI_DH_OBJECT& sign_handle,
    const std::string& sign_handle_name,
    const TPMI_SH_HMAC& session_handle,
    const std::string& session_handle_name,
    const TPM2B_DATA& qualifying_data,
    const TPMT_SIG_SCHEME& in_scheme,
    TPM2B_ATTEST* audit_info,
    TPMT_SIGNATURE* signature,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_GetSessionAuditDigest(
      privacy_admin_handle, privacy_admin_handle_name, sign_handle,
      sign_handle_name, session_handle, session_handle_name, qualifying_data,
      in_scheme, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_GetSessionAuditDigest(response, audit_info, signature,
                                           authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_GetCommandAuditDigest(
    const TPMI_RH_ENDORSEMENT& privacy_handle,
    const std::string& privacy_handle_name,
    const TPMI_DH_OBJECT& sign_handle,
    const std::string& sign_handle_name,
    const TPM2B_DATA& qualifying_data,
    const TPMT_SIG_SCHEME& in_scheme,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_GetCommandAuditDigest;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string privacy_handle_bytes;
  rc = Serialize_TPMI_RH_ENDORSEMENT(privacy_handle, &privacy_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string sign_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(sign_handle, &sign_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string qualifying_data_bytes;
  rc = Serialize_TPM2B_DATA(qualifying_data, &qualifying_data_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string in_scheme_bytes;
  rc = Serialize_TPMT_SIG_SCHEME(in_scheme, &in_scheme_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = qualifying_data_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    qualifying_data_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(privacy_handle_name.data(), privacy_handle_name.size());
  handle_section_bytes += privacy_handle_bytes;
  command_size += privacy_handle_bytes.size();
  hash->Update(sign_handle_name.data(), sign_handle_name.size());
  handle_section_bytes += sign_handle_bytes;
  command_size += sign_handle_bytes.size();
  hash->Update(qualifying_data_bytes.data(), qualifying_data_bytes.size());
  parameter_section_bytes += qualifying_data_bytes;
  command_size += qualifying_data_bytes.size();
  hash->Update(in_scheme_bytes.data(), in_scheme_bytes.size());
  parameter_section_bytes += in_scheme_bytes;
  command_size += in_scheme_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_GetCommandAuditDigest(
    const std::string& response,
    TPM2B_ATTEST* audit_info,
    TPMT_SIGNATURE* signature,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_GetCommandAuditDigest;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string audit_info_bytes;
  rc = Parse_TPM2B_ATTEST(&buffer, audit_info, &audit_info_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string signature_bytes;
  rc = Parse_TPMT_SIGNATURE(&buffer, signature, &signature_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = audit_info_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    audit_info_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_ATTEST(&audit_info_bytes, audit_info, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void GetCommandAuditDigestErrorCallback(
    const Tpm::GetCommandAuditDigestResponse& callback,
    TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_ATTEST(), TPMT_SIGNATURE());
}

void GetCommandAuditDigestResponseParser(
    const Tpm::GetCommandAuditDigestResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(GetCommandAuditDigestErrorCallback, callback);
  TPM2B_ATTEST audit_info;
  TPMT_SIGNATURE signature;
  TPM_RC rc = Tpm::ParseResponse_GetCommandAuditDigest(
      response, &audit_info, &signature, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, audit_info, signature);
}

void Tpm::GetCommandAuditDigest(const TPMI_RH_ENDORSEMENT& privacy_handle,
                                const std::string& privacy_handle_name,
                                const TPMI_DH_OBJECT& sign_handle,
                                const std::string& sign_handle_name,
                                const TPM2B_DATA& qualifying_data,
                                const TPMT_SIG_SCHEME& in_scheme,
                                AuthorizationDelegate* authorization_delegate,
                                const GetCommandAuditDigestResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(GetCommandAuditDigestErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      GetCommandAuditDigestResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_GetCommandAuditDigest(
      privacy_handle, privacy_handle_name, sign_handle, sign_handle_name,
      qualifying_data, in_scheme, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::GetCommandAuditDigestSync(
    const TPMI_RH_ENDORSEMENT& privacy_handle,
    const std::string& privacy_handle_name,
    const TPMI_DH_OBJECT& sign_handle,
    const std::string& sign_handle_name,
    const TPM2B_DATA& qualifying_data,
    const TPMT_SIG_SCHEME& in_scheme,
    TPM2B_ATTEST* audit_info,
    TPMT_SIGNATURE* signature,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_GetCommandAuditDigest(
      privacy_handle, privacy_handle_name, sign_handle, sign_handle_name,
      qualifying_data, in_scheme, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_GetCommandAuditDigest(response, audit_info, signature,
                                           authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_GetTime(
    const TPMI_RH_ENDORSEMENT& privacy_admin_handle,
    const std::string& privacy_admin_handle_name,
    const TPMI_DH_OBJECT& sign_handle,
    const std::string& sign_handle_name,
    const TPM2B_DATA& qualifying_data,
    const TPMT_SIG_SCHEME& in_scheme,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_GetTime;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string privacy_admin_handle_bytes;
  rc = Serialize_TPMI_RH_ENDORSEMENT(privacy_admin_handle,
                                     &privacy_admin_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string sign_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(sign_handle, &sign_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string qualifying_data_bytes;
  rc = Serialize_TPM2B_DATA(qualifying_data, &qualifying_data_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string in_scheme_bytes;
  rc = Serialize_TPMT_SIG_SCHEME(in_scheme, &in_scheme_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = qualifying_data_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    qualifying_data_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(privacy_admin_handle_name.data(),
               privacy_admin_handle_name.size());
  handle_section_bytes += privacy_admin_handle_bytes;
  command_size += privacy_admin_handle_bytes.size();
  hash->Update(sign_handle_name.data(), sign_handle_name.size());
  handle_section_bytes += sign_handle_bytes;
  command_size += sign_handle_bytes.size();
  hash->Update(qualifying_data_bytes.data(), qualifying_data_bytes.size());
  parameter_section_bytes += qualifying_data_bytes;
  command_size += qualifying_data_bytes.size();
  hash->Update(in_scheme_bytes.data(), in_scheme_bytes.size());
  parameter_section_bytes += in_scheme_bytes;
  command_size += in_scheme_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_GetTime(
    const std::string& response,
    TPM2B_ATTEST* time_info,
    TPMT_SIGNATURE* signature,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_GetTime;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string time_info_bytes;
  rc = Parse_TPM2B_ATTEST(&buffer, time_info, &time_info_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string signature_bytes;
  rc = Parse_TPMT_SIGNATURE(&buffer, signature, &signature_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = time_info_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    time_info_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_ATTEST(&time_info_bytes, time_info, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void GetTimeErrorCallback(const Tpm::GetTimeResponse& callback,
                          TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_ATTEST(), TPMT_SIGNATURE());
}

void GetTimeResponseParser(const Tpm::GetTimeResponse& callback,
                           AuthorizationDelegate* authorization_delegate,
                           const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(GetTimeErrorCallback, callback);
  TPM2B_ATTEST time_info;
  TPMT_SIGNATURE signature;
  TPM_RC rc = Tpm::ParseResponse_GetTime(response, &time_info, &signature,
                                         authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, time_info, signature);
}

void Tpm::GetTime(const TPMI_RH_ENDORSEMENT& privacy_admin_handle,
                  const std::string& privacy_admin_handle_name,
                  const TPMI_DH_OBJECT& sign_handle,
                  const std::string& sign_handle_name,
                  const TPM2B_DATA& qualifying_data,
                  const TPMT_SIG_SCHEME& in_scheme,
                  AuthorizationDelegate* authorization_delegate,
                  const GetTimeResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(GetTimeErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(GetTimeResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc =
      SerializeCommand_GetTime(privacy_admin_handle, privacy_admin_handle_name,
                               sign_handle, sign_handle_name, qualifying_data,
                               in_scheme, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::GetTimeSync(const TPMI_RH_ENDORSEMENT& privacy_admin_handle,
                        const std::string& privacy_admin_handle_name,
                        const TPMI_DH_OBJECT& sign_handle,
                        const std::string& sign_handle_name,
                        const TPM2B_DATA& qualifying_data,
                        const TPMT_SIG_SCHEME& in_scheme,
                        TPM2B_ATTEST* time_info,
                        TPMT_SIGNATURE* signature,
                        AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc =
      SerializeCommand_GetTime(privacy_admin_handle, privacy_admin_handle_name,
                               sign_handle, sign_handle_name, qualifying_data,
                               in_scheme, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_GetTime(response, time_info, signature,
                             authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_Commit(
    const TPMI_DH_OBJECT& sign_handle,
    const std::string& sign_handle_name,
    const UINT32& param_size,
    const TPM2B_ECC_POINT& p1,
    const TPM2B_SENSITIVE_DATA& s2,
    const TPM2B_ECC_PARAMETER& y2,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_Commit;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string param_size_bytes;
  rc = Serialize_UINT32(param_size, &param_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string sign_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(sign_handle, &sign_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string p1_bytes;
  rc = Serialize_TPM2B_ECC_POINT(p1, &p1_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string s2_bytes;
  rc = Serialize_TPM2B_SENSITIVE_DATA(s2, &s2_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string y2_bytes;
  rc = Serialize_TPM2B_ECC_PARAMETER(y2, &y2_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(sign_handle_name.data(), sign_handle_name.size());
  handle_section_bytes += sign_handle_bytes;
  command_size += sign_handle_bytes.size();
  hash->Update(param_size_bytes.data(), param_size_bytes.size());
  parameter_section_bytes += param_size_bytes;
  command_size += param_size_bytes.size();
  hash->Update(p1_bytes.data(), p1_bytes.size());
  parameter_section_bytes += p1_bytes;
  command_size += p1_bytes.size();
  hash->Update(s2_bytes.data(), s2_bytes.size());
  parameter_section_bytes += s2_bytes;
  command_size += s2_bytes.size();
  hash->Update(y2_bytes.data(), y2_bytes.size());
  parameter_section_bytes += y2_bytes;
  command_size += y2_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_Commit(
    const std::string& response,
    UINT32* param_size_out,
    TPM2B_ECC_POINT* k,
    TPM2B_ECC_POINT* l,
    TPM2B_ECC_POINT* e,
    UINT16* counter,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_Commit;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string param_size_out_bytes;
  rc = Parse_UINT32(&buffer, param_size_out, &param_size_out_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string k_bytes;
  rc = Parse_TPM2B_ECC_POINT(&buffer, k, &k_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string l_bytes;
  rc = Parse_TPM2B_ECC_POINT(&buffer, l, &l_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string e_bytes;
  rc = Parse_TPM2B_ECC_POINT(&buffer, e, &e_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string counter_bytes;
  rc = Parse_UINT16(&buffer, counter, &counter_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  return TPM_RC_SUCCESS;
}

void CommitErrorCallback(const Tpm::CommitResponse& callback,
                         TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, UINT32(), TPM2B_ECC_POINT(), TPM2B_ECC_POINT(),
               TPM2B_ECC_POINT(), UINT16());
}

void CommitResponseParser(const Tpm::CommitResponse& callback,
                          AuthorizationDelegate* authorization_delegate,
                          const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(CommitErrorCallback, callback);
  UINT32 param_size_out;
  TPM2B_ECC_POINT k;
  TPM2B_ECC_POINT l;
  TPM2B_ECC_POINT e;
  UINT16 counter;
  TPM_RC rc = Tpm::ParseResponse_Commit(response, &param_size_out, &k, &l, &e,
                                        &counter, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, param_size_out, k, l, e, counter);
}

void Tpm::Commit(const TPMI_DH_OBJECT& sign_handle,
                 const std::string& sign_handle_name,
                 const UINT32& param_size,
                 const TPM2B_ECC_POINT& p1,
                 const TPM2B_SENSITIVE_DATA& s2,
                 const TPM2B_ECC_PARAMETER& y2,
                 AuthorizationDelegate* authorization_delegate,
                 const CommitResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(CommitErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(CommitResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc =
      SerializeCommand_Commit(sign_handle, sign_handle_name, param_size, p1, s2,
                              y2, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::CommitSync(const TPMI_DH_OBJECT& sign_handle,
                       const std::string& sign_handle_name,
                       const UINT32& param_size,
                       const TPM2B_ECC_POINT& p1,
                       const TPM2B_SENSITIVE_DATA& s2,
                       const TPM2B_ECC_PARAMETER& y2,
                       UINT32* param_size_out,
                       TPM2B_ECC_POINT* k,
                       TPM2B_ECC_POINT* l,
                       TPM2B_ECC_POINT* e,
                       UINT16* counter,
                       AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc =
      SerializeCommand_Commit(sign_handle, sign_handle_name, param_size, p1, s2,
                              y2, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_Commit(response, param_size_out, k, l, e, counter,
                            authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_EC_Ephemeral(
    const UINT32& param_size,
    const TPMI_ECC_CURVE& curve_id,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_EC_Ephemeral;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string param_size_bytes;
  rc = Serialize_UINT32(param_size, &param_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string curve_id_bytes;
  rc = Serialize_TPMI_ECC_CURVE(curve_id, &curve_id_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(param_size_bytes.data(), param_size_bytes.size());
  parameter_section_bytes += param_size_bytes;
  command_size += param_size_bytes.size();
  hash->Update(curve_id_bytes.data(), curve_id_bytes.size());
  parameter_section_bytes += curve_id_bytes;
  command_size += curve_id_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_EC_Ephemeral(
    const std::string& response,
    UINT32* param_size_out,
    TPM2B_ECC_POINT* q,
    UINT16* counter,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_EC_Ephemeral;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string param_size_out_bytes;
  rc = Parse_UINT32(&buffer, param_size_out, &param_size_out_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string q_bytes;
  rc = Parse_TPM2B_ECC_POINT(&buffer, q, &q_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string counter_bytes;
  rc = Parse_UINT16(&buffer, counter, &counter_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  return TPM_RC_SUCCESS;
}

void EC_EphemeralErrorCallback(const Tpm::EC_EphemeralResponse& callback,
                               TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, UINT32(), TPM2B_ECC_POINT(), UINT16());
}

void EC_EphemeralResponseParser(const Tpm::EC_EphemeralResponse& callback,
                                AuthorizationDelegate* authorization_delegate,
                                const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(EC_EphemeralErrorCallback, callback);
  UINT32 param_size_out;
  TPM2B_ECC_POINT q;
  UINT16 counter;
  TPM_RC rc = Tpm::ParseResponse_EC_Ephemeral(response, &param_size_out, &q,
                                              &counter, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, param_size_out, q, counter);
}

void Tpm::EC_Ephemeral(const UINT32& param_size,
                       const TPMI_ECC_CURVE& curve_id,
                       AuthorizationDelegate* authorization_delegate,
                       const EC_EphemeralResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(EC_EphemeralErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(EC_EphemeralResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_EC_Ephemeral(param_size, curve_id, &command,
                                            authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::EC_EphemeralSync(const UINT32& param_size,
                             const TPMI_ECC_CURVE& curve_id,
                             UINT32* param_size_out,
                             TPM2B_ECC_POINT* q,
                             UINT16* counter,
                             AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_EC_Ephemeral(param_size, curve_id, &command,
                                            authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_EC_Ephemeral(response, param_size_out, q, counter,
                                  authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_VerifySignature(
    const TPMI_DH_OBJECT& key_handle,
    const std::string& key_handle_name,
    const TPM2B_DIGEST& digest,
    const TPMT_SIGNATURE& signature,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_VerifySignature;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string key_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(key_handle, &key_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string digest_bytes;
  rc = Serialize_TPM2B_DIGEST(digest, &digest_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string signature_bytes;
  rc = Serialize_TPMT_SIGNATURE(signature, &signature_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = digest_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    digest_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(key_handle_name.data(), key_handle_name.size());
  handle_section_bytes += key_handle_bytes;
  command_size += key_handle_bytes.size();
  hash->Update(digest_bytes.data(), digest_bytes.size());
  parameter_section_bytes += digest_bytes;
  command_size += digest_bytes.size();
  hash->Update(signature_bytes.data(), signature_bytes.size());
  parameter_section_bytes += signature_bytes;
  command_size += signature_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_VerifySignature(
    const std::string& response,
    TPMT_TK_VERIFIED* validation,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_VerifySignature;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string validation_bytes;
  rc = Parse_TPMT_TK_VERIFIED(&buffer, validation, &validation_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  return TPM_RC_SUCCESS;
}

void VerifySignatureErrorCallback(const Tpm::VerifySignatureResponse& callback,
                                  TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPMT_TK_VERIFIED());
}

void VerifySignatureResponseParser(
    const Tpm::VerifySignatureResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(VerifySignatureErrorCallback, callback);
  TPMT_TK_VERIFIED validation;
  TPM_RC rc = Tpm::ParseResponse_VerifySignature(response, &validation,
                                                 authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, validation);
}

void Tpm::VerifySignature(const TPMI_DH_OBJECT& key_handle,
                          const std::string& key_handle_name,
                          const TPM2B_DIGEST& digest,
                          const TPMT_SIGNATURE& signature,
                          AuthorizationDelegate* authorization_delegate,
                          const VerifySignatureResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(VerifySignatureErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      VerifySignatureResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_VerifySignature(key_handle, key_handle_name,
                                               digest, signature, &command,
                                               authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::VerifySignatureSync(const TPMI_DH_OBJECT& key_handle,
                                const std::string& key_handle_name,
                                const TPM2B_DIGEST& digest,
                                const TPMT_SIGNATURE& signature,
                                TPMT_TK_VERIFIED* validation,
                                AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_VerifySignature(key_handle, key_handle_name,
                                               digest, signature, &command,
                                               authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_VerifySignature(response, validation,
                                     authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_Sign(
    const TPMI_DH_OBJECT& key_handle,
    const std::string& key_handle_name,
    const TPM2B_DIGEST& digest,
    const TPMT_SIG_SCHEME& in_scheme,
    const TPMT_TK_HASHCHECK& validation,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_Sign;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string key_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(key_handle, &key_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string digest_bytes;
  rc = Serialize_TPM2B_DIGEST(digest, &digest_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string in_scheme_bytes;
  rc = Serialize_TPMT_SIG_SCHEME(in_scheme, &in_scheme_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string validation_bytes;
  rc = Serialize_TPMT_TK_HASHCHECK(validation, &validation_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = digest_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    digest_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(key_handle_name.data(), key_handle_name.size());
  handle_section_bytes += key_handle_bytes;
  command_size += key_handle_bytes.size();
  hash->Update(digest_bytes.data(), digest_bytes.size());
  parameter_section_bytes += digest_bytes;
  command_size += digest_bytes.size();
  hash->Update(in_scheme_bytes.data(), in_scheme_bytes.size());
  parameter_section_bytes += in_scheme_bytes;
  command_size += in_scheme_bytes.size();
  hash->Update(validation_bytes.data(), validation_bytes.size());
  parameter_section_bytes += validation_bytes;
  command_size += validation_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_Sign(const std::string& response,
                               TPMT_SIGNATURE* signature,
                               AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_Sign;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string signature_bytes;
  rc = Parse_TPMT_SIGNATURE(&buffer, signature, &signature_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  return TPM_RC_SUCCESS;
}

void SignErrorCallback(const Tpm::SignResponse& callback,
                       TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPMT_SIGNATURE());
}

void SignResponseParser(const Tpm::SignResponse& callback,
                        AuthorizationDelegate* authorization_delegate,
                        const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(SignErrorCallback, callback);
  TPMT_SIGNATURE signature;
  TPM_RC rc =
      Tpm::ParseResponse_Sign(response, &signature, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, signature);
}

void Tpm::Sign(const TPMI_DH_OBJECT& key_handle,
               const std::string& key_handle_name,
               const TPM2B_DIGEST& digest,
               const TPMT_SIG_SCHEME& in_scheme,
               const TPMT_TK_HASHCHECK& validation,
               AuthorizationDelegate* authorization_delegate,
               const SignResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(SignErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(SignResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc =
      SerializeCommand_Sign(key_handle, key_handle_name, digest, in_scheme,
                            validation, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::SignSync(const TPMI_DH_OBJECT& key_handle,
                     const std::string& key_handle_name,
                     const TPM2B_DIGEST& digest,
                     const TPMT_SIG_SCHEME& in_scheme,
                     const TPMT_TK_HASHCHECK& validation,
                     TPMT_SIGNATURE* signature,
                     AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc =
      SerializeCommand_Sign(key_handle, key_handle_name, digest, in_scheme,
                            validation, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_Sign(response, signature, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_SetCommandCodeAuditStatus(
    const TPMI_RH_PROVISION& auth,
    const std::string& auth_name,
    const TPMI_ALG_HASH& audit_alg,
    const TPML_CC& set_list,
    const TPML_CC& clear_list,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_SetCommandCodeAuditStatus;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_bytes;
  rc = Serialize_TPMI_RH_PROVISION(auth, &auth_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string audit_alg_bytes;
  rc = Serialize_TPMI_ALG_HASH(audit_alg, &audit_alg_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string set_list_bytes;
  rc = Serialize_TPML_CC(set_list, &set_list_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string clear_list_bytes;
  rc = Serialize_TPML_CC(clear_list, &clear_list_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(auth_name.data(), auth_name.size());
  handle_section_bytes += auth_bytes;
  command_size += auth_bytes.size();
  hash->Update(audit_alg_bytes.data(), audit_alg_bytes.size());
  parameter_section_bytes += audit_alg_bytes;
  command_size += audit_alg_bytes.size();
  hash->Update(set_list_bytes.data(), set_list_bytes.size());
  parameter_section_bytes += set_list_bytes;
  command_size += set_list_bytes.size();
  hash->Update(clear_list_bytes.data(), clear_list_bytes.size());
  parameter_section_bytes += clear_list_bytes;
  command_size += clear_list_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_SetCommandCodeAuditStatus(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_SetCommandCodeAuditStatus;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void SetCommandCodeAuditStatusErrorCallback(
    const Tpm::SetCommandCodeAuditStatusResponse& callback,
    TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void SetCommandCodeAuditStatusResponseParser(
    const Tpm::SetCommandCodeAuditStatusResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(SetCommandCodeAuditStatusErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_SetCommandCodeAuditStatus(
      response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::SetCommandCodeAuditStatus(
    const TPMI_RH_PROVISION& auth,
    const std::string& auth_name,
    const TPMI_ALG_HASH& audit_alg,
    const TPML_CC& set_list,
    const TPML_CC& clear_list,
    AuthorizationDelegate* authorization_delegate,
    const SetCommandCodeAuditStatusResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(SetCommandCodeAuditStatusErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(SetCommandCodeAuditStatusResponseParser, callback,
                 authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_SetCommandCodeAuditStatus(
      auth, auth_name, audit_alg, set_list, clear_list, &command,
      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::SetCommandCodeAuditStatusSync(
    const TPMI_RH_PROVISION& auth,
    const std::string& auth_name,
    const TPMI_ALG_HASH& audit_alg,
    const TPML_CC& set_list,
    const TPML_CC& clear_list,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_SetCommandCodeAuditStatus(
      auth, auth_name, audit_alg, set_list, clear_list, &command,
      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc =
      ParseResponse_SetCommandCodeAuditStatus(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_PCR_Extend(
    const TPMI_DH_PCR& pcr_handle,
    const std::string& pcr_handle_name,
    const TPML_DIGEST_VALUES& digests,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_PCR_Extend;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string pcr_handle_bytes;
  rc = Serialize_TPMI_DH_PCR(pcr_handle, &pcr_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string digests_bytes;
  rc = Serialize_TPML_DIGEST_VALUES(digests, &digests_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(pcr_handle_name.data(), pcr_handle_name.size());
  handle_section_bytes += pcr_handle_bytes;
  command_size += pcr_handle_bytes.size();
  hash->Update(digests_bytes.data(), digests_bytes.size());
  parameter_section_bytes += digests_bytes;
  command_size += digests_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_PCR_Extend(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_PCR_Extend;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void PCR_ExtendErrorCallback(const Tpm::PCR_ExtendResponse& callback,
                             TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void PCR_ExtendResponseParser(const Tpm::PCR_ExtendResponse& callback,
                              AuthorizationDelegate* authorization_delegate,
                              const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PCR_ExtendErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_PCR_Extend(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::PCR_Extend(const TPMI_DH_PCR& pcr_handle,
                     const std::string& pcr_handle_name,
                     const TPML_DIGEST_VALUES& digests,
                     AuthorizationDelegate* authorization_delegate,
                     const PCR_ExtendResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PCR_ExtendErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(PCR_ExtendResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_PCR_Extend(pcr_handle, pcr_handle_name, digests,
                                          &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::PCR_ExtendSync(const TPMI_DH_PCR& pcr_handle,
                           const std::string& pcr_handle_name,
                           const TPML_DIGEST_VALUES& digests,
                           AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_PCR_Extend(pcr_handle, pcr_handle_name, digests,
                                          &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_PCR_Extend(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_PCR_Event(
    const TPMI_DH_PCR& pcr_handle,
    const std::string& pcr_handle_name,
    const TPM2B_EVENT& event_data,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_PCR_Event;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string pcr_handle_bytes;
  rc = Serialize_TPMI_DH_PCR(pcr_handle, &pcr_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string event_data_bytes;
  rc = Serialize_TPM2B_EVENT(event_data, &event_data_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = event_data_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    event_data_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(pcr_handle_name.data(), pcr_handle_name.size());
  handle_section_bytes += pcr_handle_bytes;
  command_size += pcr_handle_bytes.size();
  hash->Update(event_data_bytes.data(), event_data_bytes.size());
  parameter_section_bytes += event_data_bytes;
  command_size += event_data_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_PCR_Event(
    const std::string& response,
    TPML_DIGEST_VALUES* digests,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_PCR_Event;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string digests_bytes;
  rc = Parse_TPML_DIGEST_VALUES(&buffer, digests, &digests_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  return TPM_RC_SUCCESS;
}

void PCR_EventErrorCallback(const Tpm::PCR_EventResponse& callback,
                            TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPML_DIGEST_VALUES());
}

void PCR_EventResponseParser(const Tpm::PCR_EventResponse& callback,
                             AuthorizationDelegate* authorization_delegate,
                             const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PCR_EventErrorCallback, callback);
  TPML_DIGEST_VALUES digests;
  TPM_RC rc =
      Tpm::ParseResponse_PCR_Event(response, &digests, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, digests);
}

void Tpm::PCR_Event(const TPMI_DH_PCR& pcr_handle,
                    const std::string& pcr_handle_name,
                    const TPM2B_EVENT& event_data,
                    AuthorizationDelegate* authorization_delegate,
                    const PCR_EventResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PCR_EventErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(PCR_EventResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc =
      SerializeCommand_PCR_Event(pcr_handle, pcr_handle_name, event_data,
                                 &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::PCR_EventSync(const TPMI_DH_PCR& pcr_handle,
                          const std::string& pcr_handle_name,
                          const TPM2B_EVENT& event_data,
                          TPML_DIGEST_VALUES* digests,
                          AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc =
      SerializeCommand_PCR_Event(pcr_handle, pcr_handle_name, event_data,
                                 &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_PCR_Event(response, digests, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_PCR_Read(
    const TPML_PCR_SELECTION& pcr_selection_in,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_PCR_Read;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string pcr_selection_in_bytes;
  rc = Serialize_TPML_PCR_SELECTION(pcr_selection_in, &pcr_selection_in_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(pcr_selection_in_bytes.data(), pcr_selection_in_bytes.size());
  parameter_section_bytes += pcr_selection_in_bytes;
  command_size += pcr_selection_in_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_PCR_Read(
    const std::string& response,
    UINT32* pcr_update_counter,
    TPML_PCR_SELECTION* pcr_selection_out,
    TPML_DIGEST* pcr_values,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_PCR_Read;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string pcr_update_counter_bytes;
  rc = Parse_UINT32(&buffer, pcr_update_counter, &pcr_update_counter_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string pcr_selection_out_bytes;
  rc = Parse_TPML_PCR_SELECTION(&buffer, pcr_selection_out,
                                &pcr_selection_out_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string pcr_values_bytes;
  rc = Parse_TPML_DIGEST(&buffer, pcr_values, &pcr_values_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  return TPM_RC_SUCCESS;
}

void PCR_ReadErrorCallback(const Tpm::PCR_ReadResponse& callback,
                           TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, UINT32(), TPML_PCR_SELECTION(), TPML_DIGEST());
}

void PCR_ReadResponseParser(const Tpm::PCR_ReadResponse& callback,
                            AuthorizationDelegate* authorization_delegate,
                            const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PCR_ReadErrorCallback, callback);
  UINT32 pcr_update_counter;
  TPML_PCR_SELECTION pcr_selection_out;
  TPML_DIGEST pcr_values;
  TPM_RC rc = Tpm::ParseResponse_PCR_Read(response, &pcr_update_counter,
                                          &pcr_selection_out, &pcr_values,
                                          authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, pcr_update_counter, pcr_selection_out, pcr_values);
}

void Tpm::PCR_Read(const TPML_PCR_SELECTION& pcr_selection_in,
                   AuthorizationDelegate* authorization_delegate,
                   const PCR_ReadResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PCR_ReadErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(PCR_ReadResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_PCR_Read(pcr_selection_in, &command,
                                        authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::PCR_ReadSync(const TPML_PCR_SELECTION& pcr_selection_in,
                         UINT32* pcr_update_counter,
                         TPML_PCR_SELECTION* pcr_selection_out,
                         TPML_DIGEST* pcr_values,
                         AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_PCR_Read(pcr_selection_in, &command,
                                        authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_PCR_Read(response, pcr_update_counter, pcr_selection_out,
                              pcr_values, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_PCR_Allocate(
    const TPMI_RH_PLATFORM& auth_handle,
    const std::string& auth_handle_name,
    const TPML_PCR_SELECTION& pcr_allocation,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_PCR_Allocate;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_handle_bytes;
  rc = Serialize_TPMI_RH_PLATFORM(auth_handle, &auth_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string pcr_allocation_bytes;
  rc = Serialize_TPML_PCR_SELECTION(pcr_allocation, &pcr_allocation_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(auth_handle_name.data(), auth_handle_name.size());
  handle_section_bytes += auth_handle_bytes;
  command_size += auth_handle_bytes.size();
  hash->Update(pcr_allocation_bytes.data(), pcr_allocation_bytes.size());
  parameter_section_bytes += pcr_allocation_bytes;
  command_size += pcr_allocation_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_PCR_Allocate(
    const std::string& response,
    TPMI_YES_NO* allocation_success,
    UINT32* max_pcr,
    UINT32* size_needed,
    UINT32* size_available,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_PCR_Allocate;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string allocation_success_bytes;
  rc =
      Parse_TPMI_YES_NO(&buffer, allocation_success, &allocation_success_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string max_pcr_bytes;
  rc = Parse_UINT32(&buffer, max_pcr, &max_pcr_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string size_needed_bytes;
  rc = Parse_UINT32(&buffer, size_needed, &size_needed_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string size_available_bytes;
  rc = Parse_UINT32(&buffer, size_available, &size_available_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  return TPM_RC_SUCCESS;
}

void PCR_AllocateErrorCallback(const Tpm::PCR_AllocateResponse& callback,
                               TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPMI_YES_NO(), UINT32(), UINT32(), UINT32());
}

void PCR_AllocateResponseParser(const Tpm::PCR_AllocateResponse& callback,
                                AuthorizationDelegate* authorization_delegate,
                                const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PCR_AllocateErrorCallback, callback);
  TPMI_YES_NO allocation_success;
  UINT32 max_pcr;
  UINT32 size_needed;
  UINT32 size_available;
  TPM_RC rc = Tpm::ParseResponse_PCR_Allocate(
      response, &allocation_success, &max_pcr, &size_needed, &size_available,
      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, allocation_success, max_pcr, size_needed, size_available);
}

void Tpm::PCR_Allocate(const TPMI_RH_PLATFORM& auth_handle,
                       const std::string& auth_handle_name,
                       const TPML_PCR_SELECTION& pcr_allocation,
                       AuthorizationDelegate* authorization_delegate,
                       const PCR_AllocateResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PCR_AllocateErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(PCR_AllocateResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_PCR_Allocate(auth_handle, auth_handle_name,
                                            pcr_allocation, &command,
                                            authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::PCR_AllocateSync(const TPMI_RH_PLATFORM& auth_handle,
                             const std::string& auth_handle_name,
                             const TPML_PCR_SELECTION& pcr_allocation,
                             TPMI_YES_NO* allocation_success,
                             UINT32* max_pcr,
                             UINT32* size_needed,
                             UINT32* size_available,
                             AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_PCR_Allocate(auth_handle, auth_handle_name,
                                            pcr_allocation, &command,
                                            authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_PCR_Allocate(response, allocation_success, max_pcr,
                                  size_needed, size_available,
                                  authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_PCR_SetAuthPolicy(
    const TPMI_RH_PLATFORM& auth_handle,
    const std::string& auth_handle_name,
    const TPMI_DH_PCR& pcr_num,
    const std::string& pcr_num_name,
    const TPM2B_DIGEST& auth_policy,
    const TPMI_ALG_HASH& policy_digest,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_PCR_SetAuthPolicy;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_handle_bytes;
  rc = Serialize_TPMI_RH_PLATFORM(auth_handle, &auth_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_policy_bytes;
  rc = Serialize_TPM2B_DIGEST(auth_policy, &auth_policy_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string policy_digest_bytes;
  rc = Serialize_TPMI_ALG_HASH(policy_digest, &policy_digest_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string pcr_num_bytes;
  rc = Serialize_TPMI_DH_PCR(pcr_num, &pcr_num_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = auth_policy_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    auth_policy_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(auth_handle_name.data(), auth_handle_name.size());
  handle_section_bytes += auth_handle_bytes;
  command_size += auth_handle_bytes.size();
  hash->Update(pcr_num_name.data(), pcr_num_name.size());
  handle_section_bytes += pcr_num_bytes;
  command_size += pcr_num_bytes.size();
  hash->Update(auth_policy_bytes.data(), auth_policy_bytes.size());
  parameter_section_bytes += auth_policy_bytes;
  command_size += auth_policy_bytes.size();
  hash->Update(policy_digest_bytes.data(), policy_digest_bytes.size());
  parameter_section_bytes += policy_digest_bytes;
  command_size += policy_digest_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_PCR_SetAuthPolicy(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_PCR_SetAuthPolicy;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void PCR_SetAuthPolicyErrorCallback(
    const Tpm::PCR_SetAuthPolicyResponse& callback,
    TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void PCR_SetAuthPolicyResponseParser(
    const Tpm::PCR_SetAuthPolicyResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PCR_SetAuthPolicyErrorCallback, callback);
  TPM_RC rc =
      Tpm::ParseResponse_PCR_SetAuthPolicy(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::PCR_SetAuthPolicy(const TPMI_RH_PLATFORM& auth_handle,
                            const std::string& auth_handle_name,
                            const TPMI_DH_PCR& pcr_num,
                            const std::string& pcr_num_name,
                            const TPM2B_DIGEST& auth_policy,
                            const TPMI_ALG_HASH& policy_digest,
                            AuthorizationDelegate* authorization_delegate,
                            const PCR_SetAuthPolicyResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PCR_SetAuthPolicyErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      PCR_SetAuthPolicyResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_PCR_SetAuthPolicy(
      auth_handle, auth_handle_name, pcr_num, pcr_num_name, auth_policy,
      policy_digest, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::PCR_SetAuthPolicySync(
    const TPMI_RH_PLATFORM& auth_handle,
    const std::string& auth_handle_name,
    const TPMI_DH_PCR& pcr_num,
    const std::string& pcr_num_name,
    const TPM2B_DIGEST& auth_policy,
    const TPMI_ALG_HASH& policy_digest,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_PCR_SetAuthPolicy(
      auth_handle, auth_handle_name, pcr_num, pcr_num_name, auth_policy,
      policy_digest, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_PCR_SetAuthPolicy(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_PCR_SetAuthValue(
    const TPMI_DH_PCR& pcr_handle,
    const std::string& pcr_handle_name,
    const TPM2B_DIGEST& auth,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_PCR_SetAuthValue;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string pcr_handle_bytes;
  rc = Serialize_TPMI_DH_PCR(pcr_handle, &pcr_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_bytes;
  rc = Serialize_TPM2B_DIGEST(auth, &auth_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = auth_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    auth_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(pcr_handle_name.data(), pcr_handle_name.size());
  handle_section_bytes += pcr_handle_bytes;
  command_size += pcr_handle_bytes.size();
  hash->Update(auth_bytes.data(), auth_bytes.size());
  parameter_section_bytes += auth_bytes;
  command_size += auth_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_PCR_SetAuthValue(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_PCR_SetAuthValue;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void PCR_SetAuthValueErrorCallback(
    const Tpm::PCR_SetAuthValueResponse& callback,
    TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void PCR_SetAuthValueResponseParser(
    const Tpm::PCR_SetAuthValueResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PCR_SetAuthValueErrorCallback, callback);
  TPM_RC rc =
      Tpm::ParseResponse_PCR_SetAuthValue(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::PCR_SetAuthValue(const TPMI_DH_PCR& pcr_handle,
                           const std::string& pcr_handle_name,
                           const TPM2B_DIGEST& auth,
                           AuthorizationDelegate* authorization_delegate,
                           const PCR_SetAuthValueResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PCR_SetAuthValueErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      PCR_SetAuthValueResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_PCR_SetAuthValue(
      pcr_handle, pcr_handle_name, auth, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::PCR_SetAuthValueSync(
    const TPMI_DH_PCR& pcr_handle,
    const std::string& pcr_handle_name,
    const TPM2B_DIGEST& auth,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_PCR_SetAuthValue(
      pcr_handle, pcr_handle_name, auth, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_PCR_SetAuthValue(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_PCR_Reset(
    const TPMI_DH_PCR& pcr_handle,
    const std::string& pcr_handle_name,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_PCR_Reset;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string pcr_handle_bytes;
  rc = Serialize_TPMI_DH_PCR(pcr_handle, &pcr_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(pcr_handle_name.data(), pcr_handle_name.size());
  handle_section_bytes += pcr_handle_bytes;
  command_size += pcr_handle_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_PCR_Reset(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_PCR_Reset;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void PCR_ResetErrorCallback(const Tpm::PCR_ResetResponse& callback,
                            TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void PCR_ResetResponseParser(const Tpm::PCR_ResetResponse& callback,
                             AuthorizationDelegate* authorization_delegate,
                             const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PCR_ResetErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_PCR_Reset(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::PCR_Reset(const TPMI_DH_PCR& pcr_handle,
                    const std::string& pcr_handle_name,
                    AuthorizationDelegate* authorization_delegate,
                    const PCR_ResetResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PCR_ResetErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(PCR_ResetResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_PCR_Reset(pcr_handle, pcr_handle_name, &command,
                                         authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::PCR_ResetSync(const TPMI_DH_PCR& pcr_handle,
                          const std::string& pcr_handle_name,
                          AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_PCR_Reset(pcr_handle, pcr_handle_name, &command,
                                         authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_PCR_Reset(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_PolicySigned(
    const TPMI_DH_OBJECT& auth_object,
    const std::string& auth_object_name,
    const TPMI_SH_POLICY& policy_session,
    const std::string& policy_session_name,
    const TPM2B_NONCE& nonce_tpm,
    const TPM2B_DIGEST& cp_hash_a,
    const TPM2B_NONCE& policy_ref,
    const INT32& expiration,
    const TPMT_SIGNATURE& auth,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_PolicySigned;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_object_bytes;
  rc = Serialize_TPMI_DH_OBJECT(auth_object, &auth_object_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string policy_session_bytes;
  rc = Serialize_TPMI_SH_POLICY(policy_session, &policy_session_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string nonce_tpm_bytes;
  rc = Serialize_TPM2B_NONCE(nonce_tpm, &nonce_tpm_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string cp_hash_a_bytes;
  rc = Serialize_TPM2B_DIGEST(cp_hash_a, &cp_hash_a_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string policy_ref_bytes;
  rc = Serialize_TPM2B_NONCE(policy_ref, &policy_ref_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string expiration_bytes;
  rc = Serialize_INT32(expiration, &expiration_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_bytes;
  rc = Serialize_TPMT_SIGNATURE(auth, &auth_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = nonce_tpm_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    nonce_tpm_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(auth_object_name.data(), auth_object_name.size());
  handle_section_bytes += auth_object_bytes;
  command_size += auth_object_bytes.size();
  hash->Update(policy_session_name.data(), policy_session_name.size());
  handle_section_bytes += policy_session_bytes;
  command_size += policy_session_bytes.size();
  hash->Update(nonce_tpm_bytes.data(), nonce_tpm_bytes.size());
  parameter_section_bytes += nonce_tpm_bytes;
  command_size += nonce_tpm_bytes.size();
  hash->Update(cp_hash_a_bytes.data(), cp_hash_a_bytes.size());
  parameter_section_bytes += cp_hash_a_bytes;
  command_size += cp_hash_a_bytes.size();
  hash->Update(policy_ref_bytes.data(), policy_ref_bytes.size());
  parameter_section_bytes += policy_ref_bytes;
  command_size += policy_ref_bytes.size();
  hash->Update(expiration_bytes.data(), expiration_bytes.size());
  parameter_section_bytes += expiration_bytes;
  command_size += expiration_bytes.size();
  hash->Update(auth_bytes.data(), auth_bytes.size());
  parameter_section_bytes += auth_bytes;
  command_size += auth_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_PolicySigned(
    const std::string& response,
    TPM2B_TIMEOUT* timeout,
    TPMT_TK_AUTH* policy_ticket,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_PolicySigned;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string timeout_bytes;
  rc = Parse_TPM2B_TIMEOUT(&buffer, timeout, &timeout_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string policy_ticket_bytes;
  rc = Parse_TPMT_TK_AUTH(&buffer, policy_ticket, &policy_ticket_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = timeout_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    timeout_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_TIMEOUT(&timeout_bytes, timeout, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void PolicySignedErrorCallback(const Tpm::PolicySignedResponse& callback,
                               TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_TIMEOUT(), TPMT_TK_AUTH());
}

void PolicySignedResponseParser(const Tpm::PolicySignedResponse& callback,
                                AuthorizationDelegate* authorization_delegate,
                                const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicySignedErrorCallback, callback);
  TPM2B_TIMEOUT timeout;
  TPMT_TK_AUTH policy_ticket;
  TPM_RC rc = Tpm::ParseResponse_PolicySigned(
      response, &timeout, &policy_ticket, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, timeout, policy_ticket);
}

void Tpm::PolicySigned(const TPMI_DH_OBJECT& auth_object,
                       const std::string& auth_object_name,
                       const TPMI_SH_POLICY& policy_session,
                       const std::string& policy_session_name,
                       const TPM2B_NONCE& nonce_tpm,
                       const TPM2B_DIGEST& cp_hash_a,
                       const TPM2B_NONCE& policy_ref,
                       const INT32& expiration,
                       const TPMT_SIGNATURE& auth,
                       AuthorizationDelegate* authorization_delegate,
                       const PolicySignedResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicySignedErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(PolicySignedResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_PolicySigned(
      auth_object, auth_object_name, policy_session, policy_session_name,
      nonce_tpm, cp_hash_a, policy_ref, expiration, auth, &command,
      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::PolicySignedSync(const TPMI_DH_OBJECT& auth_object,
                             const std::string& auth_object_name,
                             const TPMI_SH_POLICY& policy_session,
                             const std::string& policy_session_name,
                             const TPM2B_NONCE& nonce_tpm,
                             const TPM2B_DIGEST& cp_hash_a,
                             const TPM2B_NONCE& policy_ref,
                             const INT32& expiration,
                             const TPMT_SIGNATURE& auth,
                             TPM2B_TIMEOUT* timeout,
                             TPMT_TK_AUTH* policy_ticket,
                             AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_PolicySigned(
      auth_object, auth_object_name, policy_session, policy_session_name,
      nonce_tpm, cp_hash_a, policy_ref, expiration, auth, &command,
      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_PolicySigned(response, timeout, policy_ticket,
                                  authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_PolicySecret(
    const TPMI_DH_ENTITY& auth_handle,
    const std::string& auth_handle_name,
    const TPMI_SH_POLICY& policy_session,
    const std::string& policy_session_name,
    const TPM2B_NONCE& nonce_tpm,
    const TPM2B_DIGEST& cp_hash_a,
    const TPM2B_NONCE& policy_ref,
    const INT32& expiration,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_PolicySecret;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_handle_bytes;
  rc = Serialize_TPMI_DH_ENTITY(auth_handle, &auth_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string policy_session_bytes;
  rc = Serialize_TPMI_SH_POLICY(policy_session, &policy_session_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string nonce_tpm_bytes;
  rc = Serialize_TPM2B_NONCE(nonce_tpm, &nonce_tpm_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string cp_hash_a_bytes;
  rc = Serialize_TPM2B_DIGEST(cp_hash_a, &cp_hash_a_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string policy_ref_bytes;
  rc = Serialize_TPM2B_NONCE(policy_ref, &policy_ref_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string expiration_bytes;
  rc = Serialize_INT32(expiration, &expiration_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = nonce_tpm_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    nonce_tpm_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(auth_handle_name.data(), auth_handle_name.size());
  handle_section_bytes += auth_handle_bytes;
  command_size += auth_handle_bytes.size();
  hash->Update(policy_session_name.data(), policy_session_name.size());
  handle_section_bytes += policy_session_bytes;
  command_size += policy_session_bytes.size();
  hash->Update(nonce_tpm_bytes.data(), nonce_tpm_bytes.size());
  parameter_section_bytes += nonce_tpm_bytes;
  command_size += nonce_tpm_bytes.size();
  hash->Update(cp_hash_a_bytes.data(), cp_hash_a_bytes.size());
  parameter_section_bytes += cp_hash_a_bytes;
  command_size += cp_hash_a_bytes.size();
  hash->Update(policy_ref_bytes.data(), policy_ref_bytes.size());
  parameter_section_bytes += policy_ref_bytes;
  command_size += policy_ref_bytes.size();
  hash->Update(expiration_bytes.data(), expiration_bytes.size());
  parameter_section_bytes += expiration_bytes;
  command_size += expiration_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_PolicySecret(
    const std::string& response,
    TPM2B_TIMEOUT* timeout,
    TPMT_TK_AUTH* policy_ticket,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_PolicySecret;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string timeout_bytes;
  rc = Parse_TPM2B_TIMEOUT(&buffer, timeout, &timeout_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string policy_ticket_bytes;
  rc = Parse_TPMT_TK_AUTH(&buffer, policy_ticket, &policy_ticket_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = timeout_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    timeout_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_TIMEOUT(&timeout_bytes, timeout, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void PolicySecretErrorCallback(const Tpm::PolicySecretResponse& callback,
                               TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_TIMEOUT(), TPMT_TK_AUTH());
}

void PolicySecretResponseParser(const Tpm::PolicySecretResponse& callback,
                                AuthorizationDelegate* authorization_delegate,
                                const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicySecretErrorCallback, callback);
  TPM2B_TIMEOUT timeout;
  TPMT_TK_AUTH policy_ticket;
  TPM_RC rc = Tpm::ParseResponse_PolicySecret(
      response, &timeout, &policy_ticket, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, timeout, policy_ticket);
}

void Tpm::PolicySecret(const TPMI_DH_ENTITY& auth_handle,
                       const std::string& auth_handle_name,
                       const TPMI_SH_POLICY& policy_session,
                       const std::string& policy_session_name,
                       const TPM2B_NONCE& nonce_tpm,
                       const TPM2B_DIGEST& cp_hash_a,
                       const TPM2B_NONCE& policy_ref,
                       const INT32& expiration,
                       AuthorizationDelegate* authorization_delegate,
                       const PolicySecretResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicySecretErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(PolicySecretResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_PolicySecret(
      auth_handle, auth_handle_name, policy_session, policy_session_name,
      nonce_tpm, cp_hash_a, policy_ref, expiration, &command,
      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::PolicySecretSync(const TPMI_DH_ENTITY& auth_handle,
                             const std::string& auth_handle_name,
                             const TPMI_SH_POLICY& policy_session,
                             const std::string& policy_session_name,
                             const TPM2B_NONCE& nonce_tpm,
                             const TPM2B_DIGEST& cp_hash_a,
                             const TPM2B_NONCE& policy_ref,
                             const INT32& expiration,
                             TPM2B_TIMEOUT* timeout,
                             TPMT_TK_AUTH* policy_ticket,
                             AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_PolicySecret(
      auth_handle, auth_handle_name, policy_session, policy_session_name,
      nonce_tpm, cp_hash_a, policy_ref, expiration, &command,
      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_PolicySecret(response, timeout, policy_ticket,
                                  authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_PolicyTicket(
    const TPMI_SH_POLICY& policy_session,
    const std::string& policy_session_name,
    const TPM2B_TIMEOUT& timeout,
    const TPM2B_DIGEST& cp_hash_a,
    const TPM2B_NONCE& policy_ref,
    const TPM2B_NAME& auth_name,
    const TPMT_TK_AUTH& ticket,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_PolicyTicket;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string policy_session_bytes;
  rc = Serialize_TPMI_SH_POLICY(policy_session, &policy_session_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string timeout_bytes;
  rc = Serialize_TPM2B_TIMEOUT(timeout, &timeout_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string cp_hash_a_bytes;
  rc = Serialize_TPM2B_DIGEST(cp_hash_a, &cp_hash_a_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string policy_ref_bytes;
  rc = Serialize_TPM2B_NONCE(policy_ref, &policy_ref_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_name_bytes;
  rc = Serialize_TPM2B_NAME(auth_name, &auth_name_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string ticket_bytes;
  rc = Serialize_TPMT_TK_AUTH(ticket, &ticket_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = timeout_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    timeout_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(policy_session_name.data(), policy_session_name.size());
  handle_section_bytes += policy_session_bytes;
  command_size += policy_session_bytes.size();
  hash->Update(timeout_bytes.data(), timeout_bytes.size());
  parameter_section_bytes += timeout_bytes;
  command_size += timeout_bytes.size();
  hash->Update(cp_hash_a_bytes.data(), cp_hash_a_bytes.size());
  parameter_section_bytes += cp_hash_a_bytes;
  command_size += cp_hash_a_bytes.size();
  hash->Update(policy_ref_bytes.data(), policy_ref_bytes.size());
  parameter_section_bytes += policy_ref_bytes;
  command_size += policy_ref_bytes.size();
  hash->Update(auth_name_bytes.data(), auth_name_bytes.size());
  parameter_section_bytes += auth_name_bytes;
  command_size += auth_name_bytes.size();
  hash->Update(ticket_bytes.data(), ticket_bytes.size());
  parameter_section_bytes += ticket_bytes;
  command_size += ticket_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_PolicyTicket(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_PolicyTicket;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void PolicyTicketErrorCallback(const Tpm::PolicyTicketResponse& callback,
                               TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void PolicyTicketResponseParser(const Tpm::PolicyTicketResponse& callback,
                                AuthorizationDelegate* authorization_delegate,
                                const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyTicketErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_PolicyTicket(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::PolicyTicket(const TPMI_SH_POLICY& policy_session,
                       const std::string& policy_session_name,
                       const TPM2B_TIMEOUT& timeout,
                       const TPM2B_DIGEST& cp_hash_a,
                       const TPM2B_NONCE& policy_ref,
                       const TPM2B_NAME& auth_name,
                       const TPMT_TK_AUTH& ticket,
                       AuthorizationDelegate* authorization_delegate,
                       const PolicyTicketResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyTicketErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(PolicyTicketResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyTicket(
      policy_session, policy_session_name, timeout, cp_hash_a, policy_ref,
      auth_name, ticket, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::PolicyTicketSync(const TPMI_SH_POLICY& policy_session,
                             const std::string& policy_session_name,
                             const TPM2B_TIMEOUT& timeout,
                             const TPM2B_DIGEST& cp_hash_a,
                             const TPM2B_NONCE& policy_ref,
                             const TPM2B_NAME& auth_name,
                             const TPMT_TK_AUTH& ticket,
                             AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyTicket(
      policy_session, policy_session_name, timeout, cp_hash_a, policy_ref,
      auth_name, ticket, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_PolicyTicket(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_PolicyOR(
    const TPMI_SH_POLICY& policy_session,
    const std::string& policy_session_name,
    const TPML_DIGEST& p_hash_list,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_PolicyOR;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string policy_session_bytes;
  rc = Serialize_TPMI_SH_POLICY(policy_session, &policy_session_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string p_hash_list_bytes;
  rc = Serialize_TPML_DIGEST(p_hash_list, &p_hash_list_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(policy_session_name.data(), policy_session_name.size());
  handle_section_bytes += policy_session_bytes;
  command_size += policy_session_bytes.size();
  hash->Update(p_hash_list_bytes.data(), p_hash_list_bytes.size());
  parameter_section_bytes += p_hash_list_bytes;
  command_size += p_hash_list_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_PolicyOR(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_PolicyOR;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void PolicyORErrorCallback(const Tpm::PolicyORResponse& callback,
                           TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void PolicyORResponseParser(const Tpm::PolicyORResponse& callback,
                            AuthorizationDelegate* authorization_delegate,
                            const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyORErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_PolicyOR(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::PolicyOR(const TPMI_SH_POLICY& policy_session,
                   const std::string& policy_session_name,
                   const TPML_DIGEST& p_hash_list,
                   AuthorizationDelegate* authorization_delegate,
                   const PolicyORResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyORErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(PolicyORResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc =
      SerializeCommand_PolicyOR(policy_session, policy_session_name,
                                p_hash_list, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::PolicyORSync(const TPMI_SH_POLICY& policy_session,
                         const std::string& policy_session_name,
                         const TPML_DIGEST& p_hash_list,
                         AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc =
      SerializeCommand_PolicyOR(policy_session, policy_session_name,
                                p_hash_list, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_PolicyOR(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_PolicyPCR(
    const TPMI_SH_POLICY& policy_session,
    const std::string& policy_session_name,
    const TPM2B_DIGEST& pcr_digest,
    const TPML_PCR_SELECTION& pcrs,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_PolicyPCR;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string policy_session_bytes;
  rc = Serialize_TPMI_SH_POLICY(policy_session, &policy_session_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string pcr_digest_bytes;
  rc = Serialize_TPM2B_DIGEST(pcr_digest, &pcr_digest_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string pcrs_bytes;
  rc = Serialize_TPML_PCR_SELECTION(pcrs, &pcrs_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = pcr_digest_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    pcr_digest_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(policy_session_name.data(), policy_session_name.size());
  handle_section_bytes += policy_session_bytes;
  command_size += policy_session_bytes.size();
  hash->Update(pcr_digest_bytes.data(), pcr_digest_bytes.size());
  parameter_section_bytes += pcr_digest_bytes;
  command_size += pcr_digest_bytes.size();
  hash->Update(pcrs_bytes.data(), pcrs_bytes.size());
  parameter_section_bytes += pcrs_bytes;
  command_size += pcrs_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_PolicyPCR(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_PolicyPCR;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void PolicyPCRErrorCallback(const Tpm::PolicyPCRResponse& callback,
                            TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void PolicyPCRResponseParser(const Tpm::PolicyPCRResponse& callback,
                             AuthorizationDelegate* authorization_delegate,
                             const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyPCRErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_PolicyPCR(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::PolicyPCR(const TPMI_SH_POLICY& policy_session,
                    const std::string& policy_session_name,
                    const TPM2B_DIGEST& pcr_digest,
                    const TPML_PCR_SELECTION& pcrs,
                    AuthorizationDelegate* authorization_delegate,
                    const PolicyPCRResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyPCRErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(PolicyPCRResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyPCR(policy_session, policy_session_name,
                                         pcr_digest, pcrs, &command,
                                         authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::PolicyPCRSync(const TPMI_SH_POLICY& policy_session,
                          const std::string& policy_session_name,
                          const TPM2B_DIGEST& pcr_digest,
                          const TPML_PCR_SELECTION& pcrs,
                          AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyPCR(policy_session, policy_session_name,
                                         pcr_digest, pcrs, &command,
                                         authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_PolicyPCR(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_PolicyLocality(
    const TPMI_SH_POLICY& policy_session,
    const std::string& policy_session_name,
    const TPMA_LOCALITY& locality,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_PolicyLocality;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string policy_session_bytes;
  rc = Serialize_TPMI_SH_POLICY(policy_session, &policy_session_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string locality_bytes;
  rc = Serialize_TPMA_LOCALITY(locality, &locality_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(policy_session_name.data(), policy_session_name.size());
  handle_section_bytes += policy_session_bytes;
  command_size += policy_session_bytes.size();
  hash->Update(locality_bytes.data(), locality_bytes.size());
  parameter_section_bytes += locality_bytes;
  command_size += locality_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_PolicyLocality(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_PolicyLocality;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void PolicyLocalityErrorCallback(const Tpm::PolicyLocalityResponse& callback,
                                 TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void PolicyLocalityResponseParser(const Tpm::PolicyLocalityResponse& callback,
                                  AuthorizationDelegate* authorization_delegate,
                                  const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyLocalityErrorCallback, callback);
  TPM_RC rc =
      Tpm::ParseResponse_PolicyLocality(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::PolicyLocality(const TPMI_SH_POLICY& policy_session,
                         const std::string& policy_session_name,
                         const TPMA_LOCALITY& locality,
                         AuthorizationDelegate* authorization_delegate,
                         const PolicyLocalityResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyLocalityErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      PolicyLocalityResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyLocality(policy_session,
                                              policy_session_name, locality,
                                              &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::PolicyLocalitySync(const TPMI_SH_POLICY& policy_session,
                               const std::string& policy_session_name,
                               const TPMA_LOCALITY& locality,
                               AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyLocality(policy_session,
                                              policy_session_name, locality,
                                              &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_PolicyLocality(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_PolicyNV(
    const TPMI_RH_NV_AUTH& auth_handle,
    const std::string& auth_handle_name,
    const TPMI_RH_NV_INDEX& nv_index,
    const std::string& nv_index_name,
    const TPMI_SH_POLICY& policy_session,
    const std::string& policy_session_name,
    const TPM2B_OPERAND& operand_b,
    const UINT16& offset,
    const TPM_EO& operation,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_PolicyNV;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_handle_bytes;
  rc = Serialize_TPMI_RH_NV_AUTH(auth_handle, &auth_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string nv_index_bytes;
  rc = Serialize_TPMI_RH_NV_INDEX(nv_index, &nv_index_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string policy_session_bytes;
  rc = Serialize_TPMI_SH_POLICY(policy_session, &policy_session_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string operand_b_bytes;
  rc = Serialize_TPM2B_OPERAND(operand_b, &operand_b_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string offset_bytes;
  rc = Serialize_UINT16(offset, &offset_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string operation_bytes;
  rc = Serialize_TPM_EO(operation, &operation_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = operand_b_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    operand_b_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(auth_handle_name.data(), auth_handle_name.size());
  handle_section_bytes += auth_handle_bytes;
  command_size += auth_handle_bytes.size();
  hash->Update(nv_index_name.data(), nv_index_name.size());
  handle_section_bytes += nv_index_bytes;
  command_size += nv_index_bytes.size();
  hash->Update(policy_session_name.data(), policy_session_name.size());
  handle_section_bytes += policy_session_bytes;
  command_size += policy_session_bytes.size();
  hash->Update(operand_b_bytes.data(), operand_b_bytes.size());
  parameter_section_bytes += operand_b_bytes;
  command_size += operand_b_bytes.size();
  hash->Update(offset_bytes.data(), offset_bytes.size());
  parameter_section_bytes += offset_bytes;
  command_size += offset_bytes.size();
  hash->Update(operation_bytes.data(), operation_bytes.size());
  parameter_section_bytes += operation_bytes;
  command_size += operation_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_PolicyNV(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_PolicyNV;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void PolicyNVErrorCallback(const Tpm::PolicyNVResponse& callback,
                           TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void PolicyNVResponseParser(const Tpm::PolicyNVResponse& callback,
                            AuthorizationDelegate* authorization_delegate,
                            const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyNVErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_PolicyNV(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::PolicyNV(const TPMI_RH_NV_AUTH& auth_handle,
                   const std::string& auth_handle_name,
                   const TPMI_RH_NV_INDEX& nv_index,
                   const std::string& nv_index_name,
                   const TPMI_SH_POLICY& policy_session,
                   const std::string& policy_session_name,
                   const TPM2B_OPERAND& operand_b,
                   const UINT16& offset,
                   const TPM_EO& operation,
                   AuthorizationDelegate* authorization_delegate,
                   const PolicyNVResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyNVErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(PolicyNVResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyNV(
      auth_handle, auth_handle_name, nv_index, nv_index_name, policy_session,
      policy_session_name, operand_b, offset, operation, &command,
      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::PolicyNVSync(const TPMI_RH_NV_AUTH& auth_handle,
                         const std::string& auth_handle_name,
                         const TPMI_RH_NV_INDEX& nv_index,
                         const std::string& nv_index_name,
                         const TPMI_SH_POLICY& policy_session,
                         const std::string& policy_session_name,
                         const TPM2B_OPERAND& operand_b,
                         const UINT16& offset,
                         const TPM_EO& operation,
                         AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyNV(
      auth_handle, auth_handle_name, nv_index, nv_index_name, policy_session,
      policy_session_name, operand_b, offset, operation, &command,
      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_PolicyNV(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_PolicyCounterTimer(
    const TPMI_SH_POLICY& policy_session,
    const std::string& policy_session_name,
    const TPM2B_OPERAND& operand_b,
    const UINT16& offset,
    const TPM_EO& operation,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_PolicyCounterTimer;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string policy_session_bytes;
  rc = Serialize_TPMI_SH_POLICY(policy_session, &policy_session_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string operand_b_bytes;
  rc = Serialize_TPM2B_OPERAND(operand_b, &operand_b_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string offset_bytes;
  rc = Serialize_UINT16(offset, &offset_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string operation_bytes;
  rc = Serialize_TPM_EO(operation, &operation_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = operand_b_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    operand_b_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(policy_session_name.data(), policy_session_name.size());
  handle_section_bytes += policy_session_bytes;
  command_size += policy_session_bytes.size();
  hash->Update(operand_b_bytes.data(), operand_b_bytes.size());
  parameter_section_bytes += operand_b_bytes;
  command_size += operand_b_bytes.size();
  hash->Update(offset_bytes.data(), offset_bytes.size());
  parameter_section_bytes += offset_bytes;
  command_size += offset_bytes.size();
  hash->Update(operation_bytes.data(), operation_bytes.size());
  parameter_section_bytes += operation_bytes;
  command_size += operation_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_PolicyCounterTimer(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_PolicyCounterTimer;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void PolicyCounterTimerErrorCallback(
    const Tpm::PolicyCounterTimerResponse& callback,
    TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void PolicyCounterTimerResponseParser(
    const Tpm::PolicyCounterTimerResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyCounterTimerErrorCallback, callback);
  TPM_RC rc =
      Tpm::ParseResponse_PolicyCounterTimer(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::PolicyCounterTimer(const TPMI_SH_POLICY& policy_session,
                             const std::string& policy_session_name,
                             const TPM2B_OPERAND& operand_b,
                             const UINT16& offset,
                             const TPM_EO& operation,
                             AuthorizationDelegate* authorization_delegate,
                             const PolicyCounterTimerResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyCounterTimerErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      PolicyCounterTimerResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyCounterTimer(
      policy_session, policy_session_name, operand_b, offset, operation,
      &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::PolicyCounterTimerSync(
    const TPMI_SH_POLICY& policy_session,
    const std::string& policy_session_name,
    const TPM2B_OPERAND& operand_b,
    const UINT16& offset,
    const TPM_EO& operation,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyCounterTimer(
      policy_session, policy_session_name, operand_b, offset, operation,
      &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_PolicyCounterTimer(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_PolicyCommandCode(
    const TPMI_SH_POLICY& policy_session,
    const std::string& policy_session_name,
    const TPM_CC& code,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_PolicyCommandCode;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string policy_session_bytes;
  rc = Serialize_TPMI_SH_POLICY(policy_session, &policy_session_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string code_bytes;
  rc = Serialize_TPM_CC(code, &code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(policy_session_name.data(), policy_session_name.size());
  handle_section_bytes += policy_session_bytes;
  command_size += policy_session_bytes.size();
  hash->Update(code_bytes.data(), code_bytes.size());
  parameter_section_bytes += code_bytes;
  command_size += code_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_PolicyCommandCode(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_PolicyCommandCode;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void PolicyCommandCodeErrorCallback(
    const Tpm::PolicyCommandCodeResponse& callback,
    TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void PolicyCommandCodeResponseParser(
    const Tpm::PolicyCommandCodeResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyCommandCodeErrorCallback, callback);
  TPM_RC rc =
      Tpm::ParseResponse_PolicyCommandCode(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::PolicyCommandCode(const TPMI_SH_POLICY& policy_session,
                            const std::string& policy_session_name,
                            const TPM_CC& code,
                            AuthorizationDelegate* authorization_delegate,
                            const PolicyCommandCodeResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyCommandCodeErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      PolicyCommandCodeResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyCommandCode(
      policy_session, policy_session_name, code, &command,
      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::PolicyCommandCodeSync(
    const TPMI_SH_POLICY& policy_session,
    const std::string& policy_session_name,
    const TPM_CC& code,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyCommandCode(
      policy_session, policy_session_name, code, &command,
      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_PolicyCommandCode(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_PolicyPhysicalPresence(
    const TPMI_SH_POLICY& policy_session,
    const std::string& policy_session_name,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_PolicyPhysicalPresence;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string policy_session_bytes;
  rc = Serialize_TPMI_SH_POLICY(policy_session, &policy_session_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(policy_session_name.data(), policy_session_name.size());
  handle_section_bytes += policy_session_bytes;
  command_size += policy_session_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_PolicyPhysicalPresence(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_PolicyPhysicalPresence;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void PolicyPhysicalPresenceErrorCallback(
    const Tpm::PolicyPhysicalPresenceResponse& callback,
    TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void PolicyPhysicalPresenceResponseParser(
    const Tpm::PolicyPhysicalPresenceResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyPhysicalPresenceErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_PolicyPhysicalPresence(response,
                                                        authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::PolicyPhysicalPresence(
    const TPMI_SH_POLICY& policy_session,
    const std::string& policy_session_name,
    AuthorizationDelegate* authorization_delegate,
    const PolicyPhysicalPresenceResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyPhysicalPresenceErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      PolicyPhysicalPresenceResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyPhysicalPresence(
      policy_session, policy_session_name, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::PolicyPhysicalPresenceSync(
    const TPMI_SH_POLICY& policy_session,
    const std::string& policy_session_name,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyPhysicalPresence(
      policy_session, policy_session_name, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_PolicyPhysicalPresence(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_PolicyCpHash(
    const TPMI_SH_POLICY& policy_session,
    const std::string& policy_session_name,
    const TPM2B_DIGEST& cp_hash_a,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_PolicyCpHash;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string policy_session_bytes;
  rc = Serialize_TPMI_SH_POLICY(policy_session, &policy_session_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string cp_hash_a_bytes;
  rc = Serialize_TPM2B_DIGEST(cp_hash_a, &cp_hash_a_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = cp_hash_a_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    cp_hash_a_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(policy_session_name.data(), policy_session_name.size());
  handle_section_bytes += policy_session_bytes;
  command_size += policy_session_bytes.size();
  hash->Update(cp_hash_a_bytes.data(), cp_hash_a_bytes.size());
  parameter_section_bytes += cp_hash_a_bytes;
  command_size += cp_hash_a_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_PolicyCpHash(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_PolicyCpHash;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void PolicyCpHashErrorCallback(const Tpm::PolicyCpHashResponse& callback,
                               TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void PolicyCpHashResponseParser(const Tpm::PolicyCpHashResponse& callback,
                                AuthorizationDelegate* authorization_delegate,
                                const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyCpHashErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_PolicyCpHash(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::PolicyCpHash(const TPMI_SH_POLICY& policy_session,
                       const std::string& policy_session_name,
                       const TPM2B_DIGEST& cp_hash_a,
                       AuthorizationDelegate* authorization_delegate,
                       const PolicyCpHashResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyCpHashErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(PolicyCpHashResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyCpHash(policy_session, policy_session_name,
                                            cp_hash_a, &command,
                                            authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::PolicyCpHashSync(const TPMI_SH_POLICY& policy_session,
                             const std::string& policy_session_name,
                             const TPM2B_DIGEST& cp_hash_a,
                             AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyCpHash(policy_session, policy_session_name,
                                            cp_hash_a, &command,
                                            authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_PolicyCpHash(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_PolicyNameHash(
    const TPMI_SH_POLICY& policy_session,
    const std::string& policy_session_name,
    const TPM2B_DIGEST& name_hash,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_PolicyNameHash;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string policy_session_bytes;
  rc = Serialize_TPMI_SH_POLICY(policy_session, &policy_session_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string name_hash_bytes;
  rc = Serialize_TPM2B_DIGEST(name_hash, &name_hash_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = name_hash_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    name_hash_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(policy_session_name.data(), policy_session_name.size());
  handle_section_bytes += policy_session_bytes;
  command_size += policy_session_bytes.size();
  hash->Update(name_hash_bytes.data(), name_hash_bytes.size());
  parameter_section_bytes += name_hash_bytes;
  command_size += name_hash_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_PolicyNameHash(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_PolicyNameHash;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void PolicyNameHashErrorCallback(const Tpm::PolicyNameHashResponse& callback,
                                 TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void PolicyNameHashResponseParser(const Tpm::PolicyNameHashResponse& callback,
                                  AuthorizationDelegate* authorization_delegate,
                                  const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyNameHashErrorCallback, callback);
  TPM_RC rc =
      Tpm::ParseResponse_PolicyNameHash(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::PolicyNameHash(const TPMI_SH_POLICY& policy_session,
                         const std::string& policy_session_name,
                         const TPM2B_DIGEST& name_hash,
                         AuthorizationDelegate* authorization_delegate,
                         const PolicyNameHashResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyNameHashErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      PolicyNameHashResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyNameHash(policy_session,
                                              policy_session_name, name_hash,
                                              &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::PolicyNameHashSync(const TPMI_SH_POLICY& policy_session,
                               const std::string& policy_session_name,
                               const TPM2B_DIGEST& name_hash,
                               AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyNameHash(policy_session,
                                              policy_session_name, name_hash,
                                              &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_PolicyNameHash(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_PolicyDuplicationSelect(
    const TPMI_SH_POLICY& policy_session,
    const std::string& policy_session_name,
    const TPM2B_NAME& object_name,
    const TPM2B_NAME& new_parent_name,
    const TPMI_YES_NO& include_object,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_PolicyDuplicationSelect;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string policy_session_bytes;
  rc = Serialize_TPMI_SH_POLICY(policy_session, &policy_session_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string object_name_bytes;
  rc = Serialize_TPM2B_NAME(object_name, &object_name_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string new_parent_name_bytes;
  rc = Serialize_TPM2B_NAME(new_parent_name, &new_parent_name_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string include_object_bytes;
  rc = Serialize_TPMI_YES_NO(include_object, &include_object_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = object_name_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    object_name_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(policy_session_name.data(), policy_session_name.size());
  handle_section_bytes += policy_session_bytes;
  command_size += policy_session_bytes.size();
  hash->Update(object_name_bytes.data(), object_name_bytes.size());
  parameter_section_bytes += object_name_bytes;
  command_size += object_name_bytes.size();
  hash->Update(new_parent_name_bytes.data(), new_parent_name_bytes.size());
  parameter_section_bytes += new_parent_name_bytes;
  command_size += new_parent_name_bytes.size();
  hash->Update(include_object_bytes.data(), include_object_bytes.size());
  parameter_section_bytes += include_object_bytes;
  command_size += include_object_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_PolicyDuplicationSelect(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_PolicyDuplicationSelect;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void PolicyDuplicationSelectErrorCallback(
    const Tpm::PolicyDuplicationSelectResponse& callback,
    TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void PolicyDuplicationSelectResponseParser(
    const Tpm::PolicyDuplicationSelectResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyDuplicationSelectErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_PolicyDuplicationSelect(
      response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::PolicyDuplicationSelect(
    const TPMI_SH_POLICY& policy_session,
    const std::string& policy_session_name,
    const TPM2B_NAME& object_name,
    const TPM2B_NAME& new_parent_name,
    const TPMI_YES_NO& include_object,
    AuthorizationDelegate* authorization_delegate,
    const PolicyDuplicationSelectResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyDuplicationSelectErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      PolicyDuplicationSelectResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyDuplicationSelect(
      policy_session, policy_session_name, object_name, new_parent_name,
      include_object, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::PolicyDuplicationSelectSync(
    const TPMI_SH_POLICY& policy_session,
    const std::string& policy_session_name,
    const TPM2B_NAME& object_name,
    const TPM2B_NAME& new_parent_name,
    const TPMI_YES_NO& include_object,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyDuplicationSelect(
      policy_session, policy_session_name, object_name, new_parent_name,
      include_object, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_PolicyDuplicationSelect(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_PolicyAuthorize(
    const TPMI_SH_POLICY& policy_session,
    const std::string& policy_session_name,
    const TPM2B_DIGEST& approved_policy,
    const TPM2B_NONCE& policy_ref,
    const TPM2B_NAME& key_sign,
    const TPMT_TK_VERIFIED& check_ticket,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_PolicyAuthorize;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string policy_session_bytes;
  rc = Serialize_TPMI_SH_POLICY(policy_session, &policy_session_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string approved_policy_bytes;
  rc = Serialize_TPM2B_DIGEST(approved_policy, &approved_policy_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string policy_ref_bytes;
  rc = Serialize_TPM2B_NONCE(policy_ref, &policy_ref_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string key_sign_bytes;
  rc = Serialize_TPM2B_NAME(key_sign, &key_sign_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string check_ticket_bytes;
  rc = Serialize_TPMT_TK_VERIFIED(check_ticket, &check_ticket_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = approved_policy_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    approved_policy_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(policy_session_name.data(), policy_session_name.size());
  handle_section_bytes += policy_session_bytes;
  command_size += policy_session_bytes.size();
  hash->Update(approved_policy_bytes.data(), approved_policy_bytes.size());
  parameter_section_bytes += approved_policy_bytes;
  command_size += approved_policy_bytes.size();
  hash->Update(policy_ref_bytes.data(), policy_ref_bytes.size());
  parameter_section_bytes += policy_ref_bytes;
  command_size += policy_ref_bytes.size();
  hash->Update(key_sign_bytes.data(), key_sign_bytes.size());
  parameter_section_bytes += key_sign_bytes;
  command_size += key_sign_bytes.size();
  hash->Update(check_ticket_bytes.data(), check_ticket_bytes.size());
  parameter_section_bytes += check_ticket_bytes;
  command_size += check_ticket_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_PolicyAuthorize(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_PolicyAuthorize;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void PolicyAuthorizeErrorCallback(const Tpm::PolicyAuthorizeResponse& callback,
                                  TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void PolicyAuthorizeResponseParser(
    const Tpm::PolicyAuthorizeResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyAuthorizeErrorCallback, callback);
  TPM_RC rc =
      Tpm::ParseResponse_PolicyAuthorize(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::PolicyAuthorize(const TPMI_SH_POLICY& policy_session,
                          const std::string& policy_session_name,
                          const TPM2B_DIGEST& approved_policy,
                          const TPM2B_NONCE& policy_ref,
                          const TPM2B_NAME& key_sign,
                          const TPMT_TK_VERIFIED& check_ticket,
                          AuthorizationDelegate* authorization_delegate,
                          const PolicyAuthorizeResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyAuthorizeErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      PolicyAuthorizeResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyAuthorize(
      policy_session, policy_session_name, approved_policy, policy_ref,
      key_sign, check_ticket, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::PolicyAuthorizeSync(const TPMI_SH_POLICY& policy_session,
                                const std::string& policy_session_name,
                                const TPM2B_DIGEST& approved_policy,
                                const TPM2B_NONCE& policy_ref,
                                const TPM2B_NAME& key_sign,
                                const TPMT_TK_VERIFIED& check_ticket,
                                AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyAuthorize(
      policy_session, policy_session_name, approved_policy, policy_ref,
      key_sign, check_ticket, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_PolicyAuthorize(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_PolicyAuthValue(
    const TPMI_SH_POLICY& policy_session,
    const std::string& policy_session_name,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_PolicyAuthValue;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string policy_session_bytes;
  rc = Serialize_TPMI_SH_POLICY(policy_session, &policy_session_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(policy_session_name.data(), policy_session_name.size());
  handle_section_bytes += policy_session_bytes;
  command_size += policy_session_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_PolicyAuthValue(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_PolicyAuthValue;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void PolicyAuthValueErrorCallback(const Tpm::PolicyAuthValueResponse& callback,
                                  TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void PolicyAuthValueResponseParser(
    const Tpm::PolicyAuthValueResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyAuthValueErrorCallback, callback);
  TPM_RC rc =
      Tpm::ParseResponse_PolicyAuthValue(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::PolicyAuthValue(const TPMI_SH_POLICY& policy_session,
                          const std::string& policy_session_name,
                          AuthorizationDelegate* authorization_delegate,
                          const PolicyAuthValueResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyAuthValueErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      PolicyAuthValueResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyAuthValue(
      policy_session, policy_session_name, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::PolicyAuthValueSync(const TPMI_SH_POLICY& policy_session,
                                const std::string& policy_session_name,
                                AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyAuthValue(
      policy_session, policy_session_name, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_PolicyAuthValue(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_PolicyPassword(
    const TPMI_SH_POLICY& policy_session,
    const std::string& policy_session_name,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_PolicyPassword;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string policy_session_bytes;
  rc = Serialize_TPMI_SH_POLICY(policy_session, &policy_session_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(policy_session_name.data(), policy_session_name.size());
  handle_section_bytes += policy_session_bytes;
  command_size += policy_session_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_PolicyPassword(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_PolicyPassword;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void PolicyPasswordErrorCallback(const Tpm::PolicyPasswordResponse& callback,
                                 TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void PolicyPasswordResponseParser(const Tpm::PolicyPasswordResponse& callback,
                                  AuthorizationDelegate* authorization_delegate,
                                  const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyPasswordErrorCallback, callback);
  TPM_RC rc =
      Tpm::ParseResponse_PolicyPassword(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::PolicyPassword(const TPMI_SH_POLICY& policy_session,
                         const std::string& policy_session_name,
                         AuthorizationDelegate* authorization_delegate,
                         const PolicyPasswordResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyPasswordErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      PolicyPasswordResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyPassword(
      policy_session, policy_session_name, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::PolicyPasswordSync(const TPMI_SH_POLICY& policy_session,
                               const std::string& policy_session_name,
                               AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyPassword(
      policy_session, policy_session_name, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_PolicyPassword(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_PolicyGetDigest(
    const TPMI_SH_POLICY& policy_session,
    const std::string& policy_session_name,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_PolicyGetDigest;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string policy_session_bytes;
  rc = Serialize_TPMI_SH_POLICY(policy_session, &policy_session_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(policy_session_name.data(), policy_session_name.size());
  handle_section_bytes += policy_session_bytes;
  command_size += policy_session_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_PolicyGetDigest(
    const std::string& response,
    TPM2B_DIGEST* policy_digest,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_PolicyGetDigest;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string policy_digest_bytes;
  rc = Parse_TPM2B_DIGEST(&buffer, policy_digest, &policy_digest_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = policy_digest_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    policy_digest_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_DIGEST(&policy_digest_bytes, policy_digest, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void PolicyGetDigestErrorCallback(const Tpm::PolicyGetDigestResponse& callback,
                                  TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_DIGEST());
}

void PolicyGetDigestResponseParser(
    const Tpm::PolicyGetDigestResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyGetDigestErrorCallback, callback);
  TPM2B_DIGEST policy_digest;
  TPM_RC rc = Tpm::ParseResponse_PolicyGetDigest(response, &policy_digest,
                                                 authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, policy_digest);
}

void Tpm::PolicyGetDigest(const TPMI_SH_POLICY& policy_session,
                          const std::string& policy_session_name,
                          AuthorizationDelegate* authorization_delegate,
                          const PolicyGetDigestResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyGetDigestErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      PolicyGetDigestResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyGetDigest(
      policy_session, policy_session_name, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::PolicyGetDigestSync(const TPMI_SH_POLICY& policy_session,
                                const std::string& policy_session_name,
                                TPM2B_DIGEST* policy_digest,
                                AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyGetDigest(
      policy_session, policy_session_name, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_PolicyGetDigest(response, policy_digest,
                                     authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_PolicyNvWritten(
    const TPMI_SH_POLICY& policy_session,
    const std::string& policy_session_name,
    const TPMI_YES_NO& written_set,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_PolicyNvWritten;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string policy_session_bytes;
  rc = Serialize_TPMI_SH_POLICY(policy_session, &policy_session_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string written_set_bytes;
  rc = Serialize_TPMI_YES_NO(written_set, &written_set_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(policy_session_name.data(), policy_session_name.size());
  handle_section_bytes += policy_session_bytes;
  command_size += policy_session_bytes.size();
  hash->Update(written_set_bytes.data(), written_set_bytes.size());
  parameter_section_bytes += written_set_bytes;
  command_size += written_set_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_PolicyNvWritten(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_PolicyNvWritten;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void PolicyNvWrittenErrorCallback(const Tpm::PolicyNvWrittenResponse& callback,
                                  TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void PolicyNvWrittenResponseParser(
    const Tpm::PolicyNvWrittenResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyNvWrittenErrorCallback, callback);
  TPM_RC rc =
      Tpm::ParseResponse_PolicyNvWritten(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::PolicyNvWritten(const TPMI_SH_POLICY& policy_session,
                          const std::string& policy_session_name,
                          const TPMI_YES_NO& written_set,
                          AuthorizationDelegate* authorization_delegate,
                          const PolicyNvWrittenResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PolicyNvWrittenErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      PolicyNvWrittenResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyNvWritten(
      policy_session, policy_session_name, written_set, &command,
      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::PolicyNvWrittenSync(const TPMI_SH_POLICY& policy_session,
                                const std::string& policy_session_name,
                                const TPMI_YES_NO& written_set,
                                AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_PolicyNvWritten(
      policy_session, policy_session_name, written_set, &command,
      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_PolicyNvWritten(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_CreatePrimary(
    const TPMI_RH_HIERARCHY& primary_handle,
    const std::string& primary_handle_name,
    const TPM2B_SENSITIVE_CREATE& in_sensitive,
    const TPM2B_PUBLIC& in_public,
    const TPM2B_DATA& outside_info,
    const TPML_PCR_SELECTION& creation_pcr,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_CreatePrimary;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string primary_handle_bytes;
  rc = Serialize_TPMI_RH_HIERARCHY(primary_handle, &primary_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string in_sensitive_bytes;
  rc = Serialize_TPM2B_SENSITIVE_CREATE(in_sensitive, &in_sensitive_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string in_public_bytes;
  rc = Serialize_TPM2B_PUBLIC(in_public, &in_public_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string outside_info_bytes;
  rc = Serialize_TPM2B_DATA(outside_info, &outside_info_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string creation_pcr_bytes;
  rc = Serialize_TPML_PCR_SELECTION(creation_pcr, &creation_pcr_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = in_sensitive_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    in_sensitive_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(primary_handle_name.data(), primary_handle_name.size());
  handle_section_bytes += primary_handle_bytes;
  command_size += primary_handle_bytes.size();
  hash->Update(in_sensitive_bytes.data(), in_sensitive_bytes.size());
  parameter_section_bytes += in_sensitive_bytes;
  command_size += in_sensitive_bytes.size();
  hash->Update(in_public_bytes.data(), in_public_bytes.size());
  parameter_section_bytes += in_public_bytes;
  command_size += in_public_bytes.size();
  hash->Update(outside_info_bytes.data(), outside_info_bytes.size());
  parameter_section_bytes += outside_info_bytes;
  command_size += outside_info_bytes.size();
  hash->Update(creation_pcr_bytes.data(), creation_pcr_bytes.size());
  parameter_section_bytes += creation_pcr_bytes;
  command_size += creation_pcr_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_CreatePrimary(
    const std::string& response,
    TPM_HANDLE* object_handle,
    TPM2B_PUBLIC* out_public,
    TPM2B_CREATION_DATA* creation_data,
    TPM2B_DIGEST* creation_hash,
    TPMT_TK_CREATION* creation_ticket,
    TPM2B_NAME* name,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  std::string object_handle_bytes;
  rc = Parse_TPM_HANDLE(&buffer, object_handle, &object_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_CC command_code = TPM_CC_CreatePrimary;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string out_public_bytes;
  rc = Parse_TPM2B_PUBLIC(&buffer, out_public, &out_public_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string creation_data_bytes;
  rc = Parse_TPM2B_CREATION_DATA(&buffer, creation_data, &creation_data_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string creation_hash_bytes;
  rc = Parse_TPM2B_DIGEST(&buffer, creation_hash, &creation_hash_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string creation_ticket_bytes;
  rc = Parse_TPMT_TK_CREATION(&buffer, creation_ticket, &creation_ticket_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string name_bytes;
  rc = Parse_TPM2B_NAME(&buffer, name, &name_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = out_public_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    out_public_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_PUBLIC(&out_public_bytes, out_public, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void CreatePrimaryErrorCallback(const Tpm::CreatePrimaryResponse& callback,
                                TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM_HANDLE(), TPM2B_PUBLIC(),
               TPM2B_CREATION_DATA(), TPM2B_DIGEST(), TPMT_TK_CREATION(),
               TPM2B_NAME());
}

void CreatePrimaryResponseParser(const Tpm::CreatePrimaryResponse& callback,
                                 AuthorizationDelegate* authorization_delegate,
                                 const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(CreatePrimaryErrorCallback, callback);
  TPM_HANDLE object_handle;
  TPM2B_PUBLIC out_public;
  TPM2B_CREATION_DATA creation_data;
  TPM2B_DIGEST creation_hash;
  TPMT_TK_CREATION creation_ticket;
  TPM2B_NAME name;
  TPM_RC rc = Tpm::ParseResponse_CreatePrimary(
      response, &object_handle, &out_public, &creation_data, &creation_hash,
      &creation_ticket, &name, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, object_handle, out_public, creation_data, creation_hash,
               creation_ticket, name);
}

void Tpm::CreatePrimary(const TPMI_RH_HIERARCHY& primary_handle,
                        const std::string& primary_handle_name,
                        const TPM2B_SENSITIVE_CREATE& in_sensitive,
                        const TPM2B_PUBLIC& in_public,
                        const TPM2B_DATA& outside_info,
                        const TPML_PCR_SELECTION& creation_pcr,
                        AuthorizationDelegate* authorization_delegate,
                        const CreatePrimaryResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(CreatePrimaryErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(CreatePrimaryResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_CreatePrimary(
      primary_handle, primary_handle_name, in_sensitive, in_public,
      outside_info, creation_pcr, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::CreatePrimarySync(const TPMI_RH_HIERARCHY& primary_handle,
                              const std::string& primary_handle_name,
                              const TPM2B_SENSITIVE_CREATE& in_sensitive,
                              const TPM2B_PUBLIC& in_public,
                              const TPM2B_DATA& outside_info,
                              const TPML_PCR_SELECTION& creation_pcr,
                              TPM_HANDLE* object_handle,
                              TPM2B_PUBLIC* out_public,
                              TPM2B_CREATION_DATA* creation_data,
                              TPM2B_DIGEST* creation_hash,
                              TPMT_TK_CREATION* creation_ticket,
                              TPM2B_NAME* name,
                              AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_CreatePrimary(
      primary_handle, primary_handle_name, in_sensitive, in_public,
      outside_info, creation_pcr, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_CreatePrimary(
      response, object_handle, out_public, creation_data, creation_hash,
      creation_ticket, name, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_HierarchyControl(
    const TPMI_RH_HIERARCHY& auth_handle,
    const std::string& auth_handle_name,
    const TPMI_RH_ENABLES& enable,
    const TPMI_YES_NO& state,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_HierarchyControl;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_handle_bytes;
  rc = Serialize_TPMI_RH_HIERARCHY(auth_handle, &auth_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string enable_bytes;
  rc = Serialize_TPMI_RH_ENABLES(enable, &enable_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string state_bytes;
  rc = Serialize_TPMI_YES_NO(state, &state_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(auth_handle_name.data(), auth_handle_name.size());
  handle_section_bytes += auth_handle_bytes;
  command_size += auth_handle_bytes.size();
  hash->Update(enable_bytes.data(), enable_bytes.size());
  parameter_section_bytes += enable_bytes;
  command_size += enable_bytes.size();
  hash->Update(state_bytes.data(), state_bytes.size());
  parameter_section_bytes += state_bytes;
  command_size += state_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_HierarchyControl(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_HierarchyControl;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void HierarchyControlErrorCallback(
    const Tpm::HierarchyControlResponse& callback,
    TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void HierarchyControlResponseParser(
    const Tpm::HierarchyControlResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(HierarchyControlErrorCallback, callback);
  TPM_RC rc =
      Tpm::ParseResponse_HierarchyControl(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::HierarchyControl(const TPMI_RH_HIERARCHY& auth_handle,
                           const std::string& auth_handle_name,
                           const TPMI_RH_ENABLES& enable,
                           const TPMI_YES_NO& state,
                           AuthorizationDelegate* authorization_delegate,
                           const HierarchyControlResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(HierarchyControlErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      HierarchyControlResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_HierarchyControl(auth_handle, auth_handle_name,
                                                enable, state, &command,
                                                authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::HierarchyControlSync(
    const TPMI_RH_HIERARCHY& auth_handle,
    const std::string& auth_handle_name,
    const TPMI_RH_ENABLES& enable,
    const TPMI_YES_NO& state,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_HierarchyControl(auth_handle, auth_handle_name,
                                                enable, state, &command,
                                                authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_HierarchyControl(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_SetPrimaryPolicy(
    const TPMI_RH_HIERARCHY& auth_handle,
    const std::string& auth_handle_name,
    const TPM2B_DIGEST& auth_policy,
    const TPMI_ALG_HASH& hash_alg,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_SetPrimaryPolicy;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_handle_bytes;
  rc = Serialize_TPMI_RH_HIERARCHY(auth_handle, &auth_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_policy_bytes;
  rc = Serialize_TPM2B_DIGEST(auth_policy, &auth_policy_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string hash_alg_bytes;
  rc = Serialize_TPMI_ALG_HASH(hash_alg, &hash_alg_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = auth_policy_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    auth_policy_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(auth_handle_name.data(), auth_handle_name.size());
  handle_section_bytes += auth_handle_bytes;
  command_size += auth_handle_bytes.size();
  hash->Update(auth_policy_bytes.data(), auth_policy_bytes.size());
  parameter_section_bytes += auth_policy_bytes;
  command_size += auth_policy_bytes.size();
  hash->Update(hash_alg_bytes.data(), hash_alg_bytes.size());
  parameter_section_bytes += hash_alg_bytes;
  command_size += hash_alg_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_SetPrimaryPolicy(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_SetPrimaryPolicy;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void SetPrimaryPolicyErrorCallback(
    const Tpm::SetPrimaryPolicyResponse& callback,
    TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void SetPrimaryPolicyResponseParser(
    const Tpm::SetPrimaryPolicyResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(SetPrimaryPolicyErrorCallback, callback);
  TPM_RC rc =
      Tpm::ParseResponse_SetPrimaryPolicy(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::SetPrimaryPolicy(const TPMI_RH_HIERARCHY& auth_handle,
                           const std::string& auth_handle_name,
                           const TPM2B_DIGEST& auth_policy,
                           const TPMI_ALG_HASH& hash_alg,
                           AuthorizationDelegate* authorization_delegate,
                           const SetPrimaryPolicyResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(SetPrimaryPolicyErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      SetPrimaryPolicyResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_SetPrimaryPolicy(auth_handle, auth_handle_name,
                                                auth_policy, hash_alg, &command,
                                                authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::SetPrimaryPolicySync(
    const TPMI_RH_HIERARCHY& auth_handle,
    const std::string& auth_handle_name,
    const TPM2B_DIGEST& auth_policy,
    const TPMI_ALG_HASH& hash_alg,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_SetPrimaryPolicy(auth_handle, auth_handle_name,
                                                auth_policy, hash_alg, &command,
                                                authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_SetPrimaryPolicy(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_ChangePPS(
    const TPMI_RH_PLATFORM& auth_handle,
    const std::string& auth_handle_name,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_ChangePPS;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_handle_bytes;
  rc = Serialize_TPMI_RH_PLATFORM(auth_handle, &auth_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(auth_handle_name.data(), auth_handle_name.size());
  handle_section_bytes += auth_handle_bytes;
  command_size += auth_handle_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_ChangePPS(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_ChangePPS;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void ChangePPSErrorCallback(const Tpm::ChangePPSResponse& callback,
                            TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void ChangePPSResponseParser(const Tpm::ChangePPSResponse& callback,
                             AuthorizationDelegate* authorization_delegate,
                             const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ChangePPSErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_ChangePPS(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::ChangePPS(const TPMI_RH_PLATFORM& auth_handle,
                    const std::string& auth_handle_name,
                    AuthorizationDelegate* authorization_delegate,
                    const ChangePPSResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ChangePPSErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(ChangePPSResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_ChangePPS(auth_handle, auth_handle_name,
                                         &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::ChangePPSSync(const TPMI_RH_PLATFORM& auth_handle,
                          const std::string& auth_handle_name,
                          AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_ChangePPS(auth_handle, auth_handle_name,
                                         &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_ChangePPS(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_ChangeEPS(
    const TPMI_RH_PLATFORM& auth_handle,
    const std::string& auth_handle_name,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_ChangeEPS;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_handle_bytes;
  rc = Serialize_TPMI_RH_PLATFORM(auth_handle, &auth_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(auth_handle_name.data(), auth_handle_name.size());
  handle_section_bytes += auth_handle_bytes;
  command_size += auth_handle_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_ChangeEPS(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_ChangeEPS;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void ChangeEPSErrorCallback(const Tpm::ChangeEPSResponse& callback,
                            TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void ChangeEPSResponseParser(const Tpm::ChangeEPSResponse& callback,
                             AuthorizationDelegate* authorization_delegate,
                             const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ChangeEPSErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_ChangeEPS(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::ChangeEPS(const TPMI_RH_PLATFORM& auth_handle,
                    const std::string& auth_handle_name,
                    AuthorizationDelegate* authorization_delegate,
                    const ChangeEPSResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ChangeEPSErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(ChangeEPSResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_ChangeEPS(auth_handle, auth_handle_name,
                                         &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::ChangeEPSSync(const TPMI_RH_PLATFORM& auth_handle,
                          const std::string& auth_handle_name,
                          AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_ChangeEPS(auth_handle, auth_handle_name,
                                         &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_ChangeEPS(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_Clear(
    const TPMI_RH_CLEAR& auth_handle,
    const std::string& auth_handle_name,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_Clear;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_handle_bytes;
  rc = Serialize_TPMI_RH_CLEAR(auth_handle, &auth_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(auth_handle_name.data(), auth_handle_name.size());
  handle_section_bytes += auth_handle_bytes;
  command_size += auth_handle_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_Clear(const std::string& response,
                                AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_Clear;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void ClearErrorCallback(const Tpm::ClearResponse& callback,
                        TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void ClearResponseParser(const Tpm::ClearResponse& callback,
                         AuthorizationDelegate* authorization_delegate,
                         const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ClearErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_Clear(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::Clear(const TPMI_RH_CLEAR& auth_handle,
                const std::string& auth_handle_name,
                AuthorizationDelegate* authorization_delegate,
                const ClearResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ClearErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(ClearResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_Clear(auth_handle, auth_handle_name, &command,
                                     authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::ClearSync(const TPMI_RH_CLEAR& auth_handle,
                      const std::string& auth_handle_name,
                      AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_Clear(auth_handle, auth_handle_name, &command,
                                     authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_Clear(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_ClearControl(
    const TPMI_RH_CLEAR& auth,
    const std::string& auth_name,
    const TPMI_YES_NO& disable,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_ClearControl;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_bytes;
  rc = Serialize_TPMI_RH_CLEAR(auth, &auth_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string disable_bytes;
  rc = Serialize_TPMI_YES_NO(disable, &disable_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(auth_name.data(), auth_name.size());
  handle_section_bytes += auth_bytes;
  command_size += auth_bytes.size();
  hash->Update(disable_bytes.data(), disable_bytes.size());
  parameter_section_bytes += disable_bytes;
  command_size += disable_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_ClearControl(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_ClearControl;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void ClearControlErrorCallback(const Tpm::ClearControlResponse& callback,
                               TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void ClearControlResponseParser(const Tpm::ClearControlResponse& callback,
                                AuthorizationDelegate* authorization_delegate,
                                const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ClearControlErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_ClearControl(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::ClearControl(const TPMI_RH_CLEAR& auth,
                       const std::string& auth_name,
                       const TPMI_YES_NO& disable,
                       AuthorizationDelegate* authorization_delegate,
                       const ClearControlResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ClearControlErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(ClearControlResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_ClearControl(auth, auth_name, disable, &command,
                                            authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::ClearControlSync(const TPMI_RH_CLEAR& auth,
                             const std::string& auth_name,
                             const TPMI_YES_NO& disable,
                             AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_ClearControl(auth, auth_name, disable, &command,
                                            authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_ClearControl(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_HierarchyChangeAuth(
    const TPMI_RH_HIERARCHY_AUTH& auth_handle,
    const std::string& auth_handle_name,
    const TPM2B_AUTH& new_auth,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_HierarchyChangeAuth;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_handle_bytes;
  rc = Serialize_TPMI_RH_HIERARCHY_AUTH(auth_handle, &auth_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string new_auth_bytes;
  rc = Serialize_TPM2B_AUTH(new_auth, &new_auth_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = new_auth_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    new_auth_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(auth_handle_name.data(), auth_handle_name.size());
  handle_section_bytes += auth_handle_bytes;
  command_size += auth_handle_bytes.size();
  hash->Update(new_auth_bytes.data(), new_auth_bytes.size());
  parameter_section_bytes += new_auth_bytes;
  command_size += new_auth_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_HierarchyChangeAuth(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_HierarchyChangeAuth;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void HierarchyChangeAuthErrorCallback(
    const Tpm::HierarchyChangeAuthResponse& callback,
    TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void HierarchyChangeAuthResponseParser(
    const Tpm::HierarchyChangeAuthResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(HierarchyChangeAuthErrorCallback, callback);
  TPM_RC rc =
      Tpm::ParseResponse_HierarchyChangeAuth(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::HierarchyChangeAuth(const TPMI_RH_HIERARCHY_AUTH& auth_handle,
                              const std::string& auth_handle_name,
                              const TPM2B_AUTH& new_auth,
                              AuthorizationDelegate* authorization_delegate,
                              const HierarchyChangeAuthResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(HierarchyChangeAuthErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      HierarchyChangeAuthResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_HierarchyChangeAuth(
      auth_handle, auth_handle_name, new_auth, &command,
      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::HierarchyChangeAuthSync(
    const TPMI_RH_HIERARCHY_AUTH& auth_handle,
    const std::string& auth_handle_name,
    const TPM2B_AUTH& new_auth,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_HierarchyChangeAuth(
      auth_handle, auth_handle_name, new_auth, &command,
      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_HierarchyChangeAuth(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_DictionaryAttackLockReset(
    const TPMI_RH_LOCKOUT& lock_handle,
    const std::string& lock_handle_name,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_DictionaryAttackLockReset;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string lock_handle_bytes;
  rc = Serialize_TPMI_RH_LOCKOUT(lock_handle, &lock_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(lock_handle_name.data(), lock_handle_name.size());
  handle_section_bytes += lock_handle_bytes;
  command_size += lock_handle_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_DictionaryAttackLockReset(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_DictionaryAttackLockReset;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void DictionaryAttackLockResetErrorCallback(
    const Tpm::DictionaryAttackLockResetResponse& callback,
    TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void DictionaryAttackLockResetResponseParser(
    const Tpm::DictionaryAttackLockResetResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(DictionaryAttackLockResetErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_DictionaryAttackLockReset(
      response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::DictionaryAttackLockReset(
    const TPMI_RH_LOCKOUT& lock_handle,
    const std::string& lock_handle_name,
    AuthorizationDelegate* authorization_delegate,
    const DictionaryAttackLockResetResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(DictionaryAttackLockResetErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(DictionaryAttackLockResetResponseParser, callback,
                 authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_DictionaryAttackLockReset(
      lock_handle, lock_handle_name, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::DictionaryAttackLockResetSync(
    const TPMI_RH_LOCKOUT& lock_handle,
    const std::string& lock_handle_name,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_DictionaryAttackLockReset(
      lock_handle, lock_handle_name, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc =
      ParseResponse_DictionaryAttackLockReset(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_DictionaryAttackParameters(
    const TPMI_RH_LOCKOUT& lock_handle,
    const std::string& lock_handle_name,
    const UINT32& new_max_tries,
    const UINT32& new_recovery_time,
    const UINT32& lockout_recovery,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_DictionaryAttackParameters;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string lock_handle_bytes;
  rc = Serialize_TPMI_RH_LOCKOUT(lock_handle, &lock_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string new_max_tries_bytes;
  rc = Serialize_UINT32(new_max_tries, &new_max_tries_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string new_recovery_time_bytes;
  rc = Serialize_UINT32(new_recovery_time, &new_recovery_time_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string lockout_recovery_bytes;
  rc = Serialize_UINT32(lockout_recovery, &lockout_recovery_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(lock_handle_name.data(), lock_handle_name.size());
  handle_section_bytes += lock_handle_bytes;
  command_size += lock_handle_bytes.size();
  hash->Update(new_max_tries_bytes.data(), new_max_tries_bytes.size());
  parameter_section_bytes += new_max_tries_bytes;
  command_size += new_max_tries_bytes.size();
  hash->Update(new_recovery_time_bytes.data(), new_recovery_time_bytes.size());
  parameter_section_bytes += new_recovery_time_bytes;
  command_size += new_recovery_time_bytes.size();
  hash->Update(lockout_recovery_bytes.data(), lockout_recovery_bytes.size());
  parameter_section_bytes += lockout_recovery_bytes;
  command_size += lockout_recovery_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_DictionaryAttackParameters(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_DictionaryAttackParameters;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void DictionaryAttackParametersErrorCallback(
    const Tpm::DictionaryAttackParametersResponse& callback,
    TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void DictionaryAttackParametersResponseParser(
    const Tpm::DictionaryAttackParametersResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(DictionaryAttackParametersErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_DictionaryAttackParameters(
      response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::DictionaryAttackParameters(
    const TPMI_RH_LOCKOUT& lock_handle,
    const std::string& lock_handle_name,
    const UINT32& new_max_tries,
    const UINT32& new_recovery_time,
    const UINT32& lockout_recovery,
    AuthorizationDelegate* authorization_delegate,
    const DictionaryAttackParametersResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(DictionaryAttackParametersErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(DictionaryAttackParametersResponseParser, callback,
                 authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_DictionaryAttackParameters(
      lock_handle, lock_handle_name, new_max_tries, new_recovery_time,
      lockout_recovery, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::DictionaryAttackParametersSync(
    const TPMI_RH_LOCKOUT& lock_handle,
    const std::string& lock_handle_name,
    const UINT32& new_max_tries,
    const UINT32& new_recovery_time,
    const UINT32& lockout_recovery,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_DictionaryAttackParameters(
      lock_handle, lock_handle_name, new_max_tries, new_recovery_time,
      lockout_recovery, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_DictionaryAttackParameters(response,
                                                authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_PP_Commands(
    const TPMI_RH_PLATFORM& auth,
    const std::string& auth_name,
    const TPML_CC& set_list,
    const TPML_CC& clear_list,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_PP_Commands;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_bytes;
  rc = Serialize_TPMI_RH_PLATFORM(auth, &auth_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string set_list_bytes;
  rc = Serialize_TPML_CC(set_list, &set_list_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string clear_list_bytes;
  rc = Serialize_TPML_CC(clear_list, &clear_list_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(auth_name.data(), auth_name.size());
  handle_section_bytes += auth_bytes;
  command_size += auth_bytes.size();
  hash->Update(set_list_bytes.data(), set_list_bytes.size());
  parameter_section_bytes += set_list_bytes;
  command_size += set_list_bytes.size();
  hash->Update(clear_list_bytes.data(), clear_list_bytes.size());
  parameter_section_bytes += clear_list_bytes;
  command_size += clear_list_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_PP_Commands(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_PP_Commands;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void PP_CommandsErrorCallback(const Tpm::PP_CommandsResponse& callback,
                              TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void PP_CommandsResponseParser(const Tpm::PP_CommandsResponse& callback,
                               AuthorizationDelegate* authorization_delegate,
                               const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PP_CommandsErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_PP_Commands(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::PP_Commands(const TPMI_RH_PLATFORM& auth,
                      const std::string& auth_name,
                      const TPML_CC& set_list,
                      const TPML_CC& clear_list,
                      AuthorizationDelegate* authorization_delegate,
                      const PP_CommandsResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(PP_CommandsErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(PP_CommandsResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_PP_Commands(
      auth, auth_name, set_list, clear_list, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::PP_CommandsSync(const TPMI_RH_PLATFORM& auth,
                            const std::string& auth_name,
                            const TPML_CC& set_list,
                            const TPML_CC& clear_list,
                            AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_PP_Commands(
      auth, auth_name, set_list, clear_list, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_PP_Commands(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_SetAlgorithmSet(
    const TPMI_RH_PLATFORM& auth_handle,
    const std::string& auth_handle_name,
    const UINT32& algorithm_set,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_SetAlgorithmSet;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_handle_bytes;
  rc = Serialize_TPMI_RH_PLATFORM(auth_handle, &auth_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string algorithm_set_bytes;
  rc = Serialize_UINT32(algorithm_set, &algorithm_set_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(auth_handle_name.data(), auth_handle_name.size());
  handle_section_bytes += auth_handle_bytes;
  command_size += auth_handle_bytes.size();
  hash->Update(algorithm_set_bytes.data(), algorithm_set_bytes.size());
  parameter_section_bytes += algorithm_set_bytes;
  command_size += algorithm_set_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_SetAlgorithmSet(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_SetAlgorithmSet;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void SetAlgorithmSetErrorCallback(const Tpm::SetAlgorithmSetResponse& callback,
                                  TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void SetAlgorithmSetResponseParser(
    const Tpm::SetAlgorithmSetResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(SetAlgorithmSetErrorCallback, callback);
  TPM_RC rc =
      Tpm::ParseResponse_SetAlgorithmSet(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::SetAlgorithmSet(const TPMI_RH_PLATFORM& auth_handle,
                          const std::string& auth_handle_name,
                          const UINT32& algorithm_set,
                          AuthorizationDelegate* authorization_delegate,
                          const SetAlgorithmSetResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(SetAlgorithmSetErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      SetAlgorithmSetResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_SetAlgorithmSet(auth_handle, auth_handle_name,
                                               algorithm_set, &command,
                                               authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::SetAlgorithmSetSync(const TPMI_RH_PLATFORM& auth_handle,
                                const std::string& auth_handle_name,
                                const UINT32& algorithm_set,
                                AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_SetAlgorithmSet(auth_handle, auth_handle_name,
                                               algorithm_set, &command,
                                               authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_SetAlgorithmSet(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_FieldUpgradeStart(
    const TPMI_RH_PLATFORM& authorization,
    const std::string& authorization_name,
    const TPMI_DH_OBJECT& key_handle,
    const std::string& key_handle_name,
    const TPM2B_DIGEST& fu_digest,
    const TPMT_SIGNATURE& manifest_signature,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_FieldUpgradeStart;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_bytes;
  rc = Serialize_TPMI_RH_PLATFORM(authorization, &authorization_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string key_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(key_handle, &key_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string fu_digest_bytes;
  rc = Serialize_TPM2B_DIGEST(fu_digest, &fu_digest_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string manifest_signature_bytes;
  rc = Serialize_TPMT_SIGNATURE(manifest_signature, &manifest_signature_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = fu_digest_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    fu_digest_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(authorization_name.data(), authorization_name.size());
  handle_section_bytes += authorization_bytes;
  command_size += authorization_bytes.size();
  hash->Update(key_handle_name.data(), key_handle_name.size());
  handle_section_bytes += key_handle_bytes;
  command_size += key_handle_bytes.size();
  hash->Update(fu_digest_bytes.data(), fu_digest_bytes.size());
  parameter_section_bytes += fu_digest_bytes;
  command_size += fu_digest_bytes.size();
  hash->Update(manifest_signature_bytes.data(),
               manifest_signature_bytes.size());
  parameter_section_bytes += manifest_signature_bytes;
  command_size += manifest_signature_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_FieldUpgradeStart(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_FieldUpgradeStart;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void FieldUpgradeStartErrorCallback(
    const Tpm::FieldUpgradeStartResponse& callback,
    TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void FieldUpgradeStartResponseParser(
    const Tpm::FieldUpgradeStartResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(FieldUpgradeStartErrorCallback, callback);
  TPM_RC rc =
      Tpm::ParseResponse_FieldUpgradeStart(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::FieldUpgradeStart(const TPMI_RH_PLATFORM& authorization,
                            const std::string& authorization_name,
                            const TPMI_DH_OBJECT& key_handle,
                            const std::string& key_handle_name,
                            const TPM2B_DIGEST& fu_digest,
                            const TPMT_SIGNATURE& manifest_signature,
                            AuthorizationDelegate* authorization_delegate,
                            const FieldUpgradeStartResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(FieldUpgradeStartErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      FieldUpgradeStartResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_FieldUpgradeStart(
      authorization, authorization_name, key_handle, key_handle_name, fu_digest,
      manifest_signature, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::FieldUpgradeStartSync(
    const TPMI_RH_PLATFORM& authorization,
    const std::string& authorization_name,
    const TPMI_DH_OBJECT& key_handle,
    const std::string& key_handle_name,
    const TPM2B_DIGEST& fu_digest,
    const TPMT_SIGNATURE& manifest_signature,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_FieldUpgradeStart(
      authorization, authorization_name, key_handle, key_handle_name, fu_digest,
      manifest_signature, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_FieldUpgradeStart(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_FieldUpgradeData(
    const TPM2B_MAX_BUFFER& fu_data,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_FieldUpgradeData;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string fu_data_bytes;
  rc = Serialize_TPM2B_MAX_BUFFER(fu_data, &fu_data_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = fu_data_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    fu_data_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(fu_data_bytes.data(), fu_data_bytes.size());
  parameter_section_bytes += fu_data_bytes;
  command_size += fu_data_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_FieldUpgradeData(
    const std::string& response,
    TPMT_HA* next_digest,
    TPMT_HA* first_digest,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_FieldUpgradeData;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string next_digest_bytes;
  rc = Parse_TPMT_HA(&buffer, next_digest, &next_digest_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string first_digest_bytes;
  rc = Parse_TPMT_HA(&buffer, first_digest, &first_digest_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  return TPM_RC_SUCCESS;
}

void FieldUpgradeDataErrorCallback(
    const Tpm::FieldUpgradeDataResponse& callback,
    TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPMT_HA(), TPMT_HA());
}

void FieldUpgradeDataResponseParser(
    const Tpm::FieldUpgradeDataResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(FieldUpgradeDataErrorCallback, callback);
  TPMT_HA next_digest;
  TPMT_HA first_digest;
  TPM_RC rc = Tpm::ParseResponse_FieldUpgradeData(
      response, &next_digest, &first_digest, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, next_digest, first_digest);
}

void Tpm::FieldUpgradeData(const TPM2B_MAX_BUFFER& fu_data,
                           AuthorizationDelegate* authorization_delegate,
                           const FieldUpgradeDataResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(FieldUpgradeDataErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      FieldUpgradeDataResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_FieldUpgradeData(fu_data, &command,
                                                authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::FieldUpgradeDataSync(
    const TPM2B_MAX_BUFFER& fu_data,
    TPMT_HA* next_digest,
    TPMT_HA* first_digest,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_FieldUpgradeData(fu_data, &command,
                                                authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_FieldUpgradeData(response, next_digest, first_digest,
                                      authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_FirmwareRead(
    const UINT32& sequence_number,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_FirmwareRead;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string sequence_number_bytes;
  rc = Serialize_UINT32(sequence_number, &sequence_number_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(sequence_number_bytes.data(), sequence_number_bytes.size());
  parameter_section_bytes += sequence_number_bytes;
  command_size += sequence_number_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_FirmwareRead(
    const std::string& response,
    TPM2B_MAX_BUFFER* fu_data,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_FirmwareRead;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string fu_data_bytes;
  rc = Parse_TPM2B_MAX_BUFFER(&buffer, fu_data, &fu_data_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = fu_data_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    fu_data_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_MAX_BUFFER(&fu_data_bytes, fu_data, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void FirmwareReadErrorCallback(const Tpm::FirmwareReadResponse& callback,
                               TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_MAX_BUFFER());
}

void FirmwareReadResponseParser(const Tpm::FirmwareReadResponse& callback,
                                AuthorizationDelegate* authorization_delegate,
                                const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(FirmwareReadErrorCallback, callback);
  TPM2B_MAX_BUFFER fu_data;
  TPM_RC rc = Tpm::ParseResponse_FirmwareRead(response, &fu_data,
                                              authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, fu_data);
}

void Tpm::FirmwareRead(const UINT32& sequence_number,
                       AuthorizationDelegate* authorization_delegate,
                       const FirmwareReadResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(FirmwareReadErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(FirmwareReadResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_FirmwareRead(sequence_number, &command,
                                            authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::FirmwareReadSync(const UINT32& sequence_number,
                             TPM2B_MAX_BUFFER* fu_data,
                             AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_FirmwareRead(sequence_number, &command,
                                            authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_FirmwareRead(response, fu_data, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_ContextSave(
    const TPMI_DH_CONTEXT& save_handle,
    const std::string& save_handle_name,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_ContextSave;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string save_handle_bytes;
  rc = Serialize_TPMI_DH_CONTEXT(save_handle, &save_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(save_handle_name.data(), save_handle_name.size());
  handle_section_bytes += save_handle_bytes;
  command_size += save_handle_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_ContextSave(
    const std::string& response,
    TPMS_CONTEXT* context,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_ContextSave;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string context_bytes;
  rc = Parse_TPMS_CONTEXT(&buffer, context, &context_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  return TPM_RC_SUCCESS;
}

void ContextSaveErrorCallback(const Tpm::ContextSaveResponse& callback,
                              TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPMS_CONTEXT());
}

void ContextSaveResponseParser(const Tpm::ContextSaveResponse& callback,
                               AuthorizationDelegate* authorization_delegate,
                               const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ContextSaveErrorCallback, callback);
  TPMS_CONTEXT context;
  TPM_RC rc = Tpm::ParseResponse_ContextSave(response, &context,
                                             authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, context);
}

void Tpm::ContextSave(const TPMI_DH_CONTEXT& save_handle,
                      const std::string& save_handle_name,
                      AuthorizationDelegate* authorization_delegate,
                      const ContextSaveResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ContextSaveErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(ContextSaveResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_ContextSave(save_handle, save_handle_name,
                                           &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::ContextSaveSync(const TPMI_DH_CONTEXT& save_handle,
                            const std::string& save_handle_name,
                            TPMS_CONTEXT* context,
                            AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_ContextSave(save_handle, save_handle_name,
                                           &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_ContextSave(response, context, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_ContextLoad(
    const TPMS_CONTEXT& context,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_ContextLoad;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string context_bytes;
  rc = Serialize_TPMS_CONTEXT(context, &context_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(context_bytes.data(), context_bytes.size());
  parameter_section_bytes += context_bytes;
  command_size += context_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_ContextLoad(
    const std::string& response,
    TPMI_DH_CONTEXT* loaded_handle,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  std::string loaded_handle_bytes;
  rc = Parse_TPMI_DH_CONTEXT(&buffer, loaded_handle, &loaded_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_CC command_code = TPM_CC_ContextLoad;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void ContextLoadErrorCallback(const Tpm::ContextLoadResponse& callback,
                              TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPMI_DH_CONTEXT());
}

void ContextLoadResponseParser(const Tpm::ContextLoadResponse& callback,
                               AuthorizationDelegate* authorization_delegate,
                               const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ContextLoadErrorCallback, callback);
  TPMI_DH_CONTEXT loaded_handle;
  TPM_RC rc = Tpm::ParseResponse_ContextLoad(response, &loaded_handle,
                                             authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, loaded_handle);
}

void Tpm::ContextLoad(const TPMS_CONTEXT& context,
                      AuthorizationDelegate* authorization_delegate,
                      const ContextLoadResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ContextLoadErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(ContextLoadResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc =
      SerializeCommand_ContextLoad(context, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::ContextLoadSync(const TPMS_CONTEXT& context,
                            TPMI_DH_CONTEXT* loaded_handle,
                            AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc =
      SerializeCommand_ContextLoad(context, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_ContextLoad(response, loaded_handle,
                                 authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_FlushContext(
    const TPMI_DH_CONTEXT& flush_handle,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_FlushContext;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string flush_handle_bytes;
  rc = Serialize_TPMI_DH_CONTEXT(flush_handle, &flush_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(flush_handle_bytes.data(), flush_handle_bytes.size());
  parameter_section_bytes += flush_handle_bytes;
  command_size += flush_handle_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_FlushContext(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_FlushContext;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void FlushContextErrorCallback(const Tpm::FlushContextResponse& callback,
                               TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void FlushContextResponseParser(const Tpm::FlushContextResponse& callback,
                                AuthorizationDelegate* authorization_delegate,
                                const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(FlushContextErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_FlushContext(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::FlushContext(const TPMI_DH_CONTEXT& flush_handle,
                       AuthorizationDelegate* authorization_delegate,
                       const FlushContextResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(FlushContextErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(FlushContextResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_FlushContext(flush_handle, &command,
                                            authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::FlushContextSync(const TPMI_DH_CONTEXT& flush_handle,
                             AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_FlushContext(flush_handle, &command,
                                            authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_FlushContext(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_EvictControl(
    const TPMI_RH_PROVISION& auth,
    const std::string& auth_name,
    const TPMI_DH_OBJECT& object_handle,
    const std::string& object_handle_name,
    const TPMI_DH_PERSISTENT& persistent_handle,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_EvictControl;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_bytes;
  rc = Serialize_TPMI_RH_PROVISION(auth, &auth_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string object_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(object_handle, &object_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string persistent_handle_bytes;
  rc =
      Serialize_TPMI_DH_PERSISTENT(persistent_handle, &persistent_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(auth_name.data(), auth_name.size());
  handle_section_bytes += auth_bytes;
  command_size += auth_bytes.size();
  hash->Update(object_handle_name.data(), object_handle_name.size());
  handle_section_bytes += object_handle_bytes;
  command_size += object_handle_bytes.size();
  hash->Update(persistent_handle_bytes.data(), persistent_handle_bytes.size());
  parameter_section_bytes += persistent_handle_bytes;
  command_size += persistent_handle_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_EvictControl(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_EvictControl;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void EvictControlErrorCallback(const Tpm::EvictControlResponse& callback,
                               TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void EvictControlResponseParser(const Tpm::EvictControlResponse& callback,
                                AuthorizationDelegate* authorization_delegate,
                                const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(EvictControlErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_EvictControl(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::EvictControl(const TPMI_RH_PROVISION& auth,
                       const std::string& auth_name,
                       const TPMI_DH_OBJECT& object_handle,
                       const std::string& object_handle_name,
                       const TPMI_DH_PERSISTENT& persistent_handle,
                       AuthorizationDelegate* authorization_delegate,
                       const EvictControlResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(EvictControlErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(EvictControlResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_EvictControl(
      auth, auth_name, object_handle, object_handle_name, persistent_handle,
      &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::EvictControlSync(const TPMI_RH_PROVISION& auth,
                             const std::string& auth_name,
                             const TPMI_DH_OBJECT& object_handle,
                             const std::string& object_handle_name,
                             const TPMI_DH_PERSISTENT& persistent_handle,
                             AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_EvictControl(
      auth, auth_name, object_handle, object_handle_name, persistent_handle,
      &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_EvictControl(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_ReadClock(
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_ReadClock;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_ReadClock(
    const std::string& response,
    TPMS_TIME_INFO* current_time,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_ReadClock;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string current_time_bytes;
  rc = Parse_TPMS_TIME_INFO(&buffer, current_time, &current_time_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  return TPM_RC_SUCCESS;
}

void ReadClockErrorCallback(const Tpm::ReadClockResponse& callback,
                            TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPMS_TIME_INFO());
}

void ReadClockResponseParser(const Tpm::ReadClockResponse& callback,
                             AuthorizationDelegate* authorization_delegate,
                             const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ReadClockErrorCallback, callback);
  TPMS_TIME_INFO current_time;
  TPM_RC rc = Tpm::ParseResponse_ReadClock(response, &current_time,
                                           authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, current_time);
}

void Tpm::ReadClock(AuthorizationDelegate* authorization_delegate,
                    const ReadClockResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ReadClockErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(ReadClockResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_ReadClock(&command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::ReadClockSync(TPMS_TIME_INFO* current_time,
                          AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_ReadClock(&command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_ReadClock(response, current_time, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_ClockSet(
    const TPMI_RH_PROVISION& auth,
    const std::string& auth_name,
    const UINT64& new_time,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_ClockSet;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_bytes;
  rc = Serialize_TPMI_RH_PROVISION(auth, &auth_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string new_time_bytes;
  rc = Serialize_UINT64(new_time, &new_time_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(auth_name.data(), auth_name.size());
  handle_section_bytes += auth_bytes;
  command_size += auth_bytes.size();
  hash->Update(new_time_bytes.data(), new_time_bytes.size());
  parameter_section_bytes += new_time_bytes;
  command_size += new_time_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_ClockSet(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_ClockSet;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void ClockSetErrorCallback(const Tpm::ClockSetResponse& callback,
                           TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void ClockSetResponseParser(const Tpm::ClockSetResponse& callback,
                            AuthorizationDelegate* authorization_delegate,
                            const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ClockSetErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_ClockSet(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::ClockSet(const TPMI_RH_PROVISION& auth,
                   const std::string& auth_name,
                   const UINT64& new_time,
                   AuthorizationDelegate* authorization_delegate,
                   const ClockSetResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ClockSetErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(ClockSetResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_ClockSet(auth, auth_name, new_time, &command,
                                        authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::ClockSetSync(const TPMI_RH_PROVISION& auth,
                         const std::string& auth_name,
                         const UINT64& new_time,
                         AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_ClockSet(auth, auth_name, new_time, &command,
                                        authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_ClockSet(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_ClockRateAdjust(
    const TPMI_RH_PROVISION& auth,
    const std::string& auth_name,
    const TPM_CLOCK_ADJUST& rate_adjust,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_ClockRateAdjust;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_bytes;
  rc = Serialize_TPMI_RH_PROVISION(auth, &auth_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string rate_adjust_bytes;
  rc = Serialize_TPM_CLOCK_ADJUST(rate_adjust, &rate_adjust_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(auth_name.data(), auth_name.size());
  handle_section_bytes += auth_bytes;
  command_size += auth_bytes.size();
  hash->Update(rate_adjust_bytes.data(), rate_adjust_bytes.size());
  parameter_section_bytes += rate_adjust_bytes;
  command_size += rate_adjust_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_ClockRateAdjust(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_ClockRateAdjust;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void ClockRateAdjustErrorCallback(const Tpm::ClockRateAdjustResponse& callback,
                                  TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void ClockRateAdjustResponseParser(
    const Tpm::ClockRateAdjustResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ClockRateAdjustErrorCallback, callback);
  TPM_RC rc =
      Tpm::ParseResponse_ClockRateAdjust(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::ClockRateAdjust(const TPMI_RH_PROVISION& auth,
                          const std::string& auth_name,
                          const TPM_CLOCK_ADJUST& rate_adjust,
                          AuthorizationDelegate* authorization_delegate,
                          const ClockRateAdjustResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(ClockRateAdjustErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      ClockRateAdjustResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_ClockRateAdjust(
      auth, auth_name, rate_adjust, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::ClockRateAdjustSync(const TPMI_RH_PROVISION& auth,
                                const std::string& auth_name,
                                const TPM_CLOCK_ADJUST& rate_adjust,
                                AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_ClockRateAdjust(
      auth, auth_name, rate_adjust, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_ClockRateAdjust(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_GetCapability(
    const TPM_CAP& capability,
    const UINT32& property,
    const UINT32& property_count,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_GetCapability;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string capability_bytes;
  rc = Serialize_TPM_CAP(capability, &capability_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string property_bytes;
  rc = Serialize_UINT32(property, &property_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string property_count_bytes;
  rc = Serialize_UINT32(property_count, &property_count_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(capability_bytes.data(), capability_bytes.size());
  parameter_section_bytes += capability_bytes;
  command_size += capability_bytes.size();
  hash->Update(property_bytes.data(), property_bytes.size());
  parameter_section_bytes += property_bytes;
  command_size += property_bytes.size();
  hash->Update(property_count_bytes.data(), property_count_bytes.size());
  parameter_section_bytes += property_count_bytes;
  command_size += property_count_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_GetCapability(
    const std::string& response,
    TPMI_YES_NO* more_data,
    TPMS_CAPABILITY_DATA* capability_data,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_GetCapability;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string more_data_bytes;
  rc = Parse_TPMI_YES_NO(&buffer, more_data, &more_data_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string capability_data_bytes;
  rc = Parse_TPMS_CAPABILITY_DATA(&buffer, capability_data,
                                  &capability_data_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  return TPM_RC_SUCCESS;
}

void GetCapabilityErrorCallback(const Tpm::GetCapabilityResponse& callback,
                                TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPMI_YES_NO(), TPMS_CAPABILITY_DATA());
}

void GetCapabilityResponseParser(const Tpm::GetCapabilityResponse& callback,
                                 AuthorizationDelegate* authorization_delegate,
                                 const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(GetCapabilityErrorCallback, callback);
  TPMI_YES_NO more_data;
  TPMS_CAPABILITY_DATA capability_data;
  TPM_RC rc = Tpm::ParseResponse_GetCapability(
      response, &more_data, &capability_data, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, more_data, capability_data);
}

void Tpm::GetCapability(const TPM_CAP& capability,
                        const UINT32& property,
                        const UINT32& property_count,
                        AuthorizationDelegate* authorization_delegate,
                        const GetCapabilityResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(GetCapabilityErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(GetCapabilityResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_GetCapability(
      capability, property, property_count, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::GetCapabilitySync(const TPM_CAP& capability,
                              const UINT32& property,
                              const UINT32& property_count,
                              TPMI_YES_NO* more_data,
                              TPMS_CAPABILITY_DATA* capability_data,
                              AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_GetCapability(
      capability, property, property_count, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_GetCapability(response, more_data, capability_data,
                                   authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_TestParms(
    const TPMT_PUBLIC_PARMS& parameters,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_TestParms;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string parameters_bytes;
  rc = Serialize_TPMT_PUBLIC_PARMS(parameters, &parameters_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(parameters_bytes.data(), parameters_bytes.size());
  parameter_section_bytes += parameters_bytes;
  command_size += parameters_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_TestParms(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_TestParms;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void TestParmsErrorCallback(const Tpm::TestParmsResponse& callback,
                            TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void TestParmsResponseParser(const Tpm::TestParmsResponse& callback,
                             AuthorizationDelegate* authorization_delegate,
                             const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(TestParmsErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_TestParms(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::TestParms(const TPMT_PUBLIC_PARMS& parameters,
                    AuthorizationDelegate* authorization_delegate,
                    const TestParmsResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(TestParmsErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(TestParmsResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc =
      SerializeCommand_TestParms(parameters, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::TestParmsSync(const TPMT_PUBLIC_PARMS& parameters,
                          AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc =
      SerializeCommand_TestParms(parameters, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_TestParms(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_NV_DefineSpace(
    const TPMI_RH_PROVISION& auth_handle,
    const std::string& auth_handle_name,
    const TPM2B_AUTH& auth,
    const TPM2B_NV_PUBLIC& public_info,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_NV_DefineSpace;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_handle_bytes;
  rc = Serialize_TPMI_RH_PROVISION(auth_handle, &auth_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_bytes;
  rc = Serialize_TPM2B_AUTH(auth, &auth_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string public_info_bytes;
  rc = Serialize_TPM2B_NV_PUBLIC(public_info, &public_info_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = auth_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    auth_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(auth_handle_name.data(), auth_handle_name.size());
  handle_section_bytes += auth_handle_bytes;
  command_size += auth_handle_bytes.size();
  hash->Update(auth_bytes.data(), auth_bytes.size());
  parameter_section_bytes += auth_bytes;
  command_size += auth_bytes.size();
  hash->Update(public_info_bytes.data(), public_info_bytes.size());
  parameter_section_bytes += public_info_bytes;
  command_size += public_info_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_NV_DefineSpace(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_NV_DefineSpace;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void NV_DefineSpaceErrorCallback(const Tpm::NV_DefineSpaceResponse& callback,
                                 TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void NV_DefineSpaceResponseParser(const Tpm::NV_DefineSpaceResponse& callback,
                                  AuthorizationDelegate* authorization_delegate,
                                  const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(NV_DefineSpaceErrorCallback, callback);
  TPM_RC rc =
      Tpm::ParseResponse_NV_DefineSpace(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::NV_DefineSpace(const TPMI_RH_PROVISION& auth_handle,
                         const std::string& auth_handle_name,
                         const TPM2B_AUTH& auth,
                         const TPM2B_NV_PUBLIC& public_info,
                         AuthorizationDelegate* authorization_delegate,
                         const NV_DefineSpaceResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(NV_DefineSpaceErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      NV_DefineSpaceResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_NV_DefineSpace(auth_handle, auth_handle_name,
                                              auth, public_info, &command,
                                              authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::NV_DefineSpaceSync(const TPMI_RH_PROVISION& auth_handle,
                               const std::string& auth_handle_name,
                               const TPM2B_AUTH& auth,
                               const TPM2B_NV_PUBLIC& public_info,
                               AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_NV_DefineSpace(auth_handle, auth_handle_name,
                                              auth, public_info, &command,
                                              authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_NV_DefineSpace(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_NV_UndefineSpace(
    const TPMI_RH_PROVISION& auth_handle,
    const std::string& auth_handle_name,
    const TPMI_RH_NV_INDEX& nv_index,
    const std::string& nv_index_name,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_NV_UndefineSpace;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_handle_bytes;
  rc = Serialize_TPMI_RH_PROVISION(auth_handle, &auth_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string nv_index_bytes;
  rc = Serialize_TPMI_RH_NV_INDEX(nv_index, &nv_index_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(auth_handle_name.data(), auth_handle_name.size());
  handle_section_bytes += auth_handle_bytes;
  command_size += auth_handle_bytes.size();
  hash->Update(nv_index_name.data(), nv_index_name.size());
  handle_section_bytes += nv_index_bytes;
  command_size += nv_index_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_NV_UndefineSpace(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_NV_UndefineSpace;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void NV_UndefineSpaceErrorCallback(
    const Tpm::NV_UndefineSpaceResponse& callback,
    TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void NV_UndefineSpaceResponseParser(
    const Tpm::NV_UndefineSpaceResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(NV_UndefineSpaceErrorCallback, callback);
  TPM_RC rc =
      Tpm::ParseResponse_NV_UndefineSpace(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::NV_UndefineSpace(const TPMI_RH_PROVISION& auth_handle,
                           const std::string& auth_handle_name,
                           const TPMI_RH_NV_INDEX& nv_index,
                           const std::string& nv_index_name,
                           AuthorizationDelegate* authorization_delegate,
                           const NV_UndefineSpaceResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(NV_UndefineSpaceErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      NV_UndefineSpaceResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_NV_UndefineSpace(
      auth_handle, auth_handle_name, nv_index, nv_index_name, &command,
      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::NV_UndefineSpaceSync(
    const TPMI_RH_PROVISION& auth_handle,
    const std::string& auth_handle_name,
    const TPMI_RH_NV_INDEX& nv_index,
    const std::string& nv_index_name,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_NV_UndefineSpace(
      auth_handle, auth_handle_name, nv_index, nv_index_name, &command,
      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_NV_UndefineSpace(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_NV_UndefineSpaceSpecial(
    const TPMI_RH_NV_INDEX& nv_index,
    const std::string& nv_index_name,
    const TPMI_RH_PLATFORM& platform,
    const std::string& platform_name,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_NV_UndefineSpaceSpecial;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string nv_index_bytes;
  rc = Serialize_TPMI_RH_NV_INDEX(nv_index, &nv_index_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string platform_bytes;
  rc = Serialize_TPMI_RH_PLATFORM(platform, &platform_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(nv_index_name.data(), nv_index_name.size());
  handle_section_bytes += nv_index_bytes;
  command_size += nv_index_bytes.size();
  hash->Update(platform_name.data(), platform_name.size());
  handle_section_bytes += platform_bytes;
  command_size += platform_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_NV_UndefineSpaceSpecial(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_NV_UndefineSpaceSpecial;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void NV_UndefineSpaceSpecialErrorCallback(
    const Tpm::NV_UndefineSpaceSpecialResponse& callback,
    TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void NV_UndefineSpaceSpecialResponseParser(
    const Tpm::NV_UndefineSpaceSpecialResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(NV_UndefineSpaceSpecialErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_NV_UndefineSpaceSpecial(
      response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::NV_UndefineSpaceSpecial(
    const TPMI_RH_NV_INDEX& nv_index,
    const std::string& nv_index_name,
    const TPMI_RH_PLATFORM& platform,
    const std::string& platform_name,
    AuthorizationDelegate* authorization_delegate,
    const NV_UndefineSpaceSpecialResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(NV_UndefineSpaceSpecialErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      NV_UndefineSpaceSpecialResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_NV_UndefineSpaceSpecial(
      nv_index, nv_index_name, platform, platform_name, &command,
      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::NV_UndefineSpaceSpecialSync(
    const TPMI_RH_NV_INDEX& nv_index,
    const std::string& nv_index_name,
    const TPMI_RH_PLATFORM& platform,
    const std::string& platform_name,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_NV_UndefineSpaceSpecial(
      nv_index, nv_index_name, platform, platform_name, &command,
      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_NV_UndefineSpaceSpecial(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_NV_ReadPublic(
    const TPMI_RH_NV_INDEX& nv_index,
    const std::string& nv_index_name,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_NV_ReadPublic;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string nv_index_bytes;
  rc = Serialize_TPMI_RH_NV_INDEX(nv_index, &nv_index_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(nv_index_name.data(), nv_index_name.size());
  handle_section_bytes += nv_index_bytes;
  command_size += nv_index_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_NV_ReadPublic(
    const std::string& response,
    TPM2B_NV_PUBLIC* nv_public,
    TPM2B_NAME* nv_name,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_NV_ReadPublic;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string nv_public_bytes;
  rc = Parse_TPM2B_NV_PUBLIC(&buffer, nv_public, &nv_public_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string nv_name_bytes;
  rc = Parse_TPM2B_NAME(&buffer, nv_name, &nv_name_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = nv_public_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    nv_public_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_NV_PUBLIC(&nv_public_bytes, nv_public, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void NV_ReadPublicErrorCallback(const Tpm::NV_ReadPublicResponse& callback,
                                TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_NV_PUBLIC(), TPM2B_NAME());
}

void NV_ReadPublicResponseParser(const Tpm::NV_ReadPublicResponse& callback,
                                 AuthorizationDelegate* authorization_delegate,
                                 const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(NV_ReadPublicErrorCallback, callback);
  TPM2B_NV_PUBLIC nv_public;
  TPM2B_NAME nv_name;
  TPM_RC rc = Tpm::ParseResponse_NV_ReadPublic(response, &nv_public, &nv_name,
                                               authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, nv_public, nv_name);
}

void Tpm::NV_ReadPublic(const TPMI_RH_NV_INDEX& nv_index,
                        const std::string& nv_index_name,
                        AuthorizationDelegate* authorization_delegate,
                        const NV_ReadPublicResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(NV_ReadPublicErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(NV_ReadPublicResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_NV_ReadPublic(nv_index, nv_index_name, &command,
                                             authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::NV_ReadPublicSync(const TPMI_RH_NV_INDEX& nv_index,
                              const std::string& nv_index_name,
                              TPM2B_NV_PUBLIC* nv_public,
                              TPM2B_NAME* nv_name,
                              AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_NV_ReadPublic(nv_index, nv_index_name, &command,
                                             authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_NV_ReadPublic(response, nv_public, nv_name,
                                   authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_NV_Write(
    const TPMI_RH_NV_AUTH& auth_handle,
    const std::string& auth_handle_name,
    const TPMI_RH_NV_INDEX& nv_index,
    const std::string& nv_index_name,
    const TPM2B_MAX_NV_BUFFER& data,
    const UINT16& offset,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_NV_Write;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_handle_bytes;
  rc = Serialize_TPMI_RH_NV_AUTH(auth_handle, &auth_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string nv_index_bytes;
  rc = Serialize_TPMI_RH_NV_INDEX(nv_index, &nv_index_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string data_bytes;
  rc = Serialize_TPM2B_MAX_NV_BUFFER(data, &data_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string offset_bytes;
  rc = Serialize_UINT16(offset, &offset_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = data_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    data_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(auth_handle_name.data(), auth_handle_name.size());
  handle_section_bytes += auth_handle_bytes;
  command_size += auth_handle_bytes.size();
  hash->Update(nv_index_name.data(), nv_index_name.size());
  handle_section_bytes += nv_index_bytes;
  command_size += nv_index_bytes.size();
  hash->Update(data_bytes.data(), data_bytes.size());
  parameter_section_bytes += data_bytes;
  command_size += data_bytes.size();
  hash->Update(offset_bytes.data(), offset_bytes.size());
  parameter_section_bytes += offset_bytes;
  command_size += offset_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_NV_Write(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_NV_Write;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void NV_WriteErrorCallback(const Tpm::NV_WriteResponse& callback,
                           TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void NV_WriteResponseParser(const Tpm::NV_WriteResponse& callback,
                            AuthorizationDelegate* authorization_delegate,
                            const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(NV_WriteErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_NV_Write(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::NV_Write(const TPMI_RH_NV_AUTH& auth_handle,
                   const std::string& auth_handle_name,
                   const TPMI_RH_NV_INDEX& nv_index,
                   const std::string& nv_index_name,
                   const TPM2B_MAX_NV_BUFFER& data,
                   const UINT16& offset,
                   AuthorizationDelegate* authorization_delegate,
                   const NV_WriteResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(NV_WriteErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(NV_WriteResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_NV_Write(auth_handle, auth_handle_name, nv_index,
                                        nv_index_name, data, offset, &command,
                                        authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::NV_WriteSync(const TPMI_RH_NV_AUTH& auth_handle,
                         const std::string& auth_handle_name,
                         const TPMI_RH_NV_INDEX& nv_index,
                         const std::string& nv_index_name,
                         const TPM2B_MAX_NV_BUFFER& data,
                         const UINT16& offset,
                         AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_NV_Write(auth_handle, auth_handle_name, nv_index,
                                        nv_index_name, data, offset, &command,
                                        authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_NV_Write(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_NV_Increment(
    const TPMI_RH_NV_AUTH& auth_handle,
    const std::string& auth_handle_name,
    const TPMI_RH_NV_INDEX& nv_index,
    const std::string& nv_index_name,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_NV_Increment;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_handle_bytes;
  rc = Serialize_TPMI_RH_NV_AUTH(auth_handle, &auth_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string nv_index_bytes;
  rc = Serialize_TPMI_RH_NV_INDEX(nv_index, &nv_index_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(auth_handle_name.data(), auth_handle_name.size());
  handle_section_bytes += auth_handle_bytes;
  command_size += auth_handle_bytes.size();
  hash->Update(nv_index_name.data(), nv_index_name.size());
  handle_section_bytes += nv_index_bytes;
  command_size += nv_index_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_NV_Increment(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_NV_Increment;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void NV_IncrementErrorCallback(const Tpm::NV_IncrementResponse& callback,
                               TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void NV_IncrementResponseParser(const Tpm::NV_IncrementResponse& callback,
                                AuthorizationDelegate* authorization_delegate,
                                const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(NV_IncrementErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_NV_Increment(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::NV_Increment(const TPMI_RH_NV_AUTH& auth_handle,
                       const std::string& auth_handle_name,
                       const TPMI_RH_NV_INDEX& nv_index,
                       const std::string& nv_index_name,
                       AuthorizationDelegate* authorization_delegate,
                       const NV_IncrementResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(NV_IncrementErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(NV_IncrementResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_NV_Increment(auth_handle, auth_handle_name,
                                            nv_index, nv_index_name, &command,
                                            authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::NV_IncrementSync(const TPMI_RH_NV_AUTH& auth_handle,
                             const std::string& auth_handle_name,
                             const TPMI_RH_NV_INDEX& nv_index,
                             const std::string& nv_index_name,
                             AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_NV_Increment(auth_handle, auth_handle_name,
                                            nv_index, nv_index_name, &command,
                                            authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_NV_Increment(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_NV_Extend(
    const TPMI_RH_NV_AUTH& auth_handle,
    const std::string& auth_handle_name,
    const TPMI_RH_NV_INDEX& nv_index,
    const std::string& nv_index_name,
    const TPM2B_MAX_NV_BUFFER& data,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_NV_Extend;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_handle_bytes;
  rc = Serialize_TPMI_RH_NV_AUTH(auth_handle, &auth_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string nv_index_bytes;
  rc = Serialize_TPMI_RH_NV_INDEX(nv_index, &nv_index_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string data_bytes;
  rc = Serialize_TPM2B_MAX_NV_BUFFER(data, &data_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = data_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    data_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(auth_handle_name.data(), auth_handle_name.size());
  handle_section_bytes += auth_handle_bytes;
  command_size += auth_handle_bytes.size();
  hash->Update(nv_index_name.data(), nv_index_name.size());
  handle_section_bytes += nv_index_bytes;
  command_size += nv_index_bytes.size();
  hash->Update(data_bytes.data(), data_bytes.size());
  parameter_section_bytes += data_bytes;
  command_size += data_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_NV_Extend(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_NV_Extend;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void NV_ExtendErrorCallback(const Tpm::NV_ExtendResponse& callback,
                            TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void NV_ExtendResponseParser(const Tpm::NV_ExtendResponse& callback,
                             AuthorizationDelegate* authorization_delegate,
                             const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(NV_ExtendErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_NV_Extend(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::NV_Extend(const TPMI_RH_NV_AUTH& auth_handle,
                    const std::string& auth_handle_name,
                    const TPMI_RH_NV_INDEX& nv_index,
                    const std::string& nv_index_name,
                    const TPM2B_MAX_NV_BUFFER& data,
                    AuthorizationDelegate* authorization_delegate,
                    const NV_ExtendResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(NV_ExtendErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(NV_ExtendResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_NV_Extend(auth_handle, auth_handle_name,
                                         nv_index, nv_index_name, data,
                                         &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::NV_ExtendSync(const TPMI_RH_NV_AUTH& auth_handle,
                          const std::string& auth_handle_name,
                          const TPMI_RH_NV_INDEX& nv_index,
                          const std::string& nv_index_name,
                          const TPM2B_MAX_NV_BUFFER& data,
                          AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_NV_Extend(auth_handle, auth_handle_name,
                                         nv_index, nv_index_name, data,
                                         &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_NV_Extend(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_NV_SetBits(
    const TPMI_RH_NV_AUTH& auth_handle,
    const std::string& auth_handle_name,
    const TPMI_RH_NV_INDEX& nv_index,
    const std::string& nv_index_name,
    const UINT64& bits,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_NV_SetBits;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_handle_bytes;
  rc = Serialize_TPMI_RH_NV_AUTH(auth_handle, &auth_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string nv_index_bytes;
  rc = Serialize_TPMI_RH_NV_INDEX(nv_index, &nv_index_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string bits_bytes;
  rc = Serialize_UINT64(bits, &bits_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(auth_handle_name.data(), auth_handle_name.size());
  handle_section_bytes += auth_handle_bytes;
  command_size += auth_handle_bytes.size();
  hash->Update(nv_index_name.data(), nv_index_name.size());
  handle_section_bytes += nv_index_bytes;
  command_size += nv_index_bytes.size();
  hash->Update(bits_bytes.data(), bits_bytes.size());
  parameter_section_bytes += bits_bytes;
  command_size += bits_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_NV_SetBits(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_NV_SetBits;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void NV_SetBitsErrorCallback(const Tpm::NV_SetBitsResponse& callback,
                             TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void NV_SetBitsResponseParser(const Tpm::NV_SetBitsResponse& callback,
                              AuthorizationDelegate* authorization_delegate,
                              const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(NV_SetBitsErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_NV_SetBits(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::NV_SetBits(const TPMI_RH_NV_AUTH& auth_handle,
                     const std::string& auth_handle_name,
                     const TPMI_RH_NV_INDEX& nv_index,
                     const std::string& nv_index_name,
                     const UINT64& bits,
                     AuthorizationDelegate* authorization_delegate,
                     const NV_SetBitsResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(NV_SetBitsErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(NV_SetBitsResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_NV_SetBits(auth_handle, auth_handle_name,
                                          nv_index, nv_index_name, bits,
                                          &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::NV_SetBitsSync(const TPMI_RH_NV_AUTH& auth_handle,
                           const std::string& auth_handle_name,
                           const TPMI_RH_NV_INDEX& nv_index,
                           const std::string& nv_index_name,
                           const UINT64& bits,
                           AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_NV_SetBits(auth_handle, auth_handle_name,
                                          nv_index, nv_index_name, bits,
                                          &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_NV_SetBits(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_NV_WriteLock(
    const TPMI_RH_NV_AUTH& auth_handle,
    const std::string& auth_handle_name,
    const TPMI_RH_NV_INDEX& nv_index,
    const std::string& nv_index_name,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_NV_WriteLock;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_handle_bytes;
  rc = Serialize_TPMI_RH_NV_AUTH(auth_handle, &auth_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string nv_index_bytes;
  rc = Serialize_TPMI_RH_NV_INDEX(nv_index, &nv_index_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(auth_handle_name.data(), auth_handle_name.size());
  handle_section_bytes += auth_handle_bytes;
  command_size += auth_handle_bytes.size();
  hash->Update(nv_index_name.data(), nv_index_name.size());
  handle_section_bytes += nv_index_bytes;
  command_size += nv_index_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_NV_WriteLock(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_NV_WriteLock;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void NV_WriteLockErrorCallback(const Tpm::NV_WriteLockResponse& callback,
                               TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void NV_WriteLockResponseParser(const Tpm::NV_WriteLockResponse& callback,
                                AuthorizationDelegate* authorization_delegate,
                                const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(NV_WriteLockErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_NV_WriteLock(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::NV_WriteLock(const TPMI_RH_NV_AUTH& auth_handle,
                       const std::string& auth_handle_name,
                       const TPMI_RH_NV_INDEX& nv_index,
                       const std::string& nv_index_name,
                       AuthorizationDelegate* authorization_delegate,
                       const NV_WriteLockResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(NV_WriteLockErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(NV_WriteLockResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_NV_WriteLock(auth_handle, auth_handle_name,
                                            nv_index, nv_index_name, &command,
                                            authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::NV_WriteLockSync(const TPMI_RH_NV_AUTH& auth_handle,
                             const std::string& auth_handle_name,
                             const TPMI_RH_NV_INDEX& nv_index,
                             const std::string& nv_index_name,
                             AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_NV_WriteLock(auth_handle, auth_handle_name,
                                            nv_index, nv_index_name, &command,
                                            authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_NV_WriteLock(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_NV_GlobalWriteLock(
    const TPMI_RH_PROVISION& auth_handle,
    const std::string& auth_handle_name,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_NV_GlobalWriteLock;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_handle_bytes;
  rc = Serialize_TPMI_RH_PROVISION(auth_handle, &auth_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(auth_handle_name.data(), auth_handle_name.size());
  handle_section_bytes += auth_handle_bytes;
  command_size += auth_handle_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_NV_GlobalWriteLock(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_NV_GlobalWriteLock;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void NV_GlobalWriteLockErrorCallback(
    const Tpm::NV_GlobalWriteLockResponse& callback,
    TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void NV_GlobalWriteLockResponseParser(
    const Tpm::NV_GlobalWriteLockResponse& callback,
    AuthorizationDelegate* authorization_delegate,
    const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(NV_GlobalWriteLockErrorCallback, callback);
  TPM_RC rc =
      Tpm::ParseResponse_NV_GlobalWriteLock(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::NV_GlobalWriteLock(const TPMI_RH_PROVISION& auth_handle,
                             const std::string& auth_handle_name,
                             AuthorizationDelegate* authorization_delegate,
                             const NV_GlobalWriteLockResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(NV_GlobalWriteLockErrorCallback, callback);
  base::Callback<void(const std::string&)> parser = base::Bind(
      NV_GlobalWriteLockResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_NV_GlobalWriteLock(
      auth_handle, auth_handle_name, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::NV_GlobalWriteLockSync(
    const TPMI_RH_PROVISION& auth_handle,
    const std::string& auth_handle_name,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_NV_GlobalWriteLock(
      auth_handle, auth_handle_name, &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_NV_GlobalWriteLock(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_NV_Read(
    const TPMI_RH_NV_AUTH& auth_handle,
    const std::string& auth_handle_name,
    const TPMI_RH_NV_INDEX& nv_index,
    const std::string& nv_index_name,
    const UINT16& size,
    const UINT16& offset,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_NV_Read;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_handle_bytes;
  rc = Serialize_TPMI_RH_NV_AUTH(auth_handle, &auth_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string nv_index_bytes;
  rc = Serialize_TPMI_RH_NV_INDEX(nv_index, &nv_index_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string size_bytes;
  rc = Serialize_UINT16(size, &size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string offset_bytes;
  rc = Serialize_UINT16(offset, &offset_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(auth_handle_name.data(), auth_handle_name.size());
  handle_section_bytes += auth_handle_bytes;
  command_size += auth_handle_bytes.size();
  hash->Update(nv_index_name.data(), nv_index_name.size());
  handle_section_bytes += nv_index_bytes;
  command_size += nv_index_bytes.size();
  hash->Update(size_bytes.data(), size_bytes.size());
  parameter_section_bytes += size_bytes;
  command_size += size_bytes.size();
  hash->Update(offset_bytes.data(), offset_bytes.size());
  parameter_section_bytes += offset_bytes;
  command_size += offset_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_NV_Read(
    const std::string& response,
    TPM2B_MAX_NV_BUFFER* data,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_NV_Read;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string data_bytes;
  rc = Parse_TPM2B_MAX_NV_BUFFER(&buffer, data, &data_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = data_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    data_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_MAX_NV_BUFFER(&data_bytes, data, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void NV_ReadErrorCallback(const Tpm::NV_ReadResponse& callback,
                          TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_MAX_NV_BUFFER());
}

void NV_ReadResponseParser(const Tpm::NV_ReadResponse& callback,
                           AuthorizationDelegate* authorization_delegate,
                           const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(NV_ReadErrorCallback, callback);
  TPM2B_MAX_NV_BUFFER data;
  TPM_RC rc =
      Tpm::ParseResponse_NV_Read(response, &data, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, data);
}

void Tpm::NV_Read(const TPMI_RH_NV_AUTH& auth_handle,
                  const std::string& auth_handle_name,
                  const TPMI_RH_NV_INDEX& nv_index,
                  const std::string& nv_index_name,
                  const UINT16& size,
                  const UINT16& offset,
                  AuthorizationDelegate* authorization_delegate,
                  const NV_ReadResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(NV_ReadErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(NV_ReadResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_NV_Read(auth_handle, auth_handle_name, nv_index,
                                       nv_index_name, size, offset, &command,
                                       authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::NV_ReadSync(const TPMI_RH_NV_AUTH& auth_handle,
                        const std::string& auth_handle_name,
                        const TPMI_RH_NV_INDEX& nv_index,
                        const std::string& nv_index_name,
                        const UINT16& size,
                        const UINT16& offset,
                        TPM2B_MAX_NV_BUFFER* data,
                        AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_NV_Read(auth_handle, auth_handle_name, nv_index,
                                       nv_index_name, size, offset, &command,
                                       authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_NV_Read(response, data, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_NV_ReadLock(
    const TPMI_RH_NV_AUTH& auth_handle,
    const std::string& auth_handle_name,
    const TPMI_RH_NV_INDEX& nv_index,
    const std::string& nv_index_name,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_NV_ReadLock;
  bool is_command_parameter_encryption_possible = false;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_handle_bytes;
  rc = Serialize_TPMI_RH_NV_AUTH(auth_handle, &auth_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string nv_index_bytes;
  rc = Serialize_TPMI_RH_NV_INDEX(nv_index, &nv_index_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(auth_handle_name.data(), auth_handle_name.size());
  handle_section_bytes += auth_handle_bytes;
  command_size += auth_handle_bytes.size();
  hash->Update(nv_index_name.data(), nv_index_name.size());
  handle_section_bytes += nv_index_bytes;
  command_size += nv_index_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_NV_ReadLock(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_NV_ReadLock;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void NV_ReadLockErrorCallback(const Tpm::NV_ReadLockResponse& callback,
                              TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void NV_ReadLockResponseParser(const Tpm::NV_ReadLockResponse& callback,
                               AuthorizationDelegate* authorization_delegate,
                               const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(NV_ReadLockErrorCallback, callback);
  TPM_RC rc = Tpm::ParseResponse_NV_ReadLock(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::NV_ReadLock(const TPMI_RH_NV_AUTH& auth_handle,
                      const std::string& auth_handle_name,
                      const TPMI_RH_NV_INDEX& nv_index,
                      const std::string& nv_index_name,
                      AuthorizationDelegate* authorization_delegate,
                      const NV_ReadLockResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(NV_ReadLockErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(NV_ReadLockResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_NV_ReadLock(auth_handle, auth_handle_name,
                                           nv_index, nv_index_name, &command,
                                           authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::NV_ReadLockSync(const TPMI_RH_NV_AUTH& auth_handle,
                            const std::string& auth_handle_name,
                            const TPMI_RH_NV_INDEX& nv_index,
                            const std::string& nv_index_name,
                            AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_NV_ReadLock(auth_handle, auth_handle_name,
                                           nv_index, nv_index_name, &command,
                                           authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_NV_ReadLock(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_NV_ChangeAuth(
    const TPMI_RH_NV_INDEX& nv_index,
    const std::string& nv_index_name,
    const TPM2B_AUTH& new_auth,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_NV_ChangeAuth;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = false;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string nv_index_bytes;
  rc = Serialize_TPMI_RH_NV_INDEX(nv_index, &nv_index_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string new_auth_bytes;
  rc = Serialize_TPM2B_AUTH(new_auth, &new_auth_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = new_auth_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    new_auth_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(nv_index_name.data(), nv_index_name.size());
  handle_section_bytes += nv_index_bytes;
  command_size += nv_index_bytes.size();
  hash->Update(new_auth_bytes.data(), new_auth_bytes.size());
  parameter_section_bytes += new_auth_bytes;
  command_size += new_auth_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_NV_ChangeAuth(
    const std::string& response,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_NV_ChangeAuth;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  return TPM_RC_SUCCESS;
}

void NV_ChangeAuthErrorCallback(const Tpm::NV_ChangeAuthResponse& callback,
                                TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code);
}

void NV_ChangeAuthResponseParser(const Tpm::NV_ChangeAuthResponse& callback,
                                 AuthorizationDelegate* authorization_delegate,
                                 const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(NV_ChangeAuthErrorCallback, callback);
  TPM_RC rc =
      Tpm::ParseResponse_NV_ChangeAuth(response, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc);
}

void Tpm::NV_ChangeAuth(const TPMI_RH_NV_INDEX& nv_index,
                        const std::string& nv_index_name,
                        const TPM2B_AUTH& new_auth,
                        AuthorizationDelegate* authorization_delegate,
                        const NV_ChangeAuthResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(NV_ChangeAuthErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(NV_ChangeAuthResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_NV_ChangeAuth(nv_index, nv_index_name, new_auth,
                                             &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::NV_ChangeAuthSync(const TPMI_RH_NV_INDEX& nv_index,
                              const std::string& nv_index_name,
                              const TPM2B_AUTH& new_auth,
                              AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_NV_ChangeAuth(nv_index, nv_index_name, new_auth,
                                             &command, authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_NV_ChangeAuth(response, authorization_delegate);
  return rc;
}

TPM_RC Tpm::SerializeCommand_NV_Certify(
    const TPMI_DH_OBJECT& sign_handle,
    const std::string& sign_handle_name,
    const TPMI_RH_NV_AUTH& auth_handle,
    const std::string& auth_handle_name,
    const TPMI_RH_NV_INDEX& nv_index,
    const std::string& nv_index_name,
    const TPM2B_DATA& qualifying_data,
    const TPMT_SIG_SCHEME& in_scheme,
    const UINT16& size,
    const UINT16& offset,
    std::string* serialized_command,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  TPM_RC rc = TPM_RC_SUCCESS;
  TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
  UINT32 command_size = 10;  // Header size.
  std::string handle_section_bytes;
  std::string parameter_section_bytes;
  TPM_CC command_code = TPM_CC_NV_Certify;
  bool is_command_parameter_encryption_possible = true;
  bool is_response_parameter_encryption_possible = true;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string sign_handle_bytes;
  rc = Serialize_TPMI_DH_OBJECT(sign_handle, &sign_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string auth_handle_bytes;
  rc = Serialize_TPMI_RH_NV_AUTH(auth_handle, &auth_handle_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string nv_index_bytes;
  rc = Serialize_TPMI_RH_NV_INDEX(nv_index, &nv_index_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string qualifying_data_bytes;
  rc = Serialize_TPM2B_DATA(qualifying_data, &qualifying_data_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string in_scheme_bytes;
  rc = Serialize_TPMT_SIG_SCHEME(in_scheme, &in_scheme_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string size_bytes;
  rc = Serialize_UINT16(size, &size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string offset_bytes;
  rc = Serialize_UINT16(offset, &offset_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (authorization_delegate) {
    // Encrypt just the parameter data, not the size.
    std::string tmp = qualifying_data_bytes.substr(2);
    if (!authorization_delegate->EncryptCommandParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    qualifying_data_bytes.replace(2, std::string::npos, tmp);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(sign_handle_name.data(), sign_handle_name.size());
  handle_section_bytes += sign_handle_bytes;
  command_size += sign_handle_bytes.size();
  hash->Update(auth_handle_name.data(), auth_handle_name.size());
  handle_section_bytes += auth_handle_bytes;
  command_size += auth_handle_bytes.size();
  hash->Update(nv_index_name.data(), nv_index_name.size());
  handle_section_bytes += nv_index_bytes;
  command_size += nv_index_bytes.size();
  hash->Update(qualifying_data_bytes.data(), qualifying_data_bytes.size());
  parameter_section_bytes += qualifying_data_bytes;
  command_size += qualifying_data_bytes.size();
  hash->Update(in_scheme_bytes.data(), in_scheme_bytes.size());
  parameter_section_bytes += in_scheme_bytes;
  command_size += in_scheme_bytes.size();
  hash->Update(size_bytes.data(), size_bytes.size());
  parameter_section_bytes += size_bytes;
  command_size += size_bytes.size();
  hash->Update(offset_bytes.data(), offset_bytes.size());
  parameter_section_bytes += offset_bytes;
  command_size += offset_bytes.size();
  std::string command_hash(32, 0);
  hash->Finish(string_as_array(&command_hash), command_hash.size());
  std::string authorization_section_bytes;
  std::string authorization_size_bytes;
  if (authorization_delegate) {
    if (!authorization_delegate->GetCommandAuthorization(
            command_hash, is_command_parameter_encryption_possible,
            is_response_parameter_encryption_possible,
            &authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
    if (!authorization_section_bytes.empty()) {
      tag = TPM_ST_SESSIONS;
      std::string tmp;
      rc = Serialize_UINT32(authorization_section_bytes.size(),
                            &authorization_size_bytes);
      if (rc != TPM_RC_SUCCESS) {
        return rc;
      }
      command_size +=
          authorization_size_bytes.size() + authorization_section_bytes.size();
    }
  }
  std::string tag_bytes;
  rc = Serialize_TPMI_ST_COMMAND_TAG(tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string command_size_bytes;
  rc = Serialize_UINT32(command_size, &command_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  *serialized_command = tag_bytes + command_size_bytes + command_code_bytes +
                        handle_section_bytes + authorization_size_bytes +
                        authorization_section_bytes + parameter_section_bytes;
  CHECK(serialized_command->size() == command_size) << "Command size mismatch!";
  VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(),
                                            serialized_command->size());
  return TPM_RC_SUCCESS;
}

TPM_RC Tpm::ParseResponse_NV_Certify(
    const std::string& response,
    TPM2B_ATTEST* certify_info,
    TPMT_SIGNATURE* signature,
    AuthorizationDelegate* authorization_delegate) {
  VLOG(3) << __func__;
  VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size());
  TPM_RC rc = TPM_RC_SUCCESS;
  std::string buffer(response);
  TPM_ST tag;
  std::string tag_bytes;
  rc = Parse_TPM_ST(&buffer, &tag, &tag_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  UINT32 response_size;
  std::string response_size_bytes;
  rc = Parse_UINT32(&buffer, &response_size, &response_size_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  TPM_RC response_code;
  std::string response_code_bytes;
  rc = Parse_TPM_RC(&buffer, &response_code, &response_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (response_size != response.size()) {
    return TPM_RC_SIZE;
  }
  if (response_code != TPM_RC_SUCCESS) {
    return response_code;
  }
  TPM_CC command_code = TPM_CC_NV_Certify;
  std::string command_code_bytes;
  rc = Serialize_TPM_CC(command_code, &command_code_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string authorization_section_bytes;
  if (tag == TPM_ST_SESSIONS) {
    UINT32 parameter_section_size = buffer.size();
    rc = Parse_UINT32(&buffer, &parameter_section_size, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
    if (parameter_section_size > buffer.size()) {
      return TPM_RC_INSUFFICIENT;
    }
    authorization_section_bytes = buffer.substr(parameter_section_size);
    // Keep the parameter section in |buffer|.
    buffer.erase(parameter_section_size);
  }
  std::unique_ptr<crypto::SecureHash> hash(
      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  hash->Update(response_code_bytes.data(), response_code_bytes.size());
  hash->Update(command_code_bytes.data(), command_code_bytes.size());
  hash->Update(buffer.data(), buffer.size());
  std::string response_hash(32, 0);
  hash->Finish(string_as_array(&response_hash), response_hash.size());
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    if (!authorization_delegate->CheckResponseAuthorization(
            response_hash, authorization_section_bytes)) {
      return TRUNKS_RC_AUTHORIZATION_FAILED;
    }
  }
  std::string certify_info_bytes;
  rc = Parse_TPM2B_ATTEST(&buffer, certify_info, &certify_info_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string signature_bytes;
  rc = Parse_TPMT_SIGNATURE(&buffer, signature, &signature_bytes);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  if (tag == TPM_ST_SESSIONS) {
    CHECK(authorization_delegate) << "Authorization delegate missing!";
    // Decrypt just the parameter data, not the size.
    std::string tmp = certify_info_bytes.substr(2);
    if (!authorization_delegate->DecryptResponseParameter(&tmp)) {
      return TRUNKS_RC_ENCRYPTION_FAILED;
    }
    certify_info_bytes.replace(2, std::string::npos, tmp);
    rc = Parse_TPM2B_ATTEST(&certify_info_bytes, certify_info, nullptr);
    if (rc != TPM_RC_SUCCESS) {
      return rc;
    }
  }
  return TPM_RC_SUCCESS;
}

void NV_CertifyErrorCallback(const Tpm::NV_CertifyResponse& callback,
                             TPM_RC response_code) {
  VLOG(1) << __func__;
  callback.Run(response_code, TPM2B_ATTEST(), TPMT_SIGNATURE());
}

void NV_CertifyResponseParser(const Tpm::NV_CertifyResponse& callback,
                              AuthorizationDelegate* authorization_delegate,
                              const std::string& response) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(NV_CertifyErrorCallback, callback);
  TPM2B_ATTEST certify_info;
  TPMT_SIGNATURE signature;
  TPM_RC rc = Tpm::ParseResponse_NV_Certify(response, &certify_info, &signature,
                                            authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  callback.Run(rc, certify_info, signature);
}

void Tpm::NV_Certify(const TPMI_DH_OBJECT& sign_handle,
                     const std::string& sign_handle_name,
                     const TPMI_RH_NV_AUTH& auth_handle,
                     const std::string& auth_handle_name,
                     const TPMI_RH_NV_INDEX& nv_index,
                     const std::string& nv_index_name,
                     const TPM2B_DATA& qualifying_data,
                     const TPMT_SIG_SCHEME& in_scheme,
                     const UINT16& size,
                     const UINT16& offset,
                     AuthorizationDelegate* authorization_delegate,
                     const NV_CertifyResponse& callback) {
  VLOG(1) << __func__;
  base::Callback<void(TPM_RC)> error_reporter =
      base::Bind(NV_CertifyErrorCallback, callback);
  base::Callback<void(const std::string&)> parser =
      base::Bind(NV_CertifyResponseParser, callback, authorization_delegate);
  std::string command;
  TPM_RC rc = SerializeCommand_NV_Certify(
      sign_handle, sign_handle_name, auth_handle, auth_handle_name, nv_index,
      nv_index_name, qualifying_data, in_scheme, size, offset, &command,
      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    error_reporter.Run(rc);
    return;
  }
  transceiver_->SendCommand(command, parser);
}

TPM_RC Tpm::NV_CertifySync(const TPMI_DH_OBJECT& sign_handle,
                           const std::string& sign_handle_name,
                           const TPMI_RH_NV_AUTH& auth_handle,
                           const std::string& auth_handle_name,
                           const TPMI_RH_NV_INDEX& nv_index,
                           const std::string& nv_index_name,
                           const TPM2B_DATA& qualifying_data,
                           const TPMT_SIG_SCHEME& in_scheme,
                           const UINT16& size,
                           const UINT16& offset,
                           TPM2B_ATTEST* certify_info,
                           TPMT_SIGNATURE* signature,
                           AuthorizationDelegate* authorization_delegate) {
  VLOG(1) << __func__;
  std::string command;
  TPM_RC rc = SerializeCommand_NV_Certify(
      sign_handle, sign_handle_name, auth_handle, auth_handle_name, nv_index,
      nv_index_name, qualifying_data, in_scheme, size, offset, &command,
      authorization_delegate);
  if (rc != TPM_RC_SUCCESS) {
    return rc;
  }
  std::string response = transceiver_->SendCommandAndWait(command);
  rc = ParseResponse_NV_Certify(response, certify_info, signature,
                                authorization_delegate);
  return rc;
}

}  // namespace trunks