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