tpm_generated_test.cc revision 3e1217d9b8b9d0bd549f202e5f1a528374872b40
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