ExtensionInstallDialogView: fix scrolling behavior on Views (Win,Linux)
[chromium-blink-merge.git] / components / webcrypto / test / ecdh_unittest.cc
blobbf86f832139447804b234cec07f7cf7ce711e89a
1 // Copyright 2014 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.
5 #include "base/stl_util.h"
6 #include "components/webcrypto/algorithm_dispatch.h"
7 #include "components/webcrypto/crypto_data.h"
8 #include "components/webcrypto/jwk.h"
9 #include "components/webcrypto/status.h"
10 #include "components/webcrypto/test/test_helpers.h"
11 #include "components/webcrypto/webcrypto_util.h"
12 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
13 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
15 namespace webcrypto {
17 namespace {
19 bool SupportsEcdh() {
20 #if defined(USE_OPENSSL)
21 return true;
22 #else
23 LOG(ERROR) << "Skipping ECDH test because unsupported";
24 return false;
25 #endif
28 // TODO(eroman): Test passing an RSA public key instead of ECDH key.
29 // TODO(eroman): Test passing an ECDSA public key
31 blink::WebCryptoAlgorithm CreateEcdhImportAlgorithm(
32 blink::WebCryptoNamedCurve named_curve) {
33 return CreateEcImportAlgorithm(blink::WebCryptoAlgorithmIdEcdh, named_curve);
36 blink::WebCryptoAlgorithm CreateEcdhDeriveParams(
37 const blink::WebCryptoKey& public_key) {
38 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
39 blink::WebCryptoAlgorithmIdEcdh,
40 new blink::WebCryptoEcdhKeyDeriveParams(public_key));
43 blink::WebCryptoAlgorithm CreateAesGcmDerivedKeyParams(
44 unsigned short length_bits) {
45 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
46 blink::WebCryptoAlgorithmIdAesGcm,
47 new blink::WebCryptoAesDerivedKeyParams(length_bits));
50 // Helper that loads a "public_key" and "private_key" from the test data.
51 bool ImportKeysFromTest(const base::DictionaryValue* test,
52 blink::WebCryptoKey* public_key,
53 blink::WebCryptoKey* private_key) {
54 // Import the public key.
55 const base::DictionaryValue* public_key_json = NULL;
56 EXPECT_TRUE(test->GetDictionary("public_key", &public_key_json));
57 blink::WebCryptoNamedCurve curve =
58 GetCurveNameFromDictionary(public_key_json);
59 EXPECT_EQ(Status::Success(),
60 ImportKey(blink::WebCryptoKeyFormatJwk,
61 CryptoData(MakeJsonVector(*public_key_json)),
62 CreateEcdhImportAlgorithm(curve), true, 0, public_key));
64 // If the test didn't specify an error for private key import, that implies
65 // it expects success.
66 std::string expected_private_key_error = "Success";
67 test->GetString("private_key_error", &expected_private_key_error);
69 // Import the private key.
70 const base::DictionaryValue* private_key_json = NULL;
71 EXPECT_TRUE(test->GetDictionary("private_key", &private_key_json));
72 curve = GetCurveNameFromDictionary(private_key_json);
73 Status status = ImportKey(
74 blink::WebCryptoKeyFormatJwk,
75 CryptoData(MakeJsonVector(*private_key_json)),
76 CreateEcdhImportAlgorithm(curve), true,
77 blink::WebCryptoKeyUsageDeriveBits | blink::WebCryptoKeyUsageDeriveKey,
78 private_key);
79 EXPECT_EQ(expected_private_key_error, StatusToString(status));
80 return status.IsSuccess();
83 TEST(WebCryptoEcdhTest, DeriveBitsKnownAnswer) {
84 if (!SupportsEcdh())
85 return;
87 scoped_ptr<base::ListValue> tests;
88 ASSERT_TRUE(ReadJsonTestFileToList("ecdh.json", &tests));
90 for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
91 SCOPED_TRACE(test_index);
93 const base::DictionaryValue* test;
94 ASSERT_TRUE(tests->GetDictionary(test_index, &test));
96 // Import the keys.
97 blink::WebCryptoKey public_key;
98 blink::WebCryptoKey private_key;
99 if (!ImportKeysFromTest(test, &public_key, &private_key))
100 continue;
102 // Now try to derive bytes.
103 std::vector<uint8_t> derived_bytes;
104 int length_bits = 0;
105 ASSERT_TRUE(test->GetInteger("length_bits", &length_bits));
107 // If the test didn't specify an error, that implies it expects success.
108 std::string expected_error = "Success";
109 test->GetString("error", &expected_error);
111 Status status = DeriveBits(CreateEcdhDeriveParams(public_key), private_key,
112 length_bits, &derived_bytes);
113 ASSERT_EQ(expected_error, StatusToString(status));
114 if (status.IsError())
115 continue;
117 std::vector<uint8_t> expected_bytes =
118 GetBytesFromHexString(test, "derived_bytes");
120 EXPECT_EQ(CryptoData(expected_bytes), CryptoData(derived_bytes));
124 // Loads up a test ECDH public and private key for P-521. The keys
125 // come from different key pairs, and can be used for key derivation of up to
126 // 528 bits.
127 ::testing::AssertionResult LoadTestKeys(blink::WebCryptoKey* public_key,
128 blink::WebCryptoKey* private_key) {
129 scoped_ptr<base::ListValue> tests;
130 if (!ReadJsonTestFileToList("ecdh.json", &tests))
131 return ::testing::AssertionFailure() << "Failed loading ecdh.json";
133 const base::DictionaryValue* test = NULL;
134 bool valid_p521_keys = false;
135 for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
136 SCOPED_TRACE(test_index);
137 EXPECT_TRUE(tests->GetDictionary(test_index, &test));
138 test->GetBoolean("valid_p521_keys", &valid_p521_keys);
139 if (valid_p521_keys)
140 break;
142 if (!valid_p521_keys) {
143 return ::testing::AssertionFailure()
144 << "The P-521 test are missing in ecdh.json";
147 ImportKeysFromTest(test, public_key, private_key);
149 EXPECT_EQ(blink::WebCryptoNamedCurveP521,
150 public_key->algorithm().ecParams()->namedCurve());
152 return ::testing::AssertionSuccess();
155 // Try deriving an AES key of length 129 bits.
156 TEST(WebCryptoEcdhTest, DeriveKeyBadAesLength) {
157 if (!SupportsEcdh())
158 return;
160 blink::WebCryptoKey public_key;
161 blink::WebCryptoKey base_key;
162 ASSERT_TRUE(LoadTestKeys(&public_key, &base_key));
164 blink::WebCryptoKey derived_key;
166 ASSERT_EQ(Status::ErrorGetAesKeyLength(),
167 DeriveKey(CreateEcdhDeriveParams(public_key), base_key,
168 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesGcm),
169 CreateAesGcmDerivedKeyParams(129), true,
170 blink::WebCryptoKeyUsageEncrypt, &derived_key));
173 // Try deriving an AES key of length 192 bits.
174 TEST(WebCryptoEcdhTest, DeriveKeyUnsupportedAesLength) {
175 if (!SupportsEcdh())
176 return;
178 blink::WebCryptoKey public_key;
179 blink::WebCryptoKey base_key;
180 ASSERT_TRUE(LoadTestKeys(&public_key, &base_key));
182 blink::WebCryptoKey derived_key;
184 ASSERT_EQ(Status::ErrorAes192BitUnsupported(),
185 DeriveKey(CreateEcdhDeriveParams(public_key), base_key,
186 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesGcm),
187 CreateAesGcmDerivedKeyParams(192), true,
188 blink::WebCryptoKeyUsageEncrypt, &derived_key));
191 // Try deriving an HMAC key of length 0 bits.
192 TEST(WebCryptoEcdhTest, DeriveKeyZeroLengthHmac) {
193 if (!SupportsEcdh())
194 return;
196 blink::WebCryptoKey public_key;
197 blink::WebCryptoKey base_key;
198 ASSERT_TRUE(LoadTestKeys(&public_key, &base_key));
200 blink::WebCryptoKey derived_key;
202 const blink::WebCryptoAlgorithm import_algorithm =
203 CreateHmacImportAlgorithm(blink::WebCryptoAlgorithmIdSha1, 0);
205 ASSERT_EQ(Status::ErrorGetHmacKeyLengthZero(),
206 DeriveKey(CreateEcdhDeriveParams(public_key), base_key,
207 import_algorithm, import_algorithm, true,
208 blink::WebCryptoKeyUsageSign, &derived_key));
211 // Derive an HMAC key of length 19 bits.
212 TEST(WebCryptoEcdhTest, DeriveKeyHmac19Bits) {
213 if (!SupportsEcdh())
214 return;
216 blink::WebCryptoKey public_key;
217 blink::WebCryptoKey base_key;
218 ASSERT_TRUE(LoadTestKeys(&public_key, &base_key));
220 blink::WebCryptoKey derived_key;
222 const blink::WebCryptoAlgorithm import_algorithm =
223 CreateHmacImportAlgorithm(blink::WebCryptoAlgorithmIdSha1, 19);
225 ASSERT_EQ(Status::Success(),
226 DeriveKey(CreateEcdhDeriveParams(public_key), base_key,
227 import_algorithm, import_algorithm, true,
228 blink::WebCryptoKeyUsageSign, &derived_key));
230 ASSERT_EQ(blink::WebCryptoAlgorithmIdHmac, derived_key.algorithm().id());
231 ASSERT_EQ(blink::WebCryptoAlgorithmIdSha1,
232 derived_key.algorithm().hmacParams()->hash().id());
233 ASSERT_EQ(19u, derived_key.algorithm().hmacParams()->lengthBits());
235 // Export the key and verify its contents.
236 std::vector<uint8_t> raw_key;
237 EXPECT_EQ(Status::Success(),
238 ExportKey(blink::WebCryptoKeyFormatRaw, derived_key, &raw_key));
239 EXPECT_EQ(3u, raw_key.size());
240 // The last 7 bits of the key should be zero.
241 EXPECT_EQ(0, raw_key[raw_key.size() - 1] & 0x1f);
244 // Derive an HMAC key with no specified length (just the hash of SHA-256).
245 TEST(WebCryptoEcdhTest, DeriveKeyHmacSha256NoLength) {
246 if (!SupportsEcdh())
247 return;
249 blink::WebCryptoKey public_key;
250 blink::WebCryptoKey base_key;
251 ASSERT_TRUE(LoadTestKeys(&public_key, &base_key));
253 blink::WebCryptoKey derived_key;
255 const blink::WebCryptoAlgorithm import_algorithm =
256 CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha256);
258 ASSERT_EQ(Status::Success(),
259 DeriveKey(CreateEcdhDeriveParams(public_key), base_key,
260 import_algorithm, import_algorithm, true,
261 blink::WebCryptoKeyUsageSign, &derived_key));
263 ASSERT_EQ(blink::WebCryptoAlgorithmIdHmac, derived_key.algorithm().id());
264 ASSERT_EQ(blink::WebCryptoAlgorithmIdSha256,
265 derived_key.algorithm().hmacParams()->hash().id());
266 ASSERT_EQ(512u, derived_key.algorithm().hmacParams()->lengthBits());
268 // Export the key and verify its contents.
269 std::vector<uint8_t> raw_key;
270 EXPECT_EQ(Status::Success(),
271 ExportKey(blink::WebCryptoKeyFormatRaw, derived_key, &raw_key));
272 EXPECT_EQ(64u, raw_key.size());
275 // Derive an HMAC key with no specified length (just the hash of SHA-512).
277 // This fails, because ECDH using P-521 can only generate 528 bits, however HMAC
278 // SHA-512 requires 1024 bits.
280 // In practice, authors won't be directly generating keys from key agreement
281 // schemes, as that is frequently insecure, and instead be using KDFs to expand
282 // and generate keys. For simplicity of testing, however, test using an HMAC
283 // key.
284 TEST(WebCryptoEcdhTest, DeriveKeyHmacSha512NoLength) {
285 if (!SupportsEcdh())
286 return;
288 blink::WebCryptoKey public_key;
289 blink::WebCryptoKey base_key;
290 ASSERT_TRUE(LoadTestKeys(&public_key, &base_key));
292 blink::WebCryptoKey derived_key;
294 const blink::WebCryptoAlgorithm import_algorithm =
295 CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha512);
297 ASSERT_EQ(Status::ErrorEcdhLengthTooBig(528),
298 DeriveKey(CreateEcdhDeriveParams(public_key), base_key,
299 import_algorithm, import_algorithm, true,
300 blink::WebCryptoKeyUsageSign, &derived_key));
303 // Try deriving an AES key of length 128 bits.
304 TEST(WebCryptoEcdhTest, DeriveKeyAes128) {
305 if (!SupportsEcdh())
306 return;
308 blink::WebCryptoKey public_key;
309 blink::WebCryptoKey base_key;
310 ASSERT_TRUE(LoadTestKeys(&public_key, &base_key));
312 blink::WebCryptoKey derived_key;
314 ASSERT_EQ(Status::Success(),
315 DeriveKey(CreateEcdhDeriveParams(public_key), base_key,
316 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesGcm),
317 CreateAesGcmDerivedKeyParams(128), true,
318 blink::WebCryptoKeyUsageEncrypt, &derived_key));
320 ASSERT_EQ(blink::WebCryptoAlgorithmIdAesGcm, derived_key.algorithm().id());
321 ASSERT_EQ(128, derived_key.algorithm().aesParams()->lengthBits());
323 // Export the key and verify its contents.
324 std::vector<uint8_t> raw_key;
325 EXPECT_EQ(Status::Success(),
326 ExportKey(blink::WebCryptoKeyFormatRaw, derived_key, &raw_key));
327 EXPECT_EQ(16u, raw_key.size());
330 TEST(WebCryptoEcdhTest, ImportKeyEmptyUsage) {
331 if (!SupportsEcdh())
332 return;
334 blink::WebCryptoKey key;
336 scoped_ptr<base::ListValue> tests;
337 ASSERT_TRUE(ReadJsonTestFileToList("ecdh.json", &tests));
339 const base::DictionaryValue* test;
340 ASSERT_TRUE(tests->GetDictionary(0, &test));
342 // Import the public key.
343 const base::DictionaryValue* public_key_json = NULL;
344 EXPECT_TRUE(test->GetDictionary("public_key", &public_key_json));
345 blink::WebCryptoNamedCurve curve =
346 GetCurveNameFromDictionary(public_key_json);
347 ASSERT_EQ(Status::Success(),
348 ImportKey(blink::WebCryptoKeyFormatJwk,
349 CryptoData(MakeJsonVector(*public_key_json)),
350 CreateEcdhImportAlgorithm(curve), true, 0, &key));
351 EXPECT_EQ(0, key.usages());
353 // Import the private key.
354 const base::DictionaryValue* private_key_json = NULL;
355 EXPECT_TRUE(test->GetDictionary("private_key", &private_key_json));
356 curve = GetCurveNameFromDictionary(private_key_json);
357 ASSERT_EQ(Status::ErrorCreateKeyEmptyUsages(),
358 ImportKey(blink::WebCryptoKeyFormatJwk,
359 CryptoData(MakeJsonVector(*private_key_json)),
360 CreateEcdhImportAlgorithm(curve), true, 0, &key));
363 } // namespace
365 } // namespace webcrypto