tpm_generated_test.cc revision a2ea1493759120ba0456825efe27806c491971b7
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
29using testing::_;
30using testing::DoAll;
31using testing::Invoke;
32using testing::Return;
33using testing::SetArgPointee;
34using testing::StrictMock;
35using testing::WithArg;
36
37namespace 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.
41TEST(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
71TEST(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
78TEST(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
92TEST(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
115TEST(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
138TEST(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.
266class CommandFlowTest : public testing::Test {
267 public:
268  CommandFlowTest() : response_code_(TPM_RC_SUCCESS) {}
269  ~CommandFlowTest() override {}
270
271  void StartupCallback(TPM_RC response_code) { response_code_ = response_code; }
272
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:
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.
298class PostResponse {
299 public:
300  explicit PostResponse(const std::string& response) : response_(response) {}
301  void operator()(const base::Callback<void(const std::string&)>& callback) {
302    base::MessageLoop::current()->task_runner()->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.
311class Encryptor {
312 public:
313  Encryptor(const std::string& expected_input, const std::string& output)
314      : expected_input_(expected_input), output_(output) {}
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
326TEST_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
354TEST_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
387TEST_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