Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(19)

Side by Side Diff: crypto/cup_unittest.cc

Issue 15793005: Per discussion, implement the Omaha Client Update Protocol (CUP) in src/crypto. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« crypto/cup_nss.cc ('K') | « crypto/cup_openssl.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 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 <limits>
6 #include <vector>
7
8 #include "base/sha1.h"
9 #include "crypto/cup.h"
10 #include "crypto/random.h"
11 #include "crypto/secure_util.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 namespace {
15
16 // How to generate this key:
17 // openssl genpkey -out cr.pem -outform PEM -algorithm RSA
18 // -pkeyopt rsa_keygen_pubexp:3
19 // openssl rsa -in cr.pem -pubout -out cr_pub.pem
20
21 const char kCupTestKey1024PEM[] =
22 "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC7ct1JhLSol2DkBcJdNjR3KkEA"
23 "ZfXpF22lDD2WZu5JAZ4NiZqnHsKGJNPUbCH4AhFsXmuW5wEHhUVNhsMP6F9mQ06D"
24 "i+ygwZ8aXlklmW4S0Et+SNg3i73fnYn0KDQzrzJnMu46s/CFPhjr4f0TH9b7oHkU"
25 "XbqNZtG6gwaN1bmzFwIBAw==";
26
27 const size_t kRsaKeySize = 128;
28
29 } // end namespace
30
31 #if defined(USE_OPENSSL)
32
33 // Once CUP is implemented for OpenSSL, remove this #if block.
34 TEST(CupUnitTest, OpenSSLStub) {
35 crypto::ClientUpdateProtocol cup;
36 EXPECT_FALSE(cup.Init(8, kCupTestKey1024PEM));
37 }
38
39 #else
40
41 namespace crypto {
42
43 class CupUnitTest : public testing::Test {
44 protected:
45 virtual void SetUp() {
46 // How to generate this key:
47 // openssl genpkey -out cr.pem -outform PEM -algorithm RSA
48 // -pkeyopt rsa_keygen_pubexp:3
49 // openssl rsa -in cr.pem -pubout -out cr_pub.pem
50
51 EXPECT_TRUE(cup_.Init(8, kCupTestKey1024PEM));
52 }
53
54 // Test RsaPad for a random message of num_bytes length.
55 void TestRsaPad(size_t num_bytes) {
56 std::vector<uint8> data(num_bytes);
57 crypto::RandBytes(&data.front(), data.size());
58
59 std::vector<uint8> m = ClientUpdateProtocol::RsaPad(kRsaKeySize, data);
60 ASSERT_EQ(m.size(), kRsaKeySize);
61
62 std::vector<uint8> hash(base::kSHA1Length);
63 base::SHA1HashBytes(&m.front(),
64 static_cast<int>(m.size() - base::kSHA1Length),
65 &hash.front());
66
67 EXPECT_TRUE(SecureMemEqual(&hash.front(),
68 &m[kRsaKeySize - base::kSHA1Length],
69 base::kSHA1Length));
70
71 EXPECT_FALSE(m[0] & 0x80); // msb is always reset.
72 EXPECT_TRUE(m[0] & 0x60); // bit next to msb is always set.
73 }
74
75 void TestUrlSafeB64Encode(const char* expected_input, const char* input) {
76 std::string expected(expected_input);
77 EXPECT_EQ(expected, UrlSafeB64Encode(reinterpret_cast<const uint8*>(input),
78 strlen(input)));
79 }
80
81 std::string UrlSafeB64Encode(const uint8* in_bytes, size_t length) {
82 std::vector<uint8> in(in_bytes, in_bytes + length);
83 return ClientUpdateProtocol::UrlSafeB64Encode(in);
84 }
85
86 std::vector<uint8> HashBin(const base::StringPiece& in_str) {
87 return ClientUpdateProtocol::Hash(in_str);
88 }
89
90 std::string Hash(const std::vector<uint8>& in_bytes) {
91 return BytesToHex(ClientUpdateProtocol::Hash(in_bytes));
92 }
93
94 std::string Hash(const base::StringPiece& in_str) {
95 return BytesToHex(ClientUpdateProtocol::Hash(in_str));
96 }
97
98 std::string SymSign(const std::vector<uint8>& key,
99 uint8 id,
100 const std::vector<uint8>* h1,
101 const std::vector<uint8>* h2,
102 const std::vector<uint8>* h3) {
103 return BytesToHex(ClientUpdateProtocol::SymSign(key, id, h1, h2, h3));
104 }
105
106 std::vector<uint8> SymSignRaw(const std::vector<uint8>& key,
107 uint8 id,
108 const std::vector<uint8>* h1,
109 const std::vector<uint8>* h2,
110 const std::vector<uint8>* h3) {
111 return ClientUpdateProtocol::SymSign(key, id, h1, h2, h3);
112 }
113
114 std::string BytesToHex(const std::vector<uint8>& bytes) {
115 std::string result;
116 if (bytes.size() < std::numeric_limits<size_t>::max() / 2) {
117 static const char kHexChars[] = "0123456789abcdef";
118 for (size_t i = 0; i < bytes.size(); ++i) {
119 result.push_back(kHexChars[(bytes[i] >> 4)]);
120 result.push_back(kHexChars[(bytes[i] & 0xf)]);
121 }
122 }
123 return result;
124 }
125
126 void OverrideRAndRebuildKeys() {
127 static const char kFixedR[] =
128 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
129 "eiusmod tempor incididunt ut labore et dolore magna aliqua. ";
130
131 const std::string plaintext(kFixedR);
132 cup_.r_.assign(plaintext.begin(), plaintext.end());
133 EXPECT_TRUE(cup_.BuildSharedKey());
134 }
135
136 const std::string& ExamineVW() {
137 return cup_.vw_;
138 }
139
140 ClientUpdateProtocol& GetCup() {
141 return cup_;
142 }
143
144
145 private:
146 ClientUpdateProtocol cup_;
147 };
148
149 TEST_F(CupUnitTest, RsaPad) {
150 ASSERT_GE(kRsaKeySize, base::kSHA1Length);
151
152 TestRsaPad(1); // 1 byte.
153 TestRsaPad(base::kSHA1Length); // 20 bytes.
154 TestRsaPad(kRsaKeySize); // 128 bytes.
155 TestRsaPad(1000); // 1000 bytes.
156 }
157
158 TEST_F(CupUnitTest, B64Encode) {
159 TestUrlSafeB64Encode("MQ", "1");
160 TestUrlSafeB64Encode("MTI", "12");
161 TestUrlSafeB64Encode("MTIz", "123");
162 TestUrlSafeB64Encode("PHA-SGk_PC9wPg", "<p>Hi?</p>");
163 TestUrlSafeB64Encode("R29vZ2xlIEluYw", "Google Inc");
164 }
165
166 TEST_F(CupUnitTest, Hash) {
167 static const char kPlainText[] =
168 "The quick brown fox jumps over the lazy dog";
169
170 // Empty vector.
171 std::vector<uint8> data;
172 EXPECT_EQ("da39a3ee5e6b4b0d3255bfef95601890afd80709",
173 Hash(data));
174
175 // Non-empty vector.
176 const uint8* first = reinterpret_cast<const uint8*>(kPlainText);
177 const uint8* last = first + strlen(kPlainText);
178 data.clear();
179 data.insert(data.begin(), first, last);
180 EXPECT_EQ("2fd4e1c67a2d28fced849ee1bb76e7391b93eb12",
181 Hash(data));
182
183 // Empty string.
184 EXPECT_EQ("da39a3ee5e6b4b0d3255bfef95601890afd80709",
185 Hash(std::string()));
186
187 // Non-empty string.
188 EXPECT_EQ("2fd4e1c67a2d28fced849ee1bb76e7391b93eb12",
189 Hash(std::string(kPlainText)));
190 }
191
192 TEST_F(CupUnitTest, SymSign) {
193 static const char kPlainText[] =
194 "The quick brown fox jumps over the lazy dog";
195
196 std::vector<uint8> key;
197 key.push_back(7);
198
199 std::vector<uint8> hash = HashBin(std::string(kPlainText));
200
201 // Verify that NULL buffers are not included in the hash.
202 EXPECT_EQ("1c6fa359c0a7b11421ae4d31a92f9de8a4ef8d2d",
203 SymSign(key, 1, &hash, NULL, NULL));
204 EXPECT_EQ("1c6fa359c0a7b11421ae4d31a92f9de8a4ef8d2d",
205 SymSign(key, 1, NULL, &hash, NULL));
206 EXPECT_EQ("1c6fa359c0a7b11421ae4d31a92f9de8a4ef8d2d",
207 SymSign(key, 1, NULL, &hash, NULL));
208
209 // Verify that all three buffers are included in the hash.
210 EXPECT_EQ("fef3e343795946cd47ff4e07eca5f3f09b051d86",
211 SymSign(key, 1, &hash, &hash, &hash));
212 }
213
214 TEST_F(CupUnitTest, EncryptSharedKey) {
215 // Given a fixed public key set in our test fixture, if we override (r) with
216 // a known data, we should be able to test (w) against an expected output.
217 //
218 // This expected output can be generated using this command line, where
219 // plaintext.bin is the contents of kFixedR[] in OverrideRAndRebuildKeys():
220 //
221 // openssl rsautl -inkey cr2_pub.pem -pubin -encrypt -raw
222 // -in plaintext.bin | base64
223 //
224 // Remember to prepend the key version number, and fix up the Base64
225 // afterwards to be URL-safe.
226
227 static const char kExpectedVW[] =
228 "8:lMmNR3mVbOitbq8ceYGStFBwrJcpvY-sauFSbMVe6VONS9x42xTOLY_KdqsWCy"
229 "KuiJBiQziQLOybPUyA9vk0N5kMnC90LIh2nP2FgFG0M0Z22qjB3drsdJPi7TQZbb"
230 "Xhqm587M8vjc6VlM_eoC0qYwCPaXBqXjsyiHnXetcn5X0";
231
232 EXPECT_NE(kExpectedVW, ExamineVW());
233 OverrideRAndRebuildKeys();
234 EXPECT_EQ(kExpectedVW, ExamineVW());
235 }
236
237 TEST_F(CupUnitTest, SignRequest) {
238 static const char kUrlHost[] = "testserver.chromium.org";
239 static const char kUrlPath[] = "update";
240 static const char kUrlQuery[] = "?junk=present";
241 static const char kRequest[] = "testbody";
242
243 static const char kExpectedCP[] = "hIxzNIHv4pg03NcXPLuATX8G2SI";
244
245 OverrideRAndRebuildKeys();
246
247 std::string cup_query;
248 std::string cp;
249
250 // Check the case with a preexisting query string.
251 EXPECT_TRUE(GetCup().SignRequest(kUrlHost, kUrlPath, kUrlQuery, kRequest,
252 &cup_query, &cp));
253
254 std::string expected_query(kUrlQuery);
255 expected_query.append("&w=");
256 expected_query.append(ExamineVW());
257 EXPECT_EQ(expected_query, cup_query);
258 EXPECT_EQ(kExpectedCP, cp);
259
260 // Check the case with no query string.
261 std::string cp2;
262 EXPECT_TRUE(GetCup().SignRequest(kUrlHost, kUrlPath, std::string(), kRequest,
263 &cup_query, &cp2));
264 expected_query = "?w=";
265 expected_query.append(ExamineVW());
266 EXPECT_EQ(expected_query, cup_query);
267
268 // Changes in the URL should result in changes in the client proof.
269 EXPECT_NE(cp, cp2);
270 }
271
272 TEST_F(CupUnitTest, ValidateResponse) {
273 static const char kUrlHost[] = "testserver.chromium.org";
274 static const char kUrlPath[] = "update";
275 static const char kUrlQuery[] = "?junk=present";
276 static const char kRequest[] = "testbody";
277
278 static const char kGoodResponse[] = "intact_response";
279 static const char kGoodC[] = "c=EncryptedDataFromTheUpdateServer";
280 static const char kGoodSP[] = "5rMFMPL9Hgqb-2J8kL3scsHeNgg";
281
282 static const char kBadResponse[] = "tampered_response";
283 static const char kBadC[] = "c=TotalJunkThatAnAttackerCouldSend";
284 static const char kBadSP[] = "Base64TamperedShaOneHash";
285
286 OverrideRAndRebuildKeys();
287
288 // We should return false if no calls to SignRequest() have been made.
289 EXPECT_FALSE(GetCup().ValidateResponse(kGoodResponse, kGoodC, kGoodSP));
290
291 EXPECT_TRUE(GetCup().SignRequest(kUrlHost, kUrlPath, kUrlQuery, kRequest,
292 NULL, NULL));
293
294 // Return true on a valid response and server proof.
295 EXPECT_TRUE(GetCup().ValidateResponse(kGoodResponse, kGoodC, kGoodSP));
296
297 // Return false on anything invalid.
298 EXPECT_FALSE(GetCup().ValidateResponse(kBadResponse, kGoodC, kGoodSP));
299 EXPECT_FALSE(GetCup().ValidateResponse(kGoodResponse, kBadC, kGoodSP));
300 EXPECT_FALSE(GetCup().ValidateResponse(kGoodResponse, kGoodC, kBadSP));
301 EXPECT_FALSE(GetCup().ValidateResponse(kGoodResponse, kBadC, kBadSP));
302 EXPECT_FALSE(GetCup().ValidateResponse(kBadResponse, kGoodC, kBadSP));
303 EXPECT_FALSE(GetCup().ValidateResponse(kBadResponse, kBadC, kGoodSP));
304 EXPECT_FALSE(GetCup().ValidateResponse(kBadResponse, kBadC, kBadSP));
305 }
306
307 } // namespace crypto
308
309 #endif // !defined(USE_OPENSSL)
310
OLDNEW
« crypto/cup_nss.cc ('K') | « crypto/cup_openssl.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698