Home | History | Annotate | Download | only in trunks
      1 //
      2 // Copyright (C) 2015 The Android Open Source Project
      3 //
      4 // Licensed under the Apache License, Version 2.0 (the "License");
      5 // you may not use this file except in compliance with the License.
      6 // You may obtain a copy of the License at
      7 //
      8 //      http://www.apache.org/licenses/LICENSE-2.0
      9 //
     10 // Unless required by applicable law or agreed to in writing, software
     11 // distributed under the License is distributed on an "AS IS" BASIS,
     12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 // See the License for the specific language governing permissions and
     14 // limitations under the License.
     15 //
     16 
     17 #include "trunks/resource_manager.h"
     18 
     19 #include <algorithm>
     20 #include <map>
     21 #include <set>
     22 #include <string>
     23 #include <vector>
     24 
     25 #include <base/callback.h>
     26 
     27 #include "trunks/error_codes.h"
     28 
     29 namespace {
     30 
     31 const int kMaxCommandAttempts = 3;
     32 const size_t kMinimumAuthorizationSize = 9;
     33 const size_t kMessageHeaderSize = 10;
     34 const trunks::TPM_HANDLE kMaxVirtualHandle =
     35     (trunks::HR_TRANSIENT + trunks::HR_HANDLE_MASK);
     36 
     37 class ScopedBool {
     38  public:
     39   ScopedBool() : target_(nullptr) {}
     40   ~ScopedBool() {
     41     if (target_) {
     42       *target_ = false;
     43     }
     44   }
     45   void Enable(bool* target) {
     46     target_ = target;
     47     *target_ = true;
     48   }
     49  private:
     50   bool* target_;
     51 };
     52 
     53 }  // namespace
     54 
     55 namespace trunks {
     56 
     57 ResourceManager::ResourceManager(const TrunksFactory& factory,
     58                                  CommandTransceiver* next_transceiver)
     59     : factory_(factory),
     60       next_transceiver_(next_transceiver) {}
     61 
     62 ResourceManager::~ResourceManager() {}
     63 
     64 void ResourceManager::Initialize() {
     65   TPM_RC result = factory_.GetTpm()->StartupSync(TPM_SU_CLEAR, nullptr);
     66   // Ignore TPM_RC_INITIALIZE, that means it was already started.
     67   CHECK(result == TPM_RC_SUCCESS || result == TPM_RC_INITIALIZE)
     68       << "TPM startup failure: " << GetErrorString(result);
     69   result = factory_.GetTpm()->SelfTestSync(YES /* Full test. */, nullptr);
     70   CHECK_EQ(result, TPM_RC_SUCCESS) << "TPM self-test failure: "
     71                                    << GetErrorString(result);
     72   // Full control of the TPM is assumed and required. Existing transient object
     73   // and session handles are mercilessly flushed.
     74   for (UINT32 handle_type : {HR_TRANSIENT,
     75                              HR_HMAC_SESSION,
     76                              HR_POLICY_SESSION}) {
     77     TPMI_YES_NO more_data = YES;
     78     TPMS_CAPABILITY_DATA data;
     79     UINT32 handle_range = handle_type;
     80     while (more_data) {
     81       result = factory_.GetTpm()->GetCapabilitySync(TPM_CAP_HANDLES,
     82                                                     handle_range,
     83                                                     MAX_CAP_HANDLES,
     84                                                     &more_data,
     85                                                     &data,
     86                                                     nullptr);
     87       if (result != TPM_RC_SUCCESS) {
     88         LOG(WARNING) << "Failed to query existing handles: "
     89                      << GetErrorString(result);
     90         break;
     91       }
     92       const TPML_HANDLE& handle_list = data.data.handles;
     93       for (UINT32 i = 0; i < handle_list.count; ++i) {
     94         factory_.GetTpm()->FlushContextSync(handle_list.handle[i], nullptr);
     95       }
     96       if (more_data) {
     97         // Adjust the range to be greater than the most recent handle so on the
     98         // next query we'll start where we left off.
     99         handle_range = handle_list.handle[handle_list.count-1];
    100       }
    101     }
    102   }
    103 }
    104 
    105 void ResourceManager::SendCommand(
    106     const std::string& command,
    107     const ResponseCallback& callback) {
    108   callback.Run(SendCommandAndWait(command));
    109 }
    110 
    111 std::string ResourceManager::SendCommandAndWait(const std::string& command) {
    112   // Sanitize the |command|. If this succeeds consistency of the command header
    113   // and the size of all other sections can be assumed.
    114   MessageInfo command_info;
    115   TPM_RC result = ParseCommand(command, &command_info);
    116   if (result != TPM_RC_SUCCESS) {
    117     return CreateErrorResponse(result);
    118   }
    119   // A special case for FlushContext. It requires special handling because it
    120   // has a handle as a parameter and because we need to cleanup if it succeeds.
    121   if (command_info.code == TPM_CC_FlushContext) {
    122     return ProcessFlushContext(command, command_info);
    123   }
    124   // Process all the input handles, e.g. map virtual handles.
    125   std::vector<TPM_HANDLE> updated_handles;
    126   for (auto handle : command_info.handles) {
    127     TPM_HANDLE tpm_handle;
    128     result = ProcessInputHandle(command_info, handle, &tpm_handle);
    129     if (result != TPM_RC_SUCCESS) {
    130       return CreateErrorResponse(result);
    131     }
    132     updated_handles.push_back(tpm_handle);
    133   }
    134   std::string updated_command = ReplaceHandles(command, updated_handles);
    135   // Make sure all the required sessions are loaded.
    136   for (auto handle : command_info.session_handles) {
    137     result = EnsureSessionIsLoaded(command_info, handle);
    138     if (result != TPM_RC_SUCCESS) {
    139       return CreateErrorResponse(result);
    140     }
    141   }
    142   // On a ContextLoad we may need to map virtualized context data.
    143   if (command_info.code == TPM_CC_ContextLoad) {
    144     std::string actual_load_data = GetActualContextFromExternalContext(
    145         command_info.parameter_data);
    146     // Check equality to see if replacement is necessary, and check size to see
    147     // if the command looks like we expect (the idea is to avoid 'fixing'
    148     // malformed commands). Note: updated_command.size() is guaranteed to be >=
    149     // kMessageHeaderSize based on the sanitization in ParseCommand.
    150     if (actual_load_data != command_info.parameter_data &&
    151         actual_load_data.size() ==
    152             updated_command.size() - kMessageHeaderSize) {
    153       // Replace the parameter section of the command with |actual_load_data|.
    154       VLOG(1) << "REPLACE_EXTERNAL_CONTEXT";
    155       updated_command.replace(kMessageHeaderSize, std::string::npos,
    156                               actual_load_data);
    157     }
    158   }
    159   // Send the |updated_command| to the next layer. Attempt to fix any actionable
    160   // warnings for up to kMaxCommandAttempts.
    161   std::string response;
    162   MessageInfo response_info;
    163   int attempts = 0;
    164   while (attempts++ < kMaxCommandAttempts) {
    165     response = next_transceiver_->SendCommandAndWait(updated_command);
    166     result = ParseResponse(command_info, response, &response_info);
    167     if (result != TPM_RC_SUCCESS) {
    168       return CreateErrorResponse(result);
    169     }
    170     if (!FixWarnings(command_info, response_info.code)) {
    171       // No actionable warnings were handled.
    172       break;
    173     }
    174   }
    175   if (response_info.code == TPM_RC_SUCCESS) {
    176     if (response_info.session_continued.size() !=
    177         command_info.session_handles.size()) {
    178       LOG(WARNING) << "Session count mismatch!";
    179     }
    180     // Cleanup any sessions that were not continued.
    181     for (size_t i = 0; i < command_info.session_handles.size(); ++i) {
    182       if (i < response_info.session_continued.size() &&
    183           !response_info.session_continued[i]) {
    184         CleanupFlushedHandle(command_info.session_handles[i]);
    185       }
    186     }
    187     // On a successful context save we need to cache the context data in case it
    188     // needs to be virtualized later.
    189     if (command_info.code == TPM_CC_ContextSave) {
    190       ProcessExternalContextSave(command_info, response_info);
    191     }
    192     // Process all the output handles, which is loosely the inverse of the input
    193     // handle processing. E.g. virtualize handles.
    194     std::vector<TPM_HANDLE> virtual_handles;
    195     for (auto handle : response_info.handles) {
    196       virtual_handles.push_back(ProcessOutputHandle(handle));
    197     }
    198     response = ReplaceHandles(response, virtual_handles);
    199   }
    200   return response;
    201 }
    202 
    203 bool ResourceManager::ChooseSessionToEvict(
    204     const std::vector<TPM_HANDLE>& sessions_to_retain,
    205     TPM_HANDLE* session_to_evict) {
    206   // Build a list of candidates by excluding |sessions_to_retain|.
    207   std::vector<TPM_HANDLE> candidates;
    208   for (auto& item : session_handles_) {
    209     HandleInfo& info = item.second;
    210     if (info.is_loaded &&
    211         std::find(sessions_to_retain.begin(),
    212                   sessions_to_retain.end(),
    213                   info.tpm_handle) == sessions_to_retain.end()) {
    214       candidates.push_back(item.first);
    215     }
    216   }
    217   if (candidates.empty()) {
    218     LOG(WARNING) << "No sessions to evict.";
    219     return false;
    220   }
    221   // Choose the candidate with the earliest |time_of_last_use|.
    222   auto oldest_iter = std::min_element(
    223       candidates.begin(), candidates.end(),
    224       [this](TPM_HANDLE a, TPM_HANDLE b) {
    225         return (session_handles_[a].time_of_last_use <
    226                 session_handles_[b].time_of_last_use);
    227       });
    228   *session_to_evict = *oldest_iter;
    229   return true;
    230 }
    231 
    232 void ResourceManager::CleanupFlushedHandle(TPM_HANDLE flushed_handle) {
    233   if (IsObjectHandle(flushed_handle)) {
    234     // For transient object handles, remove both the actual and virtual handles.
    235     if (virtual_object_handles_.count(flushed_handle) > 0) {
    236       tpm_object_handles_.erase(
    237           virtual_object_handles_[flushed_handle].tpm_handle);
    238       virtual_object_handles_.erase(flushed_handle);
    239     }
    240   } else if (IsSessionHandle(flushed_handle)) {
    241     auto iter = session_handles_.find(flushed_handle);
    242     if (iter == session_handles_.end()) {
    243       return;
    244     }
    245     // For session handles, remove the handle and any associated context data.
    246     HandleInfo& info = iter->second;
    247     if (!info.is_loaded) {
    248       std::string actual_context_data;
    249       Serialize_TPMS_CONTEXT(info.context, &actual_context_data);
    250       if (actual_context_to_external_.count(actual_context_data) > 0) {
    251         external_context_to_actual_.erase(
    252             actual_context_to_external_[actual_context_data]);
    253         actual_context_to_external_.erase(actual_context_data);
    254       }
    255     }
    256     session_handles_.erase(flushed_handle);
    257     VLOG(1) << "CLEANUP_SESSION: " << std::hex << flushed_handle;
    258   }
    259 }
    260 
    261 TPM_HANDLE ResourceManager::CreateVirtualHandle() {
    262   TPM_HANDLE handle;
    263   do {
    264     handle = next_virtual_handle_;
    265     if (next_virtual_handle_ == kMaxVirtualHandle) {
    266       next_virtual_handle_ = TRANSIENT_FIRST;
    267     } else {
    268       ++next_virtual_handle_;
    269     }
    270   } while (virtual_object_handles_.count(handle) > 0);
    271   return handle;
    272 }
    273 
    274 TPM_RC ResourceManager::EnsureSessionIsLoaded(const MessageInfo& command_info,
    275                                               TPM_HANDLE session_handle) {
    276   // A password authorization can skip all this.
    277   if (session_handle == TPM_RS_PW) {
    278     return TPM_RC_SUCCESS;
    279   }
    280   auto handle_iter = session_handles_.find(session_handle);
    281   if (handle_iter == session_handles_.end()) {
    282     return MakeError(TPM_RC_HANDLE, FROM_HERE);
    283   }
    284   HandleInfo& handle_info = handle_iter->second;
    285   if (!handle_info.is_loaded) {
    286     TPM_RC result = LoadContext(command_info, &handle_info);
    287     if (result != TPM_RC_SUCCESS) {
    288       return result;
    289     }
    290     VLOG(1) << "RELOAD_SESSION: " << std::hex << session_handle;
    291   }
    292   handle_info.time_of_last_use = base::TimeTicks::Now();
    293   return TPM_RC_SUCCESS;
    294 }
    295 
    296 void ResourceManager::EvictObjects(const MessageInfo& command_info) {
    297   for (auto& item : virtual_object_handles_) {
    298     HandleInfo& info = item.second;
    299     if (!info.is_loaded ||
    300         std::find(command_info.handles.begin(),
    301                   command_info.handles.end(),
    302                   item.first) != command_info.handles.end()) {
    303       continue;
    304     }
    305     TPM_RC result = SaveContext(command_info, &info);
    306     if (result != TPM_RC_SUCCESS) {
    307       LOG(WARNING) << "Failed to save transient object: "
    308                    << GetErrorString(result);
    309       continue;
    310     }
    311     result = factory_.GetTpm()->FlushContextSync(info.tpm_handle, nullptr);
    312     if (result != TPM_RC_SUCCESS) {
    313       LOG(WARNING) << "Failed to evict transient object: "
    314                    << GetErrorString(result);
    315       continue;
    316     }
    317     tpm_object_handles_.erase(info.tpm_handle);
    318     VLOG(1) << "EVICT_OBJECT: " << std::hex << info.tpm_handle;
    319   }
    320 }
    321 
    322 void ResourceManager::EvictSession(const MessageInfo& command_info) {
    323   TPM_HANDLE session_to_evict;
    324   if (!ChooseSessionToEvict(command_info.session_handles, &session_to_evict)) {
    325     return;
    326   }
    327   HandleInfo& info = session_handles_[session_to_evict];
    328   TPM_RC result = SaveContext(command_info, &info);
    329   if (result != TPM_RC_SUCCESS) {
    330     LOG(WARNING) << "Failed to evict session: " << GetErrorString(result);
    331   }
    332   VLOG(1) << "EVICT_SESSION: " << std::hex << session_to_evict;
    333 }
    334 
    335 std::vector<TPM_HANDLE> ResourceManager::ExtractHandlesFromBuffer(
    336     size_t number_of_handles,
    337     std::string* buffer) {
    338   std::vector<TPM_HANDLE> handles(number_of_handles);
    339   for (size_t i = 0; i < number_of_handles; ++i) {
    340     TPM_HANDLE handle;
    341     if (TPM_RC_SUCCESS == Parse_TPM_HANDLE(buffer, &handle, nullptr)) {
    342       handles[i] = handle;
    343     }
    344   }
    345   return handles;
    346 }
    347 
    348 void ResourceManager::FixContextGap(const MessageInfo& command_info) {
    349   std::vector<TPM_HANDLE> sessions_to_ungap;
    350   for (const auto& item : session_handles_) {
    351     const HandleInfo& info = item.second;
    352     if (!info.is_loaded) {
    353       sessions_to_ungap.push_back(item.first);
    354     }
    355   }
    356   // Sort by |time_of_create|.
    357   std::sort(sessions_to_ungap.begin(), sessions_to_ungap.end(),
    358             [this](TPM_HANDLE a, TPM_HANDLE b) {
    359               return (session_handles_[a].time_of_create <
    360                       session_handles_[b].time_of_create);
    361             });
    362   for (auto handle : sessions_to_ungap) {
    363     HandleInfo& info = session_handles_[handle];
    364     // Loading and re-saving allows the TPM to assign a new context counter.
    365     std::string old_context_blob;
    366     Serialize_TPMS_CONTEXT(info.context, &old_context_blob);
    367     TPM_RC result = LoadContext(command_info, &info);
    368     if (result != TPM_RC_SUCCESS) {
    369       LOG(WARNING) << "Failed to un-gap session (load): "
    370                    << GetErrorString(result);
    371       continue;
    372     }
    373     result = SaveContext(command_info, &info);
    374     if (result != TPM_RC_SUCCESS) {
    375       LOG(WARNING) << "Failed to un-gap session (save): "
    376                    << GetErrorString(result);
    377       continue;
    378     }
    379     // If this context is one that we're tracking for external use, update it.
    380     auto iter = actual_context_to_external_.find(old_context_blob);
    381     if (iter == actual_context_to_external_.end()) {
    382       continue;
    383     }
    384     std::string new_context_blob;
    385     Serialize_TPMS_CONTEXT(info.context, &new_context_blob);
    386     const std::string& external_context_blob = iter->second;
    387     actual_context_to_external_[new_context_blob] = external_context_blob;
    388     external_context_to_actual_[external_context_blob] = new_context_blob;
    389     actual_context_to_external_.erase(old_context_blob);
    390   }
    391 }
    392 
    393 bool ResourceManager::FixWarnings(const MessageInfo& command_info,
    394                                   TPM_RC result) {
    395   if ((result & RC_WARN) == 0) {
    396     return false;
    397   }
    398   // This method can be called anytime without tracking whether the current
    399   // operation is already an attempt to fix a warning. All re-entrance issues
    400   // are dealt with here using the following rule: Never attempt to fix the same
    401   // warning twice.
    402   ScopedBool scoped_bool;
    403   if (!fixing_warnings_) {
    404     scoped_bool.Enable(&fixing_warnings_);
    405     warnings_already_seen_.clear();
    406   } else if (warnings_already_seen_.count(result) > 0) {
    407     return false;
    408   }
    409   warnings_already_seen_.insert(result);
    410   switch (result) {
    411     case TPM_RC_CONTEXT_GAP:
    412       FixContextGap(command_info);
    413       return true;
    414     case TPM_RC_OBJECT_MEMORY:
    415     case TPM_RC_OBJECT_HANDLES:
    416       EvictObjects(command_info);
    417       return true;
    418     case TPM_RC_SESSION_MEMORY:
    419       EvictSession(command_info);
    420       return true;
    421     case TPM_RC_MEMORY:
    422       EvictObjects(command_info);
    423       EvictSession(command_info);
    424       return true;
    425     case TPM_RC_SESSION_HANDLES:
    426       FlushSession(command_info);
    427       return true;
    428   }
    429   return false;
    430 }
    431 
    432 void ResourceManager::FlushSession(const MessageInfo& command_info) {
    433   TPM_HANDLE session_to_flush;
    434   LOG(WARNING) << "Resource manager needs to flush a session.";
    435   if (!ChooseSessionToEvict(command_info.session_handles, &session_to_flush)) {
    436     return;
    437   }
    438   TPM_RC result = factory_.GetTpm()->FlushContextSync(session_to_flush,
    439                                                       nullptr);
    440   if (result != TPM_RC_SUCCESS) {
    441     LOG(WARNING) << "Failed to flush session: " << GetErrorString(result);
    442     return;
    443   }
    444   CleanupFlushedHandle(session_to_flush);
    445 }
    446 
    447 std::string ResourceManager::GetActualContextFromExternalContext(
    448     const std::string& external_context) {
    449   auto iter = external_context_to_actual_.find(external_context);
    450   if (iter == external_context_to_actual_.end()) {
    451     return external_context;
    452   }
    453   return iter->second;
    454 }
    455 
    456 bool ResourceManager::IsObjectHandle(TPM_HANDLE handle) const {
    457   return ((handle & HR_RANGE_MASK) == HR_TRANSIENT);
    458 }
    459 
    460 bool ResourceManager::IsSessionHandle(TPM_HANDLE handle) const {
    461   return ((handle & HR_RANGE_MASK) == HR_HMAC_SESSION ||
    462           (handle & HR_RANGE_MASK) == HR_POLICY_SESSION);
    463 }
    464 
    465 TPM_RC ResourceManager::LoadContext(const MessageInfo& command_info,
    466                                     HandleInfo* handle_info) {
    467   CHECK(!handle_info->is_loaded);
    468   TPM_RC result = TPM_RC_SUCCESS;
    469   int attempts = 0;
    470   while (attempts++ < kMaxCommandAttempts) {
    471     result = factory_.GetTpm()->ContextLoadSync(handle_info->context,
    472                                                 &handle_info->tpm_handle,
    473                                                 nullptr);
    474     if (!FixWarnings(command_info, result)) {
    475       break;
    476     }
    477   }
    478   if (result != TPM_RC_SUCCESS) {
    479     LOG(ERROR) << __func__ << ": Failed to load context: "
    480                << GetErrorString(result);
    481     return result;
    482   }
    483   handle_info->is_loaded = true;
    484   return result;
    485 }
    486 
    487 TPM_RC ResourceManager::MakeError(TPM_RC tpm_error,
    488                                   const ::tracked_objects::Location& location) {
    489   LOG(ERROR) << "ResourceManager::" << location.function_name() << ":"
    490              << location.line_number() << ": " << GetErrorString(tpm_error);
    491   return tpm_error + kResourceManagerTpmErrorBase;
    492 }
    493 
    494 TPM_RC ResourceManager::ParseCommand(const std::string& command,
    495                                      MessageInfo* command_info) {
    496   CHECK(command_info);
    497   std::string buffer = command;
    498   TPM_ST tag;
    499   TPM_RC result = Parse_TPM_ST(&buffer, &tag, nullptr);
    500   if (result != TPM_RC_SUCCESS) {
    501     return MakeError(result, FROM_HERE);
    502   }
    503   if (tag != TPM_ST_SESSIONS && tag != TPM_ST_NO_SESSIONS) {
    504     return MakeError(TPM_RC_TAG, FROM_HERE);
    505   }
    506   command_info->has_sessions = (tag == TPM_ST_SESSIONS);
    507 
    508   UINT32 size = 0;
    509   result = Parse_UINT32(&buffer, &size, nullptr);
    510   if (result != TPM_RC_SUCCESS) {
    511     return MakeError(result, FROM_HERE);
    512   }
    513   if (size != command.size()) {
    514     return MakeError(TPM_RC_SIZE, FROM_HERE);
    515   }
    516 
    517   result = Parse_TPM_CC(&buffer, &command_info->code, nullptr);
    518   if (result != TPM_RC_SUCCESS) {
    519     return MakeError(result, FROM_HERE);
    520   }
    521   if (command_info->code < TPM_CC_FIRST || command_info->code > TPM_CC_LAST) {
    522     return MakeError(TPM_RC_COMMAND_CODE, FROM_HERE);
    523   }
    524 
    525   size_t number_of_handles = GetNumberOfRequestHandles(command_info->code);
    526   command_info->handles = ExtractHandlesFromBuffer(number_of_handles, &buffer);
    527   if (number_of_handles != command_info->handles.size()) {
    528     return MakeError(TPM_RC_SIZE, FROM_HERE);
    529   }
    530   if (command_info->has_sessions) {
    531     // Sessions exist, so we're expecting a valid authorization size value.
    532     UINT32 authorization_size = 0;
    533     result = Parse_UINT32(&buffer, &authorization_size, nullptr);
    534     if (result != TPM_RC_SUCCESS) {
    535       return MakeError(result, FROM_HERE);
    536     }
    537     if (buffer.size() < authorization_size ||
    538         authorization_size < kMinimumAuthorizationSize) {
    539       return MakeError(TPM_RC_SIZE, FROM_HERE);
    540     }
    541     // Move out the parameter bytes, leaving only the authorization section.
    542     command_info->parameter_data = buffer.substr(authorization_size);
    543     buffer.erase(authorization_size);
    544     // Parse as many authorization sessions as there are in the section.
    545     while (!buffer.empty()) {
    546       TPM_HANDLE handle;
    547       result = Parse_TPM_HANDLE(&buffer, &handle, nullptr);
    548       if (result != TPM_RC_SUCCESS) {
    549         return MakeError(result, FROM_HERE);
    550       }
    551       if (handle != TPM_RS_PW && session_handles_.count(handle) == 0) {
    552         return MakeError(TPM_RC_HANDLE, FROM_HERE);
    553       }
    554       TPM2B_NONCE nonce;
    555       result = Parse_TPM2B_NONCE(&buffer, &nonce, nullptr);
    556       if (result != TPM_RC_SUCCESS) {
    557         return MakeError(result, FROM_HERE);
    558       }
    559       BYTE attributes;
    560       result = Parse_BYTE(&buffer, &attributes, nullptr);
    561       if (result != TPM_RC_SUCCESS) {
    562         return MakeError(result, FROM_HERE);
    563       }
    564       TPM2B_DIGEST authorization;
    565       result = Parse_TPM2B_DIGEST(&buffer, &authorization, nullptr);
    566       if (result != TPM_RC_SUCCESS) {
    567         return MakeError(result, FROM_HERE);
    568       }
    569       command_info->session_handles.push_back(handle);
    570       command_info->session_continued.push_back((attributes & 1) == 1);
    571     }
    572   } else {
    573     // No sessions, so all remaining data is parameter data.
    574     command_info->parameter_data = buffer;
    575   }
    576   return TPM_RC_SUCCESS;
    577 }
    578 
    579 TPM_RC ResourceManager::ParseResponse(const MessageInfo& command_info,
    580                                       const std::string& response,
    581                                       MessageInfo* response_info) {
    582   CHECK(response_info);
    583   std::string buffer = response;
    584   TPM_ST tag;
    585   TPM_RC result = Parse_TPM_ST(&buffer, &tag, nullptr);
    586   if (result != TPM_RC_SUCCESS) {
    587     return MakeError(result, FROM_HERE);
    588   }
    589   if (tag != TPM_ST_SESSIONS && tag != TPM_ST_NO_SESSIONS) {
    590     return MakeError(TPM_RC_TAG, FROM_HERE);
    591   }
    592   response_info->has_sessions = (tag == TPM_ST_SESSIONS);
    593 
    594   UINT32 size = 0;
    595   result = Parse_UINT32(&buffer, &size, nullptr);
    596   if (result != TPM_RC_SUCCESS) {
    597     return MakeError(result, FROM_HERE);
    598   }
    599   if (size != response.size()) {
    600     return MakeError(TPM_RC_SIZE, FROM_HERE);
    601   }
    602 
    603   result = Parse_TPM_RC(&buffer, &response_info->code, nullptr);
    604   if (result != TPM_RC_SUCCESS) {
    605     return MakeError(result, FROM_HERE);
    606   }
    607 
    608   size_t number_of_handles = GetNumberOfResponseHandles(command_info.code);
    609   response_info->handles = ExtractHandlesFromBuffer(number_of_handles, &buffer);
    610   if (number_of_handles != response_info->handles.size()) {
    611     return MakeError(TPM_RC_SIZE, FROM_HERE);
    612   }
    613   if (response_info->has_sessions) {
    614     // Sessions exist, so we're expecting a valid parameter size value.
    615     UINT32 parameter_size = 0;
    616     result = Parse_UINT32(&buffer, &parameter_size, nullptr);
    617     if (result != TPM_RC_SUCCESS) {
    618       return MakeError(result, FROM_HERE);
    619     }
    620     if (buffer.size() < parameter_size) {
    621       return MakeError(TPM_RC_SIZE, FROM_HERE);
    622     }
    623     // Move out the parameter bytes, leaving only the authorization section.
    624     response_info->parameter_data = buffer.substr(0, parameter_size);
    625     buffer.erase(0, parameter_size);
    626     // Parse as many authorization sessions as there are in the section.
    627     while (!buffer.empty()) {
    628       TPM2B_NONCE nonce;
    629       result = Parse_TPM2B_NONCE(&buffer, &nonce, nullptr);
    630       if (result != TPM_RC_SUCCESS) {
    631         return MakeError(result, FROM_HERE);
    632       }
    633       BYTE attributes;
    634       result = Parse_BYTE(&buffer, &attributes, nullptr);
    635       if (result != TPM_RC_SUCCESS) {
    636         return MakeError(result, FROM_HERE);
    637       }
    638       TPM2B_DIGEST acknowledgement;
    639       result = Parse_TPM2B_DIGEST(&buffer, &acknowledgement, nullptr);
    640       if (result != TPM_RC_SUCCESS) {
    641         return MakeError(result, FROM_HERE);
    642       }
    643       response_info->session_continued.push_back((attributes & 1) == 1);
    644     }
    645   } else {
    646     // No sessions, so all remaining data is parameter data.
    647     response_info->parameter_data = buffer;
    648   }
    649   return TPM_RC_SUCCESS;
    650 }
    651 
    652 void ResourceManager::ProcessExternalContextSave(
    653     const MessageInfo& command_info,
    654     const MessageInfo& response_info) {
    655   CHECK_EQ(command_info.code, TPM_CC_ContextSave);
    656   if (command_info.handles.size() != 1) {
    657     LOG(WARNING) << "Invalid context save command.";
    658     return;
    659   }
    660   // We know command_info.handles[0] is valid because this is validated when the
    661   // command is parsed.
    662   TPM_HANDLE saved_handle = command_info.handles[0];
    663   // Only track external context data for session handles.
    664   if (!IsSessionHandle(saved_handle)) {
    665     return;
    666   }
    667   std::string mutable_parameter = response_info.parameter_data;
    668   TPMS_CONTEXT context;
    669   std::string context_blob;
    670   TPM_RC result = Parse_TPMS_CONTEXT(&mutable_parameter,
    671                                      &context,
    672                                      &context_blob);
    673   if (result != TPM_RC_SUCCESS) {
    674     LOG(WARNING) << "Invalid context save response: " << GetErrorString(result);
    675     return;
    676   }
    677   auto iter = session_handles_.find(saved_handle);
    678   if (iter != session_handles_.end()) {
    679     iter->second.is_loaded = false;
    680     iter->second.context = context;
    681   } else {
    682     // Unknown handle? Not anymore.
    683     LOG(WARNING) << "Context for unknown handle.";
    684     HandleInfo new_handle_info;
    685     new_handle_info.Init(saved_handle);
    686     new_handle_info.is_loaded = false;
    687     new_handle_info.context = context;
    688     session_handles_[saved_handle] = new_handle_info;
    689   }
    690   // Use the original context data as the 'external' context data. If this gets
    691   // virtualized, only the 'actual' context data will change.
    692   external_context_to_actual_[context_blob] = context_blob;
    693   actual_context_to_external_[context_blob] = context_blob;
    694 }
    695 
    696 std::string ResourceManager::ProcessFlushContext(
    697     const std::string& command,
    698     const MessageInfo& command_info) {
    699   std::string buffer = command_info.parameter_data;
    700   // There must be exactly one handle in the parameters section.
    701   std::vector<TPM_HANDLE> handles = ExtractHandlesFromBuffer(1, &buffer);
    702   if (handles.size() != 1) {
    703     return CreateErrorResponse(MakeError(TPM_RC_SIZE, FROM_HERE));
    704   }
    705   TPM_HANDLE handle = handles[0];
    706   TPM_HANDLE actual_handle = handle;
    707   if (IsObjectHandle(handle)) {
    708     auto iter = virtual_object_handles_.find(handle);
    709     if (iter == virtual_object_handles_.end()) {
    710       return CreateErrorResponse(MakeError(TPM_RC_HANDLE, FROM_HERE));
    711     }
    712     if (!iter->second.is_loaded) {
    713       // The handle wasn't loaded so no need to bother the TPM.
    714       CleanupFlushedHandle(handle);
    715       return CreateErrorResponse(TPM_RC_SUCCESS);
    716     }
    717     actual_handle = iter->second.tpm_handle;
    718   }
    719   // Send a command with the original header but with |actual_handle| as the
    720   // parameter.
    721   std::string handle_blob;
    722   Serialize_TPM_HANDLE(actual_handle, &handle_blob);
    723   std::string updated_command = command.substr(0, kMessageHeaderSize) +
    724                                 handle_blob;
    725   // No need to loop and fix warnings, there are no actionable warnings on when
    726   // flushing context.
    727   std::string response = next_transceiver_->SendCommandAndWait(updated_command);
    728   MessageInfo response_info;
    729   TPM_RC result = ParseResponse(command_info, response, &response_info);
    730   if (result != TPM_RC_SUCCESS) {
    731     return CreateErrorResponse(result);
    732   }
    733   // Cleanup the handle locally even if the TPM did not recognize it.
    734   if (response_info.code == TPM_RC_SUCCESS ||
    735       response_info.code == TPM_RC_HANDLE) {
    736     CleanupFlushedHandle(handle);
    737   }
    738   return response;
    739 }
    740 
    741 TPM_RC ResourceManager::ProcessInputHandle(const MessageInfo& command_info,
    742                                            TPM_HANDLE virtual_handle,
    743                                            TPM_HANDLE* actual_handle) {
    744   // Only transient object handles are virtualized.
    745   if (!IsObjectHandle(virtual_handle)) {
    746     *actual_handle = virtual_handle;
    747     return TPM_RC_SUCCESS;
    748   }
    749   auto handle_iter = virtual_object_handles_.find(virtual_handle);
    750   if (handle_iter == virtual_object_handles_.end()) {
    751     return MakeError(TPM_RC_HANDLE, FROM_HERE);
    752   }
    753   HandleInfo& handle_info = handle_iter->second;
    754   if (!handle_info.is_loaded) {
    755     TPM_RC result = LoadContext(command_info, &handle_info);
    756     if (result != TPM_RC_SUCCESS) {
    757       return result;
    758     }
    759     tpm_object_handles_[handle_info.tpm_handle] = virtual_handle;
    760     VLOG(1) << "RELOAD_OBJECT: " << std::hex << virtual_handle;
    761   }
    762   VLOG(1) << "INPUT_HANDLE_REPLACE: " << std::hex << virtual_handle << " -> "
    763           << std::hex << handle_info.tpm_handle;
    764   *actual_handle = handle_info.tpm_handle;
    765   return TPM_RC_SUCCESS;
    766 }
    767 
    768 TPM_HANDLE ResourceManager::ProcessOutputHandle(TPM_HANDLE handle) {
    769   // Track, but do not virtualize, session handles.
    770   if (IsSessionHandle(handle)) {
    771     auto session_handle_iter = session_handles_.find(handle);
    772     if (session_handle_iter == session_handles_.end()) {
    773       HandleInfo new_handle_info;
    774       new_handle_info.Init(handle);
    775       session_handles_[handle] = new_handle_info;
    776       VLOG(1) << "OUTPUT_HANDLE_NEW_SESSION: " << std::hex << handle;
    777     }
    778     return handle;
    779   }
    780   // Only transient object handles are virtualized.
    781   if (!IsObjectHandle(handle)) {
    782     return handle;
    783   }
    784   auto virtual_handle_iter = tpm_object_handles_.find(handle);
    785   if (virtual_handle_iter == tpm_object_handles_.end()) {
    786     TPM_HANDLE new_virtual_handle = CreateVirtualHandle();
    787     HandleInfo new_handle_info;
    788     new_handle_info.Init(handle);
    789     virtual_object_handles_[new_virtual_handle] = new_handle_info;
    790     tpm_object_handles_[handle] = new_virtual_handle;
    791     VLOG(1) << "OUTPUT_HANDLE_NEW_VIRTUAL: " << std::hex << handle << " -> "
    792             << std::hex << new_virtual_handle;
    793     return new_virtual_handle;
    794   }
    795   VLOG(1) << "OUTPUT_HANDLE_REPLACE: " << std::hex << handle << " -> "
    796           << std::hex << virtual_handle_iter->second;
    797   return virtual_handle_iter->second;
    798 }
    799 
    800 std::string ResourceManager::ReplaceHandles(
    801     const std::string& message,
    802     const std::vector<TPM_HANDLE>& new_handles) {
    803   std::string handles_blob;
    804   for (auto handle : new_handles) {
    805     CHECK_EQ(Serialize_TPM_HANDLE(handle, &handles_blob), TPM_RC_SUCCESS);
    806   }
    807   std::string mutable_message = message;
    808   CHECK_GE(message.size(), kMessageHeaderSize + handles_blob.size());
    809   return mutable_message.replace(kMessageHeaderSize, handles_blob.size(),
    810                                  handles_blob);
    811 }
    812 
    813 TPM_RC ResourceManager::SaveContext(const MessageInfo& command_info,
    814                                     HandleInfo* handle_info) {
    815   CHECK(handle_info->is_loaded);
    816   TPM_RC result = TPM_RC_SUCCESS;
    817   int attempts = 0;
    818   while (attempts++ < kMaxCommandAttempts) {
    819     std::string tpm_handle_name;
    820     Serialize_TPM_HANDLE(handle_info->tpm_handle, &tpm_handle_name);
    821     result = factory_.GetTpm()->ContextSaveSync(handle_info->tpm_handle,
    822                                                 tpm_handle_name,
    823                                                 &handle_info->context,
    824                                                 nullptr);
    825     if (!FixWarnings(command_info, result)) {
    826       break;
    827     }
    828   }
    829   if (result != TPM_RC_SUCCESS) {
    830     LOG(ERROR) << __func__ << ": Failed to load context: "
    831                << GetErrorString(result);
    832     return result;
    833   }
    834   handle_info->is_loaded = false;
    835   return result;
    836 }
    837 
    838 
    839 ResourceManager::HandleInfo::HandleInfo()
    840     : is_loaded(false),
    841       tpm_handle(0) {
    842   memset(&context, 0, sizeof(TPMS_CONTEXT));
    843 }
    844 
    845 void ResourceManager::HandleInfo::Init(TPM_HANDLE handle) {
    846   tpm_handle = handle;
    847   is_loaded = true;
    848   time_of_create = base::TimeTicks::Now();
    849   time_of_last_use = base::TimeTicks::Now();
    850 }
    851 
    852 }  // namespace trunks
    853