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 <string>
20 #include <vector>
21 
22 #include <base/bind.h>
23 #include <gmock/gmock.h>
24 #include <gtest/gtest.h>
25 
26 #include "trunks/error_codes.h"
27 #include "trunks/mock_command_transceiver.h"
28 #include "trunks/mock_tpm.h"
29 #include "trunks/trunks_factory_for_test.h"
30 
31 using testing::_;
32 using testing::DoAll;
33 using testing::Eq;
34 using testing::Field;
35 using testing::InSequence;
36 using testing::Return;
37 using testing::ReturnPointee;
38 using testing::SetArgumentPointee;
39 using testing::StrictMock;
40 
41 namespace {
42 
43 const trunks::TPM_HANDLE kArbitraryObjectHandle = trunks::TRANSIENT_FIRST + 25;
44 const trunks::TPM_HANDLE kArbitrarySessionHandle = trunks::HMAC_SESSION_FIRST;
45 
Assign(std::string * to,const std::string & from)46 void Assign(std::string* to, const std::string& from) {
47   *to = from;
48 }
49 
50 class ScopedDisableLogging {
51  public:
ScopedDisableLogging()52   ScopedDisableLogging() : original_severity_(logging::GetMinLogLevel()) {
53     logging::SetMinLogLevel(logging::LOG_FATAL);
54   }
~ScopedDisableLogging()55   ~ScopedDisableLogging() { logging::SetMinLogLevel(original_severity_); }
56 
57  private:
58   logging::LogSeverity original_severity_;
59 };
60 
61 }  // namespace
62 
63 namespace trunks {
64 
65 class ResourceManagerTest : public testing::Test {
66  public:
67   const std::vector<TPM_HANDLE> kNoHandles;
68   const std::string kNoAuthorization;
69   const std::string kNoParameters;
70 
ResourceManagerTest()71   ResourceManagerTest() : resource_manager_(factory_, &transceiver_) {}
~ResourceManagerTest()72   ~ResourceManagerTest() override {}
73 
SetUp()74   void SetUp() override { factory_.set_tpm(&tpm_); }
75 
76   // Builds a well-formed command.
CreateCommand(TPM_CC code,const std::vector<TPM_HANDLE> & handles,const std::string & authorization,const std::string & parameters)77   std::string CreateCommand(TPM_CC code,
78                             const std::vector<TPM_HANDLE>& handles,
79                             const std::string& authorization,
80                             const std::string& parameters) {
81     std::string buffer;
82     TPM_ST tag = authorization.empty() ? TPM_ST_NO_SESSIONS : TPM_ST_SESSIONS;
83     UINT32 size = 10 + (handles.size() * 4) + authorization.size() +
84                   parameters.size() + (authorization.empty() ? 0 : 4);
85     Serialize_TPM_ST(tag, &buffer);
86     Serialize_UINT32(size, &buffer);
87     Serialize_TPM_CC(code, &buffer);
88     for (auto handle : handles) {
89       Serialize_TPM_HANDLE(handle, &buffer);
90     }
91     if (!authorization.empty()) {
92       Serialize_UINT32(authorization.size(), &buffer);
93     }
94     return buffer + authorization + parameters;
95   }
96 
97   // Builds a well-formed response.
CreateResponse(TPM_RC code,const std::vector<TPM_HANDLE> & handles,const std::string & authorization,const std::string & parameters)98   std::string CreateResponse(TPM_RC code,
99                              const std::vector<TPM_HANDLE>& handles,
100                              const std::string& authorization,
101                              const std::string& parameters) {
102     std::string buffer;
103     TPM_ST tag = authorization.empty() ? TPM_ST_NO_SESSIONS : TPM_ST_SESSIONS;
104     UINT32 size = 10 + (handles.size() * 4) + authorization.size() +
105                   parameters.size() + (authorization.empty() ? 0 : 4);
106     Serialize_TPM_ST(tag, &buffer);
107     Serialize_UINT32(size, &buffer);
108     Serialize_TPM_RC(code, &buffer);
109     for (auto handle : handles) {
110       Serialize_TPM_HANDLE(handle, &buffer);
111     }
112     if (!authorization.empty()) {
113       Serialize_UINT32(parameters.size(), &buffer);
114     }
115     return buffer + parameters + authorization;
116   }
117 
118   // Builds a well-formed command authorization section.
CreateCommandAuthorization(TPM_HANDLE handle,bool continue_session)119   std::string CreateCommandAuthorization(TPM_HANDLE handle,
120                                          bool continue_session) {
121     std::string buffer;
122     Serialize_TPM_HANDLE(handle, &buffer);
123     Serialize_TPM2B_NONCE(Make_TPM2B_DIGEST(std::string(32, 'A')), &buffer);
124     Serialize_BYTE(continue_session ? 1 : 0, &buffer);
125     Serialize_TPM2B_DIGEST(Make_TPM2B_DIGEST(std::string(32, 'B')), &buffer);
126     return buffer;
127   }
128 
129   // Builds a well-formed response authorization section.
CreateResponseAuthorization(bool continue_session)130   std::string CreateResponseAuthorization(bool continue_session) {
131     std::string buffer;
132     Serialize_TPM2B_NONCE(Make_TPM2B_DIGEST(std::string(32, 'A')), &buffer);
133     Serialize_BYTE(continue_session ? 1 : 0, &buffer);
134     Serialize_TPM2B_DIGEST(Make_TPM2B_DIGEST(std::string(32, 'B')), &buffer);
135     return buffer;
136   }
137 
GetHeader(const std::string & message)138   std::string GetHeader(const std::string& message) {
139     return message.substr(0, 10);
140   }
141 
StripHeader(const std::string & message)142   std::string StripHeader(const std::string& message) {
143     return message.substr(10);
144   }
145 
146   // Makes the resource manager aware of a transient object handle and returns
147   // the newly associated virtual handle.
LoadHandle(TPM_HANDLE handle)148   TPM_HANDLE LoadHandle(TPM_HANDLE handle) {
149     std::vector<TPM_HANDLE> input_handles = {PERSISTENT_FIRST};
150     std::string command = CreateCommand(TPM_CC_Load, input_handles,
151                                         kNoAuthorization, kNoParameters);
152     std::vector<TPM_HANDLE> output_handles = {handle};
153     std::string response = CreateResponse(TPM_RC_SUCCESS, output_handles,
154                                           kNoAuthorization, kNoParameters);
155     EXPECT_CALL(transceiver_, SendCommandAndWait(command))
156         .WillOnce(Return(response));
157     std::string actual_response = resource_manager_.SendCommandAndWait(command);
158     std::string handle_blob = StripHeader(actual_response);
159     TPM_HANDLE virtual_handle;
160     CHECK_EQ(TPM_RC_SUCCESS,
161              Parse_TPM_HANDLE(&handle_blob, &virtual_handle, NULL));
162     return virtual_handle;
163   }
164 
165   // Causes the resource manager to evict existing object handles.
EvictObjects()166   void EvictObjects() {
167     std::string command = CreateCommand(TPM_CC_Startup, kNoHandles,
168                                         kNoAuthorization, kNoParameters);
169     std::string response = CreateErrorResponse(TPM_RC_OBJECT_MEMORY);
170     std::string success_response = CreateResponse(
171         TPM_RC_SUCCESS, kNoHandles, kNoAuthorization, kNoParameters);
172     EXPECT_CALL(transceiver_, SendCommandAndWait(_))
173         .WillOnce(Return(response))
174         .WillRepeatedly(Return(success_response));
175     EXPECT_CALL(tpm_, ContextSaveSync(_, _, _, _))
176         .WillRepeatedly(Return(TPM_RC_SUCCESS));
177     EXPECT_CALL(tpm_, FlushContextSync(_, _))
178         .WillRepeatedly(Return(TPM_RC_SUCCESS));
179     resource_manager_.SendCommandAndWait(command);
180   }
181 
182   // Makes the resource manager aware of a session handle.
StartSession(TPM_HANDLE handle)183   void StartSession(TPM_HANDLE handle) {
184     std::vector<TPM_HANDLE> input_handles = {1, 2};
185     std::string command = CreateCommand(TPM_CC_StartAuthSession, input_handles,
186                                         kNoAuthorization, kNoParameters);
187     std::vector<TPM_HANDLE> output_handles = {handle};
188     std::string response = CreateResponse(TPM_RC_SUCCESS, output_handles,
189                                           kNoAuthorization, kNoParameters);
190     EXPECT_CALL(transceiver_, SendCommandAndWait(command))
191         .WillOnce(Return(response));
192     std::string actual_response = resource_manager_.SendCommandAndWait(command);
193     ASSERT_EQ(response, actual_response);
194   }
195 
196   // Causes the resource manager to evict an existing session handle.
EvictSession()197   void EvictSession() {
198     std::string command = CreateCommand(TPM_CC_Startup, kNoHandles,
199                                         kNoAuthorization, kNoParameters);
200     std::string response = CreateErrorResponse(TPM_RC_SESSION_MEMORY);
201     std::string success_response = CreateResponse(
202         TPM_RC_SUCCESS, kNoHandles, kNoAuthorization, kNoParameters);
203     EXPECT_CALL(transceiver_, SendCommandAndWait(_))
204         .WillOnce(Return(response))
205         .WillRepeatedly(Return(success_response));
206     EXPECT_CALL(tpm_, ContextSaveSync(_, _, _, _))
207         .WillOnce(Return(TPM_RC_SUCCESS));
208     resource_manager_.SendCommandAndWait(command);
209   }
210 
211   // Creates a TPMS_CONTEXT with the given sequence field.
CreateContext(UINT64 sequence)212   TPMS_CONTEXT CreateContext(UINT64 sequence) {
213     TPMS_CONTEXT context;
214     memset(&context, 0, sizeof(context));
215     context.sequence = sequence;
216     return context;
217   }
218 
219   // Creates a serialized TPMS_CONTEXT with the given sequence field.
CreateContextParameter(UINT64 sequence)220   std::string CreateContextParameter(UINT64 sequence) {
221     std::string buffer;
222     Serialize_TPMS_CONTEXT(CreateContext(sequence), &buffer);
223     return buffer;
224   }
225 
226  protected:
227   StrictMock<MockTpm> tpm_;
228   TrunksFactoryForTest factory_;
229   StrictMock<MockCommandTransceiver> transceiver_;
230   ResourceManager resource_manager_;
231 };
232 
TEST_F(ResourceManagerTest,BasicPassThrough)233 TEST_F(ResourceManagerTest, BasicPassThrough) {
234   std::string command = CreateCommand(TPM_CC_Startup, kNoHandles,
235                                       kNoAuthorization, kNoParameters);
236   std::string response = CreateResponse(TPM_RC_SUCCESS, kNoHandles,
237                                         kNoAuthorization, kNoParameters);
238   EXPECT_CALL(transceiver_, SendCommandAndWait(command))
239       .WillOnce(Return(response));
240   std::string actual_response = resource_manager_.SendCommandAndWait(command);
241   EXPECT_EQ(actual_response, response);
242 }
243 
TEST_F(ResourceManagerTest,BasicPassThroughAsync)244 TEST_F(ResourceManagerTest, BasicPassThroughAsync) {
245   std::string command = CreateCommand(TPM_CC_Startup, kNoHandles,
246                                       kNoAuthorization, kNoParameters);
247   std::string response = CreateResponse(TPM_RC_SUCCESS, kNoHandles,
248                                         kNoAuthorization, kNoParameters);
249   EXPECT_CALL(transceiver_, SendCommandAndWait(command))
250       .WillOnce(Return(response));
251   std::string actual_response;
252   CommandTransceiver::ResponseCallback callback =
253       base::Bind(&Assign, &actual_response);
254   resource_manager_.SendCommand(command, callback);
255   EXPECT_EQ(actual_response, response);
256 }
257 
TEST_F(ResourceManagerTest,VirtualHandleOutput)258 TEST_F(ResourceManagerTest, VirtualHandleOutput) {
259   std::vector<TPM_HANDLE> input_handles = {PERSISTENT_FIRST};
260   std::string command = CreateCommand(TPM_CC_Load, input_handles,
261                                       kNoAuthorization, kNoParameters);
262   std::vector<TPM_HANDLE> output_handles = {kArbitraryObjectHandle};
263   std::string response = CreateResponse(TPM_RC_SUCCESS, output_handles,
264                                         kNoAuthorization, kNoParameters);
265   EXPECT_CALL(transceiver_, SendCommandAndWait(command))
266       .WillOnce(Return(response));
267   std::string actual_response = resource_manager_.SendCommandAndWait(command);
268   EXPECT_EQ(response.size(), actual_response.size());
269   // We expect the resource manager has replaced the output handle with a
270   // virtual handle (which we can't predict, but it's unlikely to be the same as
271   // the handle emitted by the mock).
272   EXPECT_EQ(GetHeader(response), GetHeader(actual_response));
273   EXPECT_NE(StripHeader(response), StripHeader(actual_response));
274   TPM_HT handle_type = static_cast<TPM_HT>(StripHeader(actual_response)[0]);
275   EXPECT_EQ(TPM_HT_TRANSIENT, handle_type);
276 }
277 
TEST_F(ResourceManagerTest,VirtualHandleInput)278 TEST_F(ResourceManagerTest, VirtualHandleInput) {
279   TPM_HANDLE tpm_handle = kArbitraryObjectHandle;
280   TPM_HANDLE virtual_handle = LoadHandle(tpm_handle);
281   std::vector<TPM_HANDLE> input_handles = {virtual_handle};
282   std::string command = CreateCommand(TPM_CC_Sign, input_handles,
283                                       kNoAuthorization, kNoParameters);
284   // We expect the resource manager to replace |virtual_handle| with
285   // |tpm_handle|.
286   std::vector<TPM_HANDLE> expected_input_handles = {tpm_handle};
287   std::string expected_command = CreateCommand(
288       TPM_CC_Sign, expected_input_handles, kNoAuthorization, kNoParameters);
289   std::string response = CreateResponse(TPM_RC_SUCCESS, kNoHandles,
290                                         kNoAuthorization, kNoParameters);
291   EXPECT_CALL(transceiver_, SendCommandAndWait(expected_command))
292       .WillOnce(Return(response));
293   std::string actual_response = resource_manager_.SendCommandAndWait(command);
294   EXPECT_EQ(response, actual_response);
295 }
296 
TEST_F(ResourceManagerTest,VirtualHandleCleanup)297 TEST_F(ResourceManagerTest, VirtualHandleCleanup) {
298   TPM_HANDLE tpm_handle = kArbitraryObjectHandle;
299   TPM_HANDLE virtual_handle = LoadHandle(tpm_handle);
300   std::string parameters;
301   Serialize_TPM_HANDLE(virtual_handle, &parameters);
302   std::string command = CreateCommand(TPM_CC_FlushContext, kNoHandles,
303                                       kNoAuthorization, parameters);
304   std::string expected_parameters;
305   Serialize_TPM_HANDLE(tpm_handle, &expected_parameters);
306   std::string expected_command = CreateCommand(
307       TPM_CC_FlushContext, kNoHandles, kNoAuthorization, expected_parameters);
308   std::string response = CreateResponse(TPM_RC_SUCCESS, kNoHandles,
309                                         kNoAuthorization, kNoParameters);
310   EXPECT_CALL(transceiver_, SendCommandAndWait(expected_command))
311       .WillOnce(Return(response));
312   std::string actual_response = resource_manager_.SendCommandAndWait(command);
313   EXPECT_EQ(response, actual_response);
314   // Now we expect there to be no record of |virtual_handle|.
315   std::vector<TPM_HANDLE> input_handles = {virtual_handle};
316   command = CreateCommand(TPM_CC_Sign, input_handles, kNoAuthorization,
317                           kNoParameters);
318   response = CreateErrorResponse(TPM_RC_HANDLE | kResourceManagerTpmErrorBase);
319   actual_response = resource_manager_.SendCommandAndWait(command);
320   EXPECT_EQ(response, actual_response);
321 
322   // Try again but attempt to flush |tpm_handle| instead of |virtual_handle|.
323   virtual_handle = LoadHandle(tpm_handle);
324   parameters.clear();
325   Serialize_TPM_HANDLE(tpm_handle, &parameters);
326   command = CreateCommand(TPM_CC_FlushContext, kNoHandles, kNoAuthorization,
327                           parameters);
328   actual_response = resource_manager_.SendCommandAndWait(command);
329   // TPM_RC_HANDLE also expected here.
330   EXPECT_EQ(response, actual_response);
331 }
332 
TEST_F(ResourceManagerTest,VirtualHandleLoadBeforeUse)333 TEST_F(ResourceManagerTest, VirtualHandleLoadBeforeUse) {
334   TPM_HANDLE tpm_handle = kArbitraryObjectHandle;
335   TPM_HANDLE virtual_handle = LoadHandle(tpm_handle);
336   EvictObjects();
337   std::vector<TPM_HANDLE> input_handles = {virtual_handle};
338   std::string command = CreateCommand(TPM_CC_Sign, input_handles,
339                                       kNoAuthorization, kNoParameters);
340   std::vector<TPM_HANDLE> expected_input_handles = {tpm_handle};
341   std::string expected_command = CreateCommand(
342       TPM_CC_Sign, expected_input_handles, kNoAuthorization, kNoParameters);
343   std::string response = CreateResponse(TPM_RC_SUCCESS, kNoHandles,
344                                         kNoAuthorization, kNoParameters);
345   EXPECT_CALL(tpm_, ContextLoadSync(_, _, _)).WillOnce(Return(TPM_RC_SUCCESS));
346   EXPECT_CALL(transceiver_, SendCommandAndWait(expected_command))
347       .WillOnce(Return(response));
348   std::string actual_response = resource_manager_.SendCommandAndWait(command);
349   EXPECT_EQ(response, actual_response);
350 }
351 
TEST_F(ResourceManagerTest,InvalidVirtualHandle)352 TEST_F(ResourceManagerTest, InvalidVirtualHandle) {
353   std::vector<TPM_HANDLE> input_handles = {kArbitraryObjectHandle};
354   std::string command = CreateCommand(TPM_CC_Sign, input_handles,
355                                       kNoAuthorization, kNoParameters);
356   std::string response =
357       CreateErrorResponse(TPM_RC_HANDLE | kResourceManagerTpmErrorBase);
358   std::string actual_response = resource_manager_.SendCommandAndWait(command);
359   EXPECT_EQ(response, actual_response);
360 }
361 
TEST_F(ResourceManagerTest,SimpleFuzzInputParser)362 TEST_F(ResourceManagerTest, SimpleFuzzInputParser) {
363   std::vector<TPM_HANDLE> handles = {1, 2};
364   std::string parameters = "12345";
365   std::string command =
366       CreateCommand(TPM_CC_StartAuthSession, handles,
367                     CreateCommandAuthorization(kArbitrarySessionHandle,
368                                                true),  // continue_session
369                     parameters);
370   // We don't care about what happens, only that it doesn't crash.
371   EXPECT_CALL(transceiver_, SendCommandAndWait(_))
372       .WillRepeatedly(Return(CreateErrorResponse(TPM_RC_FAILURE)));
373   ScopedDisableLogging no_logging;
374   for (size_t i = 0; i < command.size(); ++i) {
375     resource_manager_.SendCommandAndWait(command.substr(0, i));
376     resource_manager_.SendCommandAndWait(command.substr(i));
377     std::string fuzzed_command(command);
378     for (uint8_t value = 0;; value++) {
379       fuzzed_command[i] = static_cast<char>(value);
380       resource_manager_.SendCommandAndWait(fuzzed_command);
381       if (value == 255) {
382         break;
383       }
384     }
385   }
386 }
387 
TEST_F(ResourceManagerTest,SimpleFuzzOutputParser)388 TEST_F(ResourceManagerTest, SimpleFuzzOutputParser) {
389   std::vector<TPM_HANDLE> handles = {1, 2};
390   std::string parameters = "12345";
391   std::string command =
392       CreateCommand(TPM_CC_StartAuthSession, handles,
393                     CreateCommandAuthorization(kArbitrarySessionHandle,
394                                                true),  // continue_session
395                     parameters);
396   std::vector<TPM_HANDLE> out_handles = {3};
397   std::string response =
398       CreateResponse(TPM_RC_SUCCESS, out_handles,
399                      CreateResponseAuthorization(true),  // continue_session
400                      parameters);
401   std::string fuzzed_response;
402   EXPECT_CALL(transceiver_, SendCommandAndWait(_))
403       .WillRepeatedly(ReturnPointee(&fuzzed_response));
404   ScopedDisableLogging no_logging;
405   for (size_t i = 0; i < response.size(); ++i) {
406     fuzzed_response = response.substr(0, i);
407     resource_manager_.SendCommandAndWait(command);
408     fuzzed_response = response.substr(i);
409     resource_manager_.SendCommandAndWait(command);
410     fuzzed_response = response;
411     for (uint8_t value = 0;; value++) {
412       fuzzed_response[i] = static_cast<char>(value);
413       resource_manager_.SendCommandAndWait(command);
414       if (value == 255) {
415         break;
416       }
417     }
418     fuzzed_response[i] = response[i];
419   }
420 }
421 
TEST_F(ResourceManagerTest,NewSession)422 TEST_F(ResourceManagerTest, NewSession) {
423   StartSession(kArbitrarySessionHandle);
424   std::string command =
425       CreateCommand(TPM_CC_Startup, kNoHandles,
426                     CreateCommandAuthorization(kArbitrarySessionHandle,
427                                                true),  // continue_session
428                     kNoParameters);
429   std::string response =
430       CreateResponse(TPM_RC_SUCCESS, kNoHandles,
431                      CreateResponseAuthorization(true),  // continue_session
432                      kNoParameters);
433   EXPECT_CALL(transceiver_, SendCommandAndWait(command))
434       .WillOnce(Return(response));
435   std::string actual_response = resource_manager_.SendCommandAndWait(command);
436   EXPECT_EQ(response, actual_response);
437 }
438 
TEST_F(ResourceManagerTest,DiscontinuedSession)439 TEST_F(ResourceManagerTest, DiscontinuedSession) {
440   StartSession(kArbitrarySessionHandle);
441   // Use the session but do not continue.
442   std::string command =
443       CreateCommand(TPM_CC_Startup, kNoHandles,
444                     CreateCommandAuthorization(kArbitrarySessionHandle,
445                                                false),  // continue_session
446                     kNoParameters);
447   std::string response =
448       CreateResponse(TPM_RC_SUCCESS, kNoHandles,
449                      CreateResponseAuthorization(false),  // continue_session
450                      kNoParameters);
451   EXPECT_CALL(transceiver_, SendCommandAndWait(command))
452       .WillOnce(Return(response));
453   std::string actual_response = resource_manager_.SendCommandAndWait(command);
454   EXPECT_EQ(response, actual_response);
455   // Now attempt to use it again and expect a handle error.
456   response = CreateErrorResponse(TPM_RC_HANDLE | kResourceManagerTpmErrorBase);
457   actual_response = resource_manager_.SendCommandAndWait(command);
458   EXPECT_EQ(response, actual_response);
459 }
460 
TEST_F(ResourceManagerTest,LoadSessionBeforeUse)461 TEST_F(ResourceManagerTest, LoadSessionBeforeUse) {
462   StartSession(kArbitrarySessionHandle);
463   EvictSession();
464   std::string command =
465       CreateCommand(TPM_CC_Startup, kNoHandles,
466                     CreateCommandAuthorization(kArbitrarySessionHandle,
467                                                true),  // continue_session
468                     kNoParameters);
469   std::string response =
470       CreateResponse(TPM_RC_SUCCESS, kNoHandles,
471                      CreateResponseAuthorization(true),  // continue_session
472                      kNoParameters);
473   EXPECT_CALL(transceiver_, SendCommandAndWait(command))
474       .WillOnce(Return(response));
475   EXPECT_CALL(tpm_, ContextLoadSync(_, _, _)).WillOnce(Return(TPM_RC_SUCCESS));
476   std::string actual_response = resource_manager_.SendCommandAndWait(command);
477   EXPECT_EQ(response, actual_response);
478 }
479 
TEST_F(ResourceManagerTest,SessionHandleCleanup)480 TEST_F(ResourceManagerTest, SessionHandleCleanup) {
481   StartSession(kArbitrarySessionHandle);
482   std::string parameters;
483   Serialize_TPM_HANDLE(kArbitrarySessionHandle, &parameters);
484   std::string command = CreateCommand(TPM_CC_FlushContext, kNoHandles,
485                                       kNoAuthorization, parameters);
486   std::string response = CreateResponse(TPM_RC_SUCCESS, kNoHandles,
487                                         kNoAuthorization, kNoParameters);
488   EXPECT_CALL(transceiver_, SendCommandAndWait(command))
489       .WillOnce(Return(response));
490   std::string actual_response = resource_manager_.SendCommandAndWait(command);
491   EXPECT_EQ(response, actual_response);
492   // Now we expect there to be no record of |kArbitrarySessionHandle|.
493   command = CreateCommand(TPM_CC_Startup, kNoHandles,
494                           CreateCommandAuthorization(kArbitrarySessionHandle,
495                                                      true),  // continue_session
496                           kNoParameters);
497   response = CreateErrorResponse(TPM_RC_HANDLE | kResourceManagerTpmErrorBase);
498   actual_response = resource_manager_.SendCommandAndWait(command);
499   EXPECT_EQ(response, actual_response);
500 }
501 
TEST_F(ResourceManagerTest,EvictWhenObjectInUse)502 TEST_F(ResourceManagerTest, EvictWhenObjectInUse) {
503   TPM_HANDLE tpm_handle = kArbitraryObjectHandle;
504   TPM_HANDLE virtual_handle = LoadHandle(tpm_handle);
505   TPM_HANDLE tpm_handle2 = kArbitraryObjectHandle + 1;
506   LoadHandle(tpm_handle2);
507   std::vector<TPM_HANDLE> input_handles = {virtual_handle};
508   std::string command = CreateCommand(TPM_CC_Sign, input_handles,
509                                       kNoAuthorization, kNoParameters);
510   // Trigger evict logic and verify |input_handles| are not evicted.
511   std::string response = CreateErrorResponse(TPM_RC_OBJECT_MEMORY);
512   std::string success_response = CreateResponse(
513       TPM_RC_SUCCESS, kNoHandles, kNoAuthorization, kNoParameters);
514   EXPECT_CALL(tpm_, ContextSaveSync(tpm_handle2, _, _, _))
515       .WillOnce(Return(TPM_RC_SUCCESS));
516   EXPECT_CALL(tpm_, FlushContextSync(tpm_handle2, _))
517       .WillOnce(Return(TPM_RC_SUCCESS));
518   EXPECT_CALL(transceiver_, SendCommandAndWait(_))
519       .WillOnce(Return(response))
520       .WillRepeatedly(Return(success_response));
521   std::string actual_response = resource_manager_.SendCommandAndWait(command);
522   EXPECT_EQ(success_response, actual_response);
523 }
524 
TEST_F(ResourceManagerTest,EvictWhenSessionInUse)525 TEST_F(ResourceManagerTest, EvictWhenSessionInUse) {
526   StartSession(kArbitrarySessionHandle);
527   StartSession(kArbitrarySessionHandle + 1);
528   std::string command =
529       CreateCommand(TPM_CC_Startup, kNoHandles,
530                     CreateCommandAuthorization(kArbitrarySessionHandle,
531                                                true),  // continue_session
532                     kNoParameters);
533   std::string response =
534       CreateResponse(TPM_RC_SUCCESS, kNoHandles,
535                      CreateResponseAuthorization(true),  // continue_session
536                      kNoParameters);
537   std::string error_response = CreateErrorResponse(TPM_RC_SESSION_MEMORY);
538   EXPECT_CALL(transceiver_, SendCommandAndWait(_))
539       .WillOnce(Return(error_response))
540       .WillRepeatedly(Return(response));
541   EXPECT_CALL(tpm_, ContextSaveSync(kArbitrarySessionHandle + 1, _, _, _))
542       .WillOnce(Return(TPM_RC_SUCCESS));
543   std::string actual_response = resource_manager_.SendCommandAndWait(command);
544   EXPECT_EQ(response, actual_response);
545 }
546 
TEST_F(ResourceManagerTest,EvictMultipleObjects)547 TEST_F(ResourceManagerTest, EvictMultipleObjects) {
548   const int kNumObjects = 10;
549   std::map<TPM_HANDLE, TPM_HANDLE> handles;
550   for (int i = 0; i < kNumObjects; ++i) {
551     TPM_HANDLE handle = kArbitraryObjectHandle + i;
552     handles[LoadHandle(handle)] = handle;
553   }
554   EvictObjects();
555   std::string response = CreateResponse(TPM_RC_SUCCESS, kNoHandles,
556                                         kNoAuthorization, kNoParameters);
557   EXPECT_CALL(tpm_, ContextLoadSync(_, _, _))
558       .Times(kNumObjects)
559       .WillRepeatedly(Return(TPM_RC_SUCCESS));
560   EXPECT_CALL(transceiver_, SendCommandAndWait(_))
561       .WillRepeatedly(Return(response));
562   for (auto item : handles) {
563     std::vector<TPM_HANDLE> input_handles = {item.first};
564     std::string command = CreateCommand(TPM_CC_Sign, input_handles,
565                                         kNoAuthorization, kNoParameters);
566     std::string actual_response = resource_manager_.SendCommandAndWait(command);
567     EXPECT_EQ(response, actual_response);
568   }
569 }
570 
TEST_F(ResourceManagerTest,EvictMostStaleSession)571 TEST_F(ResourceManagerTest, EvictMostStaleSession) {
572   StartSession(kArbitrarySessionHandle);
573   StartSession(kArbitrarySessionHandle + 1);
574   StartSession(kArbitrarySessionHandle + 2);
575   std::string response =
576       CreateResponse(TPM_RC_SUCCESS, kNoHandles,
577                      CreateResponseAuthorization(true),  // continue_session
578                      kNoParameters);
579   EXPECT_CALL(transceiver_, SendCommandAndWait(_))
580       .WillRepeatedly(Return(response));
581   // Use the first two sessions, leaving the third as the most stale.
582   for (int i = 0; i < 2; ++i) {
583     std::string command =
584         CreateCommand(TPM_CC_Startup, kNoHandles,
585                       CreateCommandAuthorization(kArbitrarySessionHandle + i,
586                                                  true),  // continue_session
587                       kNoParameters);
588     std::string actual_response = resource_manager_.SendCommandAndWait(command);
589     EXPECT_EQ(response, actual_response);
590   }
591   EvictSession();
592   // EvictSession will have messed with the expectations; set them again.
593   EXPECT_CALL(transceiver_, SendCommandAndWait(_))
594       .WillRepeatedly(Return(response));
595   // Use the first two sessions again, expecting no calls to ContextLoad.
596   for (int i = 0; i < 2; ++i) {
597     std::string command =
598         CreateCommand(TPM_CC_Startup, kNoHandles,
599                       CreateCommandAuthorization(kArbitrarySessionHandle + i,
600                                                  true),  // continue_session
601                       kNoParameters);
602     std::string actual_response = resource_manager_.SendCommandAndWait(command);
603     EXPECT_EQ(response, actual_response);
604   }
605   // Expect a call to ContextLoad if we use the third session.
606   std::string command =
607       CreateCommand(TPM_CC_Startup, kNoHandles,
608                     CreateCommandAuthorization(kArbitrarySessionHandle + 2,
609                                                true),  // continue_session
610                     kNoParameters);
611   EXPECT_CALL(tpm_, ContextLoadSync(_, _, _)).WillOnce(Return(TPM_RC_SUCCESS));
612   std::string actual_response = resource_manager_.SendCommandAndWait(command);
613   EXPECT_EQ(response, actual_response);
614 }
615 
TEST_F(ResourceManagerTest,HandleContextGap)616 TEST_F(ResourceManagerTest, HandleContextGap) {
617   const int kNumSessions = 7;
618   const int kNumSessionsToUngap = 4;
619   std::vector<TPM_HANDLE> expected_ungap_order;
620   for (int i = 0; i < kNumSessions; ++i) {
621     StartSession(kArbitrarySessionHandle + i);
622     if (i < kNumSessionsToUngap) {
623       EvictSession();
624       expected_ungap_order.push_back(kArbitrarySessionHandle + i);
625     }
626   }
627   // Invoke a context gap.
628   std::string command = CreateCommand(TPM_CC_Startup, kNoHandles,
629                                       kNoAuthorization, kNoParameters);
630   std::string response = CreateErrorResponse(TPM_RC_CONTEXT_GAP);
631   std::string success_response = CreateResponse(
632       TPM_RC_SUCCESS, kNoHandles, kNoAuthorization, kNoParameters);
633   {
634     InSequence ungap_order;
635     for (auto handle : expected_ungap_order) {
636       EXPECT_CALL(tpm_, ContextLoadSync(_, _, _))
637           .WillOnce(Return(TPM_RC_SUCCESS));
638       EXPECT_CALL(tpm_, ContextSaveSync(handle, _, _, _))
639           .WillOnce(Return(TPM_RC_SUCCESS));
640     }
641   }
642   EXPECT_CALL(transceiver_, SendCommandAndWait(_))
643       .WillOnce(Return(response))
644       .WillRepeatedly(Return(success_response));
645   std::string actual_response = resource_manager_.SendCommandAndWait(command);
646   EXPECT_EQ(success_response, actual_response);
647 }
648 
TEST_F(ResourceManagerTest,ExternalContext)649 TEST_F(ResourceManagerTest, ExternalContext) {
650   StartSession(kArbitrarySessionHandle);
651   // Do an external context save.
652   std::vector<TPM_HANDLE> handles = {kArbitrarySessionHandle};
653   std::string context_save = CreateCommand(TPM_CC_ContextSave, handles,
654                                            kNoAuthorization, kNoParameters);
655   std::string context_parameter1 = CreateContextParameter(1);
656   std::string context_save_response1 = CreateResponse(
657       TPM_RC_SUCCESS, kNoHandles, kNoAuthorization, context_parameter1);
658   EXPECT_CALL(transceiver_, SendCommandAndWait(context_save))
659       .WillOnce(Return(context_save_response1));
660   std::string actual_response =
661       resource_manager_.SendCommandAndWait(context_save);
662   EXPECT_EQ(context_save_response1, actual_response);
663 
664   // Invoke a context gap (which will cause context1 to be mapped to context2).
665   EXPECT_CALL(tpm_,
666               ContextLoadSync(Field(&TPMS_CONTEXT::sequence, Eq(1u)), _, _))
667       .WillOnce(Return(TPM_RC_SUCCESS));
668   EXPECT_CALL(tpm_, ContextSaveSync(kArbitrarySessionHandle, _, _, _))
669       .WillOnce(DoAll(SetArgumentPointee<2>(CreateContext(2)),
670                       Return(TPM_RC_SUCCESS)));
671   std::string command = CreateCommand(TPM_CC_Startup, kNoHandles,
672                                       kNoAuthorization, kNoParameters);
673   std::string response = CreateErrorResponse(TPM_RC_CONTEXT_GAP);
674   std::string success_response = CreateResponse(
675       TPM_RC_SUCCESS, kNoHandles, kNoAuthorization, kNoParameters);
676   EXPECT_CALL(transceiver_, SendCommandAndWait(command))
677       .WillOnce(Return(response))
678       .WillOnce(Return(success_response));
679   actual_response = resource_manager_.SendCommandAndWait(command);
680   EXPECT_EQ(success_response, actual_response);
681 
682   // Now load external context1 and expect an actual load of context2.
683   std::string context_load1 = CreateCommand(
684       TPM_CC_ContextLoad, kNoHandles, kNoAuthorization, context_parameter1);
685   std::string context_load2 =
686       CreateCommand(TPM_CC_ContextLoad, kNoHandles, kNoAuthorization,
687                     CreateContextParameter(2));
688   std::string context_load_response =
689       CreateResponse(TPM_RC_SUCCESS, handles, kNoAuthorization, kNoParameters);
690   EXPECT_CALL(transceiver_, SendCommandAndWait(context_load2))
691       .WillOnce(Return(context_load_response));
692   actual_response = resource_manager_.SendCommandAndWait(context_load1);
693   EXPECT_EQ(context_load_response, actual_response);
694 }
695 
TEST_F(ResourceManagerTest,NestedFailures)696 TEST_F(ResourceManagerTest, NestedFailures) {
697   // The scenario being tested is when a command results in a warning to be
698   // handled by the resource manager, and in the process of handling the first
699   // warning another warning occurs which should be handled by the resource
700   // manager, etc..
701   for (int i = 0; i < 3; ++i) {
702     LoadHandle(kArbitraryObjectHandle + i);
703   }
704   EvictObjects();
705   for (int i = 3; i < 6; ++i) {
706     LoadHandle(kArbitraryObjectHandle + i);
707   }
708   for (int i = 0; i < 10; ++i) {
709     StartSession(kArbitrarySessionHandle + i);
710     EvictSession();
711   }
712   for (int i = 10; i < 20; ++i) {
713     StartSession(kArbitrarySessionHandle + i);
714   }
715   std::string error_response = CreateErrorResponse(TPM_RC_MEMORY);
716   EXPECT_CALL(transceiver_, SendCommandAndWait(_))
717       .WillRepeatedly(Return(error_response));
718   // The TPM_RC_MEMORY will result in a context save, make that fail too.
719   EXPECT_CALL(tpm_, ContextSaveSync(_, _, _, _))
720       .WillRepeatedly(Return(TPM_RC_CONTEXT_GAP));
721   // The TPM_RC_CONTEXT_GAP will result in a context load.
722   EXPECT_CALL(tpm_, ContextLoadSync(_, _, _))
723       .WillRepeatedly(Return(TPM_RC_SESSION_HANDLES));
724   // The TPM_RC_SESSION_HANDLES will result in a context flush.
725   EXPECT_CALL(tpm_, FlushContextSync(_, _))
726       .WillRepeatedly(Return(TPM_RC_SESSION_MEMORY));
727   // The resource manager should not handle the same warning twice so we expect
728   // the error of the original call to bubble up.
729   std::string command = CreateCommand(TPM_CC_Startup, kNoHandles,
730                                       kNoAuthorization, kNoParameters);
731   std::string response = resource_manager_.SendCommandAndWait(command);
732   EXPECT_EQ(error_response, response);
733 }
734 
TEST_F(ResourceManagerTest,OutOfMemory)735 TEST_F(ResourceManagerTest, OutOfMemory) {
736   std::string error_response = CreateErrorResponse(TPM_RC_MEMORY);
737   EXPECT_CALL(transceiver_, SendCommandAndWait(_))
738       .WillRepeatedly(Return(error_response));
739   std::string command = CreateCommand(TPM_CC_Startup, kNoHandles,
740                                       kNoAuthorization, kNoParameters);
741   std::string response = resource_manager_.SendCommandAndWait(command);
742   EXPECT_EQ(error_response, response);
743 }
744 
TEST_F(ResourceManagerTest,ReentrantFixGap)745 TEST_F(ResourceManagerTest, ReentrantFixGap) {
746   for (int i = 0; i < 3; ++i) {
747     StartSession(kArbitrarySessionHandle + i);
748     EvictSession();
749   }
750   for (int i = 3; i < 6; ++i) {
751     StartSession(kArbitrarySessionHandle + i);
752   }
753   std::string error_response = CreateErrorResponse(TPM_RC_CONTEXT_GAP);
754   EXPECT_CALL(transceiver_, SendCommandAndWait(_))
755       .WillRepeatedly(Return(error_response));
756   EXPECT_CALL(tpm_, ContextSaveSync(_, _, _, _))
757       .WillRepeatedly(Return(TPM_RC_CONTEXT_GAP));
758   EXPECT_CALL(tpm_, ContextLoadSync(_, _, _))
759       .WillOnce(Return(TPM_RC_CONTEXT_GAP))
760       .WillRepeatedly(Return(TPM_RC_SUCCESS));
761   std::string command = CreateCommand(TPM_CC_Startup, kNoHandles,
762                                       kNoAuthorization, kNoParameters);
763   std::string response = resource_manager_.SendCommandAndWait(command);
764   EXPECT_EQ(error_response, response);
765 }
766 
TEST_F(ResourceManagerTest,PasswordAuthorization)767 TEST_F(ResourceManagerTest, PasswordAuthorization) {
768   std::string command =
769       CreateCommand(TPM_CC_Startup, kNoHandles,
770                     CreateCommandAuthorization(TPM_RS_PW,
771                                                false),  // continue_session
772                     kNoParameters);
773   std::string response =
774       CreateResponse(TPM_RC_SUCCESS, kNoHandles,
775                      CreateResponseAuthorization(false),  // continue_session
776                      kNoParameters);
777   EXPECT_CALL(transceiver_, SendCommandAndWait(command))
778       .WillOnce(Return(response));
779   std::string actual_response = resource_manager_.SendCommandAndWait(command);
780   EXPECT_EQ(response, actual_response);
781 }
782 
783 }  // namespace trunks
784