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