1 // Copyright 2014 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Note: These tests are not generated. They test generated code.
6
7 #include <iterator>
8 #include <utility>
9
10 #include <gtest/gtest.h>
11
12 #include "mock_authorization_delegate.h"
13 #include "mock_command_transceiver.h"
14 #include "tpm_generated.h"
15
16 using testing::_;
17 using testing::DoAll;
18 using testing::Invoke;
19 using testing::Return;
20 using testing::SetArgPointee;
21 using testing::StrictMock;
22 using testing::WithArg;
23
24 namespace trunks {
25
26 // This test is designed to get good coverage of the different types of code
27 // generated for serializing and parsing structures / unions / typedefs.
TEST(GeneratorTest,SerializeParseStruct)28 TEST(GeneratorTest, SerializeParseStruct) {
29 TPM2B_CREATION_DATA data;
30 memset(&data, 0, sizeof(TPM2B_CREATION_DATA));
31 data.size = sizeof(TPMS_CREATION_DATA);
32 data.creation_data.pcr_select.count = 1;
33 data.creation_data.pcr_select.pcr_selections[0].hash = TPM_ALG_SHA256;
34 data.creation_data.pcr_select.pcr_selections[0].sizeof_select = 1;
35 data.creation_data.pcr_select.pcr_selections[0].pcr_select[0] = 0;
36 data.creation_data.pcr_digest.size = 2;
37 data.creation_data.locality = 0;
38 data.creation_data.parent_name_alg = TPM_ALG_SHA256;
39 data.creation_data.parent_name.size = 3;
40 data.creation_data.parent_qualified_name.size = 4;
41 data.creation_data.outside_info.size = 5;
42 std::string buffer;
43 TPM_RC rc = Serialize_TPM2B_CREATION_DATA(data, &buffer);
44 ASSERT_EQ(TPM_RC_SUCCESS, rc);
45 EXPECT_EQ(35u, buffer.size());
46 TPM2B_CREATION_DATA data2;
47 memset(&data2, 0, sizeof(TPM2B_CREATION_DATA));
48 std::string buffer_before = buffer;
49 std::string buffer_parsed;
50 rc = Parse_TPM2B_CREATION_DATA(&buffer, &data2, &buffer_parsed);
51 ASSERT_EQ(TPM_RC_SUCCESS, rc);
52 EXPECT_EQ(0u, buffer.size());
53 EXPECT_EQ(buffer_before, buffer_parsed);
54 EXPECT_EQ(data.size, data2.size);
55 EXPECT_EQ(0, memcmp(&data.creation_data, &data2.creation_data,
56 sizeof(TPMS_CREATION_DATA)));
57 }
58
59 // This tests serializing and parsing TPM2B_ structures with zero |size|, in
60 // which case the enclosed structure isn't marshalled.
TEST(GeneratorTest,SerializeParseEmptyStruct)61 TEST(GeneratorTest, SerializeParseEmptyStruct) {
62 TPM2B_CREATION_DATA data;
63 memset(&data, 0, sizeof(TPM2B_CREATION_DATA));
64 std::string buffer;
65 TPM_RC rc = Serialize_TPM2B_CREATION_DATA(data, &buffer);
66 ASSERT_EQ(TPM_RC_SUCCESS, rc);
67 EXPECT_EQ(2u, buffer.size());
68 TPM2B_CREATION_DATA data2;
69 memset(&data2, 0, sizeof(TPM2B_CREATION_DATA));
70 std::string buffer_before = buffer;
71 std::string buffer_parsed;
72 rc = Parse_TPM2B_CREATION_DATA(&buffer, &data2, &buffer_parsed);
73 ASSERT_EQ(TPM_RC_SUCCESS, rc);
74 EXPECT_EQ(0u, buffer.size());
75 EXPECT_EQ(buffer_before, buffer_parsed);
76 EXPECT_EQ(data.size, data2.size);
77 EXPECT_EQ(0, memcmp(&data.creation_data, &data2.creation_data,
78 sizeof(TPMS_CREATION_DATA)));
79 }
80
TEST(GeneratorTest,SerializeBufferOverflow)81 TEST(GeneratorTest, SerializeBufferOverflow) {
82 TPM2B_MAX_BUFFER value;
83 value.size = std::size(value.buffer) + 1;
84 std::string tmp;
85 EXPECT_EQ(TPM_RC_INSUFFICIENT, Serialize_TPM2B_MAX_BUFFER(value, &tmp));
86 }
87
TEST(GeneratorTest,ParseBufferOverflow)88 TEST(GeneratorTest, ParseBufferOverflow) {
89 TPM2B_MAX_BUFFER tmp;
90 // Case 1: Sufficient source but overflow the destination.
91 std::string malformed1 = "\x10\x00";
92 malformed1 += std::string(0x1000, 'A');
93 ASSERT_GT(0x1000u, sizeof(tmp.buffer));
94 EXPECT_EQ(TPM_RC_INSUFFICIENT,
95 Parse_TPM2B_MAX_BUFFER(&malformed1, &tmp, nullptr));
96 // Case 2: Sufficient destination but overflow the source.
97 std::string malformed2 = "\x00\x01";
98 EXPECT_EQ(TPM_RC_INSUFFICIENT,
99 Parse_TPM2B_MAX_BUFFER(&malformed2, &tmp, nullptr));
100 }
101
TEST(GeneratorTest,SynchronousCommand)102 TEST(GeneratorTest, SynchronousCommand) {
103 // A hand-rolled TPM2_Startup command.
104 std::string expected_command(
105 "\x80\x01" // tag=TPM_ST_NO_SESSIONS
106 "\x00\x00\x00\x0C" // size=12
107 "\x00\x00\x01\x44" // code=TPM_CC_Startup
108 "\x00\x00", // param=TPM_SU_CLEAR
109 12);
110 std::string command_response(
111 "\x80\x01" // tag=TPM_ST_NO_SESSIONS
112 "\x00\x00\x00\x0A" // size=10
113 "\x00\x00\x00\x00", // code=TPM_RC_SUCCESS
114 10);
115 StrictMock<MockCommandTransceiver> transceiver;
116 EXPECT_CALL(transceiver, SendCommandAndWait(expected_command))
117 .WillOnce(Return(command_response));
118 StrictMock<MockAuthorizationDelegate> authorization;
119 EXPECT_CALL(authorization, GetCommandAuthorization(_, _, _, _))
120 .WillOnce(Return(true));
121 Tpm tpm(&transceiver);
122 EXPECT_EQ(TPM_RC_SUCCESS, tpm.StartupSync(TPM_SU_CLEAR, &authorization));
123 }
124
TEST(GeneratorTest,SynchronousCommandWithError)125 TEST(GeneratorTest, SynchronousCommandWithError) {
126 // A hand-rolled TPM2_Startup command.
127 std::string expected_command(
128 "\x80\x01" // tag=TPM_ST_NO_SESSIONS
129 "\x00\x00\x00\x0C" // size=12
130 "\x00\x00\x01\x44" // code=TPM_CC_Startup
131 "\x00\x00", // param=TPM_SU_CLEAR
132 12);
133 std::string command_response(
134 "\x80\x01" // tag=TPM_ST_NO_SESSIONS
135 "\x00\x00\x00\x0A" // size=10
136 "\x00\x00\x01\x01", // code=TPM_RC_FAILURE
137 10);
138 StrictMock<MockCommandTransceiver> transceiver;
139 EXPECT_CALL(transceiver, SendCommandAndWait(expected_command))
140 .WillOnce(Return(command_response));
141 StrictMock<MockAuthorizationDelegate> authorization;
142 EXPECT_CALL(authorization, GetCommandAuthorization(_, _, _, _))
143 .WillOnce(Return(true));
144 Tpm tpm(&transceiver);
145 EXPECT_EQ(TPM_RC_FAILURE, tpm.StartupSync(TPM_SU_CLEAR, &authorization));
146 }
147
TEST(GeneratorTest,SynchronousCommandResponseTest)148 TEST(GeneratorTest, SynchronousCommandResponseTest) {
149 std::string auth_in(10, 'A');
150 std::string auth_out(10, 'B');
151 std::string auth_size("\x00\x00\x00\x0A", 4);
152 std::string handle_in("\x40\x00\x00\x07", 4); // primary_handle = TPM_RH_NULL
153 std::string handle_out("\x80\x00\x00\x01", 4); // out_handle
154 std::string sensitive(
155 "\x00\x05" // sensitive.size = 5
156 "\x00\x01" // sensitive.auth.size = 1
157 "\x61" // sensitive.auth.buffer[0] = 0x65
158 "\x00\x00", // sensitive.data.size = 0
159 7);
160 std::string public_data(
161 "\x00\x12" // public.size = 18
162 "\x00\x25" // public.type = TPM_ALG_SYMCIPHER
163 "\x00\x0B" // public.name_alg = SHA256
164 "\x00\x00\x00\x00"
165 "\x00\x00" // public.auth_policy.size = 0
166 "\x00\x06" // public.sym.alg = TPM_ALG_AES
167 "\x00\x80" // public.sym.key_bits = 128
168 "\x00\x43" // public.sym.mode = TPM_ALG_CFB
169 "\x00\x00", // public.unique.size = 0
170 20);
171 std::string outside("\x00\x00", 2); // outside_info.size = 0
172 std::string pcr_select("\x00\x00\x00\x00", 4); // pcr_select.size = 0
173
174 std::string data(
175 "\x00\x0F" // creation_data.size = 15
176 "\x00\x00\x00\x00" // creation.pcr = 0
177 "\x00\x00" // creation.digest.size = 0
178 "\x00" // creation.locality = 0
179 "\x00\x00" // creation.parent_alg = 0
180 "\x00\x00" // creation.parent_name.size = 0
181 "\x00\x00"
182 "\x00\x00", // creation.outside.size = 0
183 17);
184 std::string hash(
185 "\x00\x01"
186 "\x62",
187 3);
188 std::string ticket(
189 "\x80\x02" // tag = TPM_ST_SESSIONS
190 "\x40\x00\x00\x07" // parent = TPM_RH_NULL
191 "\x00\x00",
192 8);
193 std::string name(
194 "\x00\x03"
195 "KEY",
196 5);
197 std::string parameter_size("\x00\x00\x00\x35", 4); // param_size = 38
198
199 std::string command_tag(
200 "\x80\x02" // tag = TPM_ST_SESSIONS
201 "\x00\x00\x00\x3D" // size = 61
202 "\x00\x00\x01\x31", // code = TPM_CC_CreatePrimary
203 10);
204 std::string response_tag(
205 "\x80\x02" // tag = TPM_ST_SESSIONS
206 "\x00\x00\x00\x51" // size = 79
207 "\x00\x00\x00\x00", // rc = TPM_RC_SUCCESS
208 10);
209
210 std::string expected_command = command_tag + handle_in + auth_size + auth_in +
211 sensitive + public_data + outside + pcr_select;
212 std::string command_response = response_tag + handle_out + parameter_size +
213 public_data + data + hash + ticket + name +
214 auth_out;
215
216 StrictMock<MockCommandTransceiver> transceiver;
217 EXPECT_CALL(transceiver, SendCommandAndWait(expected_command))
218 .WillOnce(Return(command_response));
219 StrictMock<MockAuthorizationDelegate> authorization;
220 EXPECT_CALL(authorization, GetCommandAuthorization(_, _, _, _))
221 .WillOnce(DoAll(SetArgPointee<3>(auth_in), Return(true)));
222 EXPECT_CALL(authorization, CheckResponseAuthorization(_, auth_out))
223 .WillOnce(Return(true));
224 EXPECT_CALL(authorization, EncryptCommandParameter(_)).WillOnce(Return(true));
225 EXPECT_CALL(authorization, DecryptResponseParameter(_))
226 .WillOnce(Return(true));
227
228 TPM2B_SENSITIVE_CREATE in_sensitive;
229 in_sensitive.size = sizeof(TPMS_SENSITIVE_CREATE);
230 in_sensitive.sensitive.user_auth.size = 1;
231 in_sensitive.sensitive.user_auth.buffer[0] = 'a';
232 in_sensitive.sensitive.data.size = 0;
233 TPM2B_PUBLIC in_public;
234 in_public.size = sizeof(TPMT_PUBLIC);
235 in_public.public_area.type = TPM_ALG_SYMCIPHER;
236 in_public.public_area.name_alg = TPM_ALG_SHA256;
237 in_public.public_area.object_attributes = 0;
238 in_public.public_area.auth_policy.size = 0;
239 in_public.public_area.parameters.sym_detail.sym.algorithm = TPM_ALG_AES;
240 in_public.public_area.parameters.sym_detail.sym.key_bits.aes = 128;
241 in_public.public_area.parameters.sym_detail.sym.mode.aes = TPM_ALG_CFB;
242 in_public.public_area.unique.sym.size = 0;
243 TPM2B_DATA outside_info;
244 outside_info.size = 0;
245 TPML_PCR_SELECTION create_pcr;
246 create_pcr.count = 0;
247
248 TPM_HANDLE key_handle;
249 TPM2B_PUBLIC out_public;
250 TPM2B_CREATION_DATA creation_data;
251 TPM2B_DIGEST creation_hash;
252 TPMT_TK_CREATION creation_ticket;
253 TPM2B_NAME key_name;
254
255 Tpm tpm(&transceiver);
256 TPM_RC rc = tpm.CreatePrimarySync(
257 trunks::TPM_RH_NULL, "", in_sensitive, in_public, outside_info,
258 create_pcr, &key_handle, &out_public, &creation_data, &creation_hash,
259 &creation_ticket, &key_name, &authorization);
260 ASSERT_EQ(rc, TPM_RC_SUCCESS);
261 EXPECT_EQ(key_handle, 0x80000001);
262 EXPECT_EQ(out_public.size, sizeof(TPMT_PUBLIC));
263 EXPECT_EQ(creation_data.size, sizeof(TPMS_CREATION_DATA));
264 EXPECT_EQ(creation_hash.size, 1);
265 EXPECT_EQ(creation_hash.buffer[0], 'b');
266 EXPECT_EQ(creation_ticket.tag, 0x8002);
267 EXPECT_EQ(creation_ticket.hierarchy, 0x40000007u);
268 EXPECT_EQ(creation_ticket.digest.size, 0);
269 EXPECT_EQ(key_name.size, 3);
270 EXPECT_EQ(key_name.name[0], 'K');
271 EXPECT_EQ(key_name.name[1], 'E');
272 EXPECT_EQ(key_name.name[2], 'Y');
273 }
274
275 // A fixture for asynchronous command flow tests.
276 class CommandFlowTest : public testing::Test {
277 public:
CommandFlowTest()278 CommandFlowTest() : response_code_(TPM_RC_SUCCESS) {}
~CommandFlowTest()279 ~CommandFlowTest() override {}
280
StartupCallback(TPM_RC response_code)281 void StartupCallback(TPM_RC response_code) { response_code_ = response_code; }
282
CertifyCallback(TPM_RC response_code,const TPM2B_ATTEST & certify_info,const TPMT_SIGNATURE & signature)283 void CertifyCallback(TPM_RC response_code,
284 const TPM2B_ATTEST& certify_info,
285 const TPMT_SIGNATURE& signature) {
286 response_code_ = response_code;
287 signed_data_ = StringFrom_TPM2B_ATTEST(certify_info);
288 signature_ =
289 StringFrom_TPM2B_PUBLIC_KEY_RSA(signature.signature.rsassa.sig);
290 }
291
292 protected:
Run()293 void Run() {}
294
295 TPM_RC response_code_;
296 std::string signature_;
297 std::string signed_data_;
298 };
299
300 // A functor for posting command responses.
301 class PostResponse {
302 public:
PostResponse(const std::string & response)303 explicit PostResponse(const std::string& response) : response_(response) {}
operator ()(base::OnceCallback<void (const std::string &)> callback)304 void operator()(base::OnceCallback<void(const std::string&)> callback) {
305 std::move(callback).Run(response_);
306 }
307
308 private:
309 std::string response_;
310 };
311
312 // A functor to handle fake encryption / decryption of parameters.
313 class Encryptor {
314 public:
Encryptor(const std::string & expected_input,const std::string & output)315 Encryptor(const std::string& expected_input, const std::string& output)
316 : expected_input_(expected_input), output_(output) {}
operator ()(std::string * value)317 bool operator()(std::string* value) {
318 EXPECT_EQ(expected_input_, *value);
319 value->assign(output_);
320 return true;
321 }
322
323 private:
324 std::string expected_input_;
325 std::string output_;
326 };
327
TEST_F(CommandFlowTest,SimpleCommandFlow)328 TEST_F(CommandFlowTest, SimpleCommandFlow) {
329 // A hand-rolled TPM2_Startup command.
330 std::string expected_command(
331 "\x80\x01" // tag=TPM_ST_NO_SESSIONS
332 "\x00\x00\x00\x0C" // size=12
333 "\x00\x00\x01\x44" // code=TPM_CC_Startup
334 "\x00\x00", // param=TPM_SU_CLEAR
335 12);
336 std::string command_response(
337 "\x80\x01" // tag=TPM_ST_NO_SESSIONS
338 "\x00\x00\x00\x0A" // size=10
339 "\x00\x00\x00\x00", // code=TPM_RC_SUCCESS
340 10);
341 StrictMock<MockCommandTransceiver> transceiver;
342 EXPECT_CALL(transceiver, SendCommand(expected_command, _))
343 .WillOnce(WithArg<1>(Invoke(PostResponse(command_response))));
344 StrictMock<MockAuthorizationDelegate> authorization;
345 EXPECT_CALL(authorization, GetCommandAuthorization(_, _, _, _))
346 .WillOnce(Return(true));
347 Tpm tpm(&transceiver);
348 response_code_ = TPM_RC_FAILURE;
349 tpm.Startup(TPM_SU_CLEAR, &authorization,
350 std::function<void(TPM_RC)>([this](TPM_RC response_code) {
351 this->StartupCallback(response_code);
352 }));
353 Run();
354 EXPECT_EQ(TPM_RC_SUCCESS, response_code_);
355 }
356
TEST_F(CommandFlowTest,SimpleCommandFlowWithError)357 TEST_F(CommandFlowTest, SimpleCommandFlowWithError) {
358 // A hand-rolled TPM2_Startup command.
359 std::string expected_command(
360 "\x80\x01" // tag=TPM_ST_NO_SESSIONS
361 "\x00\x00\x00\x0C" // size=12
362 "\x00\x00\x01\x44" // code=TPM_CC_Startup
363 "\x00\x00", // param=TPM_SU_CLEAR
364 12);
365 std::string command_response(
366 "\x80\x01" // tag=TPM_ST_NO_SESSIONS
367 "\x00\x00\x00\x0A" // size=10
368 "\x00\x00\x01\x01", // code=TPM_RC_FAILURE
369 10);
370 StrictMock<MockCommandTransceiver> transceiver;
371 EXPECT_CALL(transceiver, SendCommand(expected_command, _))
372 .WillOnce(WithArg<1>(Invoke(PostResponse(command_response))));
373 StrictMock<MockAuthorizationDelegate> authorization;
374 EXPECT_CALL(authorization, GetCommandAuthorization(_, _, _, _))
375 .WillOnce(Return(true));
376 Tpm tpm(&transceiver);
377 tpm.Startup(TPM_SU_CLEAR, &authorization,
378 std::function<void(TPM_RC)>([this](TPM_RC response_code) {
379 this->StartupCallback(response_code);
380 }));
381 Run();
382 EXPECT_EQ(TPM_RC_FAILURE, response_code_);
383 }
384
385 // This test is designed to get good coverage of the different types of code
386 // generated for command / response processing. It covers:
387 // - input handles
388 // - authorization
389 // - multiple input and output parameters
390 // - parameter encryption and decryption
TEST_F(CommandFlowTest,FullCommandFlow)391 TEST_F(CommandFlowTest, FullCommandFlow) {
392 // A hand-rolled TPM2_Certify command.
393 std::string auth_in(10, 'A');
394 std::string auth_out(20, 'B');
395 std::string user_data(
396 "\x00\x0C"
397 "ct_user_data",
398 14);
399 std::string scheme("\x00\x10", 2); // scheme=TPM_ALG_NULL
400 std::string signed_data(
401 "\x00\x0E"
402 "ct_signed_data",
403 16);
404 std::string signature(
405 "\x00\x14" // sig_scheme=RSASSA
406 "\x00\x0B" // hash_scheme=SHA256
407 "\x00\x09" // signature size
408 "signature", // signature bytes
409 15);
410 std::string expected_command(
411 "\x80\x02" // tag=TPM_ST_SESSIONS
412 "\x00\x00\x00\x30" // size=48
413 "\x00\x00\x01\x48" // code=TPM_CC_Certify
414 "\x11\x22\x33\x44" // @objectHandle
415 "\x55\x66\x77\x88" // @signHandle
416 "\x00\x00\x00\x0A", // auth_size=10
417 22);
418 expected_command += auth_in + user_data + scheme;
419 std::string command_response(
420 "\x80\x02" // tag=TPM_ST_SESSIONS
421 "\x00\x00\x00\x41" // size=65
422 "\x00\x00\x00\x00" // code=TPM_RC_SUCCESS
423 "\x00\x00\x00\x1F", // param_size=31
424 14);
425 command_response += signed_data + signature + auth_out;
426
427 StrictMock<MockCommandTransceiver> transceiver;
428 EXPECT_CALL(transceiver, SendCommand(expected_command, _))
429 .WillOnce(WithArg<1>(Invoke(PostResponse(command_response))));
430 StrictMock<MockAuthorizationDelegate> authorization;
431 EXPECT_CALL(authorization, GetCommandAuthorization(_, _, _, _))
432 .WillOnce(DoAll(SetArgPointee<3>(auth_in), Return(true)));
433 EXPECT_CALL(authorization, CheckResponseAuthorization(_, auth_out))
434 .WillOnce(Return(true));
435 EXPECT_CALL(authorization, EncryptCommandParameter(_))
436 .WillOnce(Invoke(Encryptor("pt_user_data", "ct_user_data")));
437 EXPECT_CALL(authorization, DecryptResponseParameter(_))
438 .WillOnce(Invoke(Encryptor("ct_signed_data", "pt_signed_data")));
439
440 TPMT_SIG_SCHEME null_scheme;
441 null_scheme.scheme = TPM_ALG_NULL;
442 null_scheme.details.rsassa.hash_alg = TPM_ALG_SHA256;
443 Tpm tpm(&transceiver);
444 tpm.Certify(
445 0x11223344u, "object_handle", 0x55667788u, "sign_handle",
446 Make_TPM2B_DATA("pt_user_data"), null_scheme, &authorization,
447 std::function<void(TPM_RC, const TPM2B_ATTEST&, const TPMT_SIGNATURE&)>(
448 [this](TPM_RC response_code, const TPM2B_ATTEST& certify_info,
449 const TPMT_SIGNATURE& signature) {
450 this->CertifyCallback(response_code, certify_info, signature);
451 }));
452 Run();
453 ASSERT_EQ(TPM_RC_SUCCESS, response_code_);
454 EXPECT_EQ("pt_signed_data", signed_data_);
455 EXPECT_EQ("signature", signature_);
456 }
457
458 } // namespace trunks
459