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