Home | History | Annotate | Download | only in trunks
      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.
     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 
     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 
     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 
     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 
    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 
    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:
    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.
    298 class 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()->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:
    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 
    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 
    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
    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