1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "components/nacl/loader/nacl_validation_db.h" 6 #include "components/nacl/loader/nacl_validation_query.h" 7 #include "testing/gtest/include/gtest/gtest.h" 8 9 // This test makes sure that validation signature generation is performed 10 // correctly. In effect, this means that we are checking all of the data 11 // (and no other data) we are passing the signature generator affects the final 12 // signature. To avoid tying the tests to a particular implementation, each 13 // test generates two signatures and compares them rather than trying to compare 14 // against a specified signature. 15 16 namespace { 17 18 const char kKey[] = "bogus key for HMAC..."; 19 const char kKeyAlt[] = "bogus key for HMAC!!!"; 20 21 const char kVersion[] = "bogus version"; 22 const char kVersionAlt[] = "bogus!version"; 23 24 25 const char kShortData[] = "Short data 1234567890"; 26 const char kAltShortData[] = "Short!data 1234567890"; 27 28 const char kLongData[] = "Long data." 29 "1234567890123456789012345678901234567890123456789012345678901234567890" 30 "1234567890123456789012345678901234567890123456789012345678901234567890" 31 "1234567890123456789012345678901234567890123456789012345678901234567890" 32 "1234567890123456789012345678901234567890123456789012345678901234567890"; 33 34 class MockValidationDB : public NaClValidationDB { 35 public: 36 MockValidationDB() 37 : did_query_(false), 38 did_set_(false), 39 status_(true) { 40 } 41 42 virtual bool QueryKnownToValidate(const std::string& signature) OVERRIDE { 43 // The typecast is needed to work around gtest trying to take the address 44 // of a constant. 45 EXPECT_EQ((int) NaClValidationQuery::kDigestLength, 46 (int) signature.length()); 47 EXPECT_FALSE(did_query_); 48 EXPECT_FALSE(did_set_); 49 did_query_ = true; 50 memcpy(query_signature_, signature.data(), 51 NaClValidationQuery::kDigestLength); 52 return status_; 53 } 54 55 virtual void SetKnownToValidate(const std::string& signature) OVERRIDE { 56 // The typecast is needed to work around gtest trying to take the address 57 // of a constant. 58 ASSERT_EQ((int) NaClValidationQuery::kDigestLength, 59 (int) signature.length()); 60 EXPECT_TRUE(did_query_); 61 EXPECT_FALSE(did_set_); 62 did_set_ = true; 63 memcpy(set_signature_, signature.data(), 64 NaClValidationQuery::kDigestLength); 65 // Signatures should be the same. 66 EXPECT_EQ(0, memcmp(query_signature_, set_signature_, 67 NaClValidationQuery::kDigestLength)); 68 } 69 70 virtual bool ResolveFileToken(struct NaClFileToken* file_token, int32* fd, 71 std::string* path) OVERRIDE { 72 *fd = -1; 73 *path = ""; 74 return false; 75 } 76 77 bool did_query_; 78 bool did_set_; 79 bool status_; 80 81 uint8 query_signature_[NaClValidationQuery::kDigestLength]; 82 uint8 set_signature_[NaClValidationQuery::kDigestLength]; 83 }; 84 85 class TestQuery { 86 public: 87 TestQuery(const char* key, const char* version) { 88 db.reset(new MockValidationDB()); 89 context.reset(new NaClValidationQueryContext(db.get(), key, version)); 90 query.reset(context->CreateQuery()); 91 } 92 93 scoped_ptr<MockValidationDB> db; 94 scoped_ptr<NaClValidationQueryContext> context; 95 scoped_ptr<NaClValidationQuery> query; 96 }; 97 98 class NaClValidationQueryTest : public ::testing::Test { 99 protected: 100 scoped_ptr<TestQuery> query1; 101 scoped_ptr<TestQuery> query2; 102 103 virtual void SetUp() { 104 query1.reset(new TestQuery(kKey, kVersion)); 105 query2.reset(new TestQuery(kKey, kVersion)); 106 } 107 108 void AssertQuerySame() { 109 ASSERT_TRUE(query1->db->did_query_); 110 ASSERT_TRUE(query2->db->did_query_); 111 ASSERT_EQ(0, memcmp(query1->db->query_signature_, 112 query2->db->query_signature_, 113 NaClValidationQuery::kDigestLength)); 114 } 115 116 void AssertQueryDifferent() { 117 ASSERT_TRUE(query1->db->did_query_); 118 ASSERT_TRUE(query2->db->did_query_); 119 ASSERT_NE(0, memcmp(query1->db->query_signature_, 120 query2->db->query_signature_, 121 NaClValidationQuery::kDigestLength)); 122 } 123 }; 124 125 TEST_F(NaClValidationQueryTest, Sanity) { 126 query1->query->AddData(kShortData, sizeof(kShortData)); 127 ASSERT_FALSE(query1->db->did_query_); 128 ASSERT_FALSE(query1->db->did_set_); 129 ASSERT_EQ(1, query1->query->QueryKnownToValidate()); 130 ASSERT_TRUE(query1->db->did_query_); 131 ASSERT_FALSE(query1->db->did_set_); 132 query1->query->SetKnownToValidate(); 133 ASSERT_TRUE(query1->db->did_query_); 134 ASSERT_TRUE(query1->db->did_set_); 135 } 136 137 TEST_F(NaClValidationQueryTest, ConsistentShort) { 138 query1->query->AddData(kShortData, sizeof(kShortData)); 139 query1->query->QueryKnownToValidate(); 140 141 query2->query->AddData(kShortData, sizeof(kShortData)); 142 query2->query->QueryKnownToValidate(); 143 144 AssertQuerySame(); 145 } 146 147 TEST_F(NaClValidationQueryTest, InconsistentShort) { 148 query1->query->AddData(kShortData, sizeof(kShortData)); 149 query1->query->QueryKnownToValidate(); 150 151 query2->query->AddData(kAltShortData, sizeof(kAltShortData)); 152 query2->query->QueryKnownToValidate(); 153 154 AssertQueryDifferent(); 155 } 156 157 // Test for a bug caught during development where AddData would accidently 158 // overwrite previously written data and add uninitialzied memory to the hash. 159 TEST_F(NaClValidationQueryTest, ConsistentShortBug) { 160 query1->query->AddData(kShortData, sizeof(kShortData)); 161 query1->query->AddData(kShortData, sizeof(kShortData)); 162 query1->query->QueryKnownToValidate(); 163 164 query2->query->AddData(kShortData, sizeof(kShortData)); 165 query2->query->AddData(kShortData, sizeof(kShortData)); 166 query2->query->QueryKnownToValidate(); 167 168 AssertQuerySame(); 169 } 170 171 // Test for a bug caught during development where AddData would accidently 172 // overwrite previously written data and add uninitialzed memory to the hash. 173 TEST_F(NaClValidationQueryTest, InconsistentShortBug1) { 174 query1->query->AddData(kShortData, sizeof(kShortData)); 175 query1->query->AddData(kShortData, sizeof(kShortData)); 176 query1->query->QueryKnownToValidate(); 177 178 query2->query->AddData(kAltShortData, sizeof(kAltShortData)); 179 query2->query->AddData(kShortData, sizeof(kShortData)); 180 query2->query->QueryKnownToValidate(); 181 182 AssertQueryDifferent(); 183 } 184 185 // Make sure we don't ignore the second bit of data. 186 TEST_F(NaClValidationQueryTest, InconsistentShort2) { 187 query1->query->AddData(kShortData, sizeof(kShortData)); 188 query1->query->AddData(kShortData, sizeof(kShortData)); 189 query1->query->QueryKnownToValidate(); 190 191 query2->query->AddData(kShortData, sizeof(kShortData)); 192 query2->query->AddData(kAltShortData, sizeof(kAltShortData)); 193 query2->query->QueryKnownToValidate(); 194 195 AssertQueryDifferent(); 196 } 197 198 TEST_F(NaClValidationQueryTest, InconsistentZeroSizedAdd) { 199 query1->query->AddData(kShortData, sizeof(kShortData)); 200 query1->query->QueryKnownToValidate(); 201 202 query2->query->AddData(kShortData, sizeof(kShortData)); 203 query2->query->AddData(kShortData, 0); 204 query2->query->QueryKnownToValidate(); 205 206 AssertQueryDifferent(); 207 } 208 209 TEST_F(NaClValidationQueryTest, ConsistentZeroSizedAdd) { 210 query1->query->AddData(kShortData, sizeof(kShortData)); 211 query1->query->AddData("a", 0); 212 query1->query->QueryKnownToValidate(); 213 214 query2->query->AddData(kShortData, sizeof(kShortData)); 215 query2->query->AddData("b", 0); 216 query2->query->QueryKnownToValidate(); 217 218 AssertQuerySame(); 219 } 220 221 TEST_F(NaClValidationQueryTest, ConsistentRepeatedShort) { 222 for (int i = 0; i < 30; i++) { 223 query1->query->AddData(kShortData, sizeof(kShortData)); 224 } 225 query1->query->QueryKnownToValidate(); 226 227 for (int i = 0; i < 30; i++) { 228 query2->query->AddData(kShortData, sizeof(kShortData)); 229 } 230 query2->query->QueryKnownToValidate(); 231 232 AssertQuerySame(); 233 } 234 235 TEST_F(NaClValidationQueryTest, ConsistentLong) { 236 query1->query->AddData(kLongData, sizeof(kLongData)); 237 query1->query->QueryKnownToValidate(); 238 239 query2->query->AddData(kLongData, sizeof(kLongData)); 240 query2->query->QueryKnownToValidate(); 241 242 AssertQuerySame(); 243 } 244 245 TEST_F(NaClValidationQueryTest, ConsistentRepeatedLong) { 246 for (int i = 0; i < 30; i++) { 247 query1->query->AddData(kLongData, sizeof(kLongData)); 248 } 249 query1->query->QueryKnownToValidate(); 250 251 for (int i = 0; i < 30; i++) { 252 query2->query->AddData(kLongData, sizeof(kLongData)); 253 } 254 query2->query->QueryKnownToValidate(); 255 256 AssertQuerySame(); 257 } 258 259 TEST_F(NaClValidationQueryTest, PerturbKey) { 260 query2.reset(new TestQuery(kKeyAlt, kVersion)); 261 262 query1->query->AddData(kShortData, sizeof(kShortData)); 263 query1->query->QueryKnownToValidate(); 264 265 query2->query->AddData(kShortData, sizeof(kShortData)); 266 query2->query->QueryKnownToValidate(); 267 268 AssertQueryDifferent(); 269 } 270 271 TEST_F(NaClValidationQueryTest, PerturbVersion) { 272 query2.reset(new TestQuery(kKey, kVersionAlt)); 273 274 query1->query->AddData(kShortData, sizeof(kShortData)); 275 query1->query->QueryKnownToValidate(); 276 277 query2->query->AddData(kShortData, sizeof(kShortData)); 278 query2->query->QueryKnownToValidate(); 279 280 AssertQueryDifferent(); 281 } 282 283 } 284