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, ¶meters);
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, ¶meters);
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, ¶meters);
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