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