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