| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/child/webcrypto/shared_crypto.h" | 5 #include "content/child/webcrypto/shared_crypto.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 522 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 533 const blink::WebArrayBuffer& json) { | 533 const blink::WebArrayBuffer& json) { |
| 534 base::StringPiece json_string(reinterpret_cast<const char*>(json.data()), | 534 base::StringPiece json_string(reinterpret_cast<const char*>(json.data()), |
| 535 json.byteLength()); | 535 json.byteLength()); |
| 536 base::Value* value = base::JSONReader::Read(json_string); | 536 base::Value* value = base::JSONReader::Read(json_string); |
| 537 EXPECT_TRUE(value); | 537 EXPECT_TRUE(value); |
| 538 base::DictionaryValue* dict_value = NULL; | 538 base::DictionaryValue* dict_value = NULL; |
| 539 value->GetAsDictionary(&dict_value); | 539 value->GetAsDictionary(&dict_value); |
| 540 return scoped_ptr<base::DictionaryValue>(dict_value); | 540 return scoped_ptr<base::DictionaryValue>(dict_value); |
| 541 } | 541 } |
| 542 | 542 |
| 543 // Verifies that the JSON in the input ArrayBuffer contains the provided | 543 // Verifies the input dictionary contains the expected values. Exact matches are |
| 544 // expected values. Exact matches are required on the fields examined. | 544 // required on the fields examined. |
| 545 ::testing::AssertionResult VerifySymmetricJwk( | 545 ::testing::AssertionResult VerifyJwk( |
| 546 const blink::WebArrayBuffer& json, | 546 const scoped_ptr<base::DictionaryValue>& dict, |
| 547 const std::string& kty_expected, |
| 547 const std::string& alg_expected, | 548 const std::string& alg_expected, |
| 548 const std::string& k_expected_hex, | |
| 549 blink::WebCryptoKeyUsageMask use_mask_expected) { | 549 blink::WebCryptoKeyUsageMask use_mask_expected) { |
| 550 | 550 |
| 551 scoped_ptr<base::DictionaryValue> dict = GetJwkDictionary(json); | |
| 552 if (!dict.get() || dict->empty()) | |
| 553 return ::testing::AssertionFailure() << "JSON parsing failed"; | |
| 554 | |
| 555 // ---- kty | 551 // ---- kty |
| 556 std::string value_string; | 552 std::string value_string; |
| 557 if (!dict->GetString("kty", &value_string)) | 553 if (!dict->GetString("kty", &value_string)) |
| 558 return ::testing::AssertionFailure() << "Missing 'kty'"; | 554 return ::testing::AssertionFailure() << "Missing 'kty'"; |
| 559 if (value_string != "oct") | 555 if (value_string != kty_expected) |
| 560 return ::testing::AssertionFailure() | 556 return ::testing::AssertionFailure() << "Expected 'kty' to be " |
| 561 << "Expected 'kty' to be 'oct' but found " << value_string; | 557 << kty_expected << "but found " |
| 558 << value_string; |
| 562 | 559 |
| 563 // ---- alg | 560 // ---- alg |
| 564 if (!dict->GetString("alg", &value_string)) | 561 if (!dict->GetString("alg", &value_string)) |
| 565 return ::testing::AssertionFailure() << "Missing 'alg'"; | 562 return ::testing::AssertionFailure() << "Missing 'alg'"; |
| 566 if (value_string != alg_expected) | 563 if (value_string != alg_expected) |
| 567 return ::testing::AssertionFailure() << "Expected 'alg' to be " | 564 return ::testing::AssertionFailure() << "Expected 'alg' to be " |
| 568 << alg_expected << " but found " | 565 << alg_expected << " but found " |
| 569 << value_string; | 566 << value_string; |
| 570 | 567 |
| 571 // ---- k | |
| 572 if (!dict->GetString("k", &value_string)) | |
| 573 return ::testing::AssertionFailure() << "Missing 'k'"; | |
| 574 std::string k_value; | |
| 575 if (!webcrypto::Base64DecodeUrlSafe(value_string, &k_value)) | |
| 576 return ::testing::AssertionFailure() << "Base64DecodeUrlSafe(k) failed"; | |
| 577 if (!LowerCaseEqualsASCII(base::HexEncode(k_value.data(), k_value.size()), | |
| 578 k_expected_hex.c_str())) { | |
| 579 return ::testing::AssertionFailure() << "Expected 'k' to be " | |
| 580 << k_expected_hex | |
| 581 << " but found something different"; | |
| 582 } | |
| 583 // ---- ext | 568 // ---- ext |
| 584 // always expect ext == true in this case | 569 // always expect ext == true in this case |
| 585 bool ext_value; | 570 bool ext_value; |
| 586 if (!dict->GetBoolean("ext", &ext_value)) | 571 if (!dict->GetBoolean("ext", &ext_value)) |
| 587 return ::testing::AssertionFailure() << "Missing 'ext'"; | 572 return ::testing::AssertionFailure() << "Missing 'ext'"; |
| 588 if (!ext_value) | 573 if (!ext_value) |
| 589 return ::testing::AssertionFailure() | 574 return ::testing::AssertionFailure() |
| 590 << "Expected 'ext' to be true but found false"; | 575 << "Expected 'ext' to be true but found false"; |
| 591 | 576 |
| 592 // ---- key_ops | 577 // ---- key_ops |
| 593 base::ListValue* key_ops; | 578 base::ListValue* key_ops; |
| 594 if (!dict->GetList("key_ops", &key_ops)) | 579 if (!dict->GetList("key_ops", &key_ops)) |
| 595 return ::testing::AssertionFailure() << "Missing 'key_ops'"; | 580 return ::testing::AssertionFailure() << "Missing 'key_ops'"; |
| 596 blink::WebCryptoKeyUsageMask key_ops_mask = 0; | 581 blink::WebCryptoKeyUsageMask key_ops_mask = 0; |
| 597 Status status = GetWebCryptoUsagesFromJwkKeyOps(key_ops, &key_ops_mask); | 582 Status status = GetWebCryptoUsagesFromJwkKeyOps(key_ops, &key_ops_mask); |
| 598 if (status.IsError()) | 583 if (status.IsError()) |
| 599 return ::testing::AssertionFailure() << "Failure extracting 'key_ops'"; | 584 return ::testing::AssertionFailure() << "Failure extracting 'key_ops'"; |
| 600 if (key_ops_mask != use_mask_expected) | 585 if (key_ops_mask != use_mask_expected) |
| 601 return ::testing::AssertionFailure() | 586 return ::testing::AssertionFailure() |
| 602 << "Expected 'key_ops' mask to be " << use_mask_expected | 587 << "Expected 'key_ops' mask to be " << use_mask_expected |
| 603 << " but found " << key_ops_mask << " (" << value_string << ")"; | 588 << " but found " << key_ops_mask << " (" << value_string << ")"; |
| 604 | 589 |
| 605 return ::testing::AssertionSuccess(); | 590 return ::testing::AssertionSuccess(); |
| 606 } | 591 } |
| 607 | 592 |
| 593 // Verifies that the JSON in the input ArrayBuffer contains the provided |
| 594 // expected values. Exact matches are required on the fields examined. |
| 595 ::testing::AssertionResult VerifySecretJwk( |
| 596 const blink::WebArrayBuffer& json, |
| 597 const std::string& alg_expected, |
| 598 const std::string& k_expected_hex, |
| 599 blink::WebCryptoKeyUsageMask use_mask_expected) { |
| 600 scoped_ptr<base::DictionaryValue> dict = GetJwkDictionary(json); |
| 601 if (!dict.get() || dict->empty()) |
| 602 return ::testing::AssertionFailure() << "JSON parsing failed"; |
| 603 |
| 604 // ---- k |
| 605 std::string value_string; |
| 606 if (!dict->GetString("k", &value_string)) |
| 607 return ::testing::AssertionFailure() << "Missing 'k'"; |
| 608 std::string k_value; |
| 609 if (!webcrypto::Base64DecodeUrlSafe(value_string, &k_value)) |
| 610 return ::testing::AssertionFailure() << "Base64DecodeUrlSafe(k) failed"; |
| 611 if (!LowerCaseEqualsASCII(base::HexEncode(k_value.data(), k_value.size()), |
| 612 k_expected_hex.c_str())) { |
| 613 return ::testing::AssertionFailure() << "Expected 'k' to be " |
| 614 << k_expected_hex |
| 615 << " but found something different"; |
| 616 } |
| 617 |
| 618 return VerifyJwk(dict, "oct", alg_expected, use_mask_expected); |
| 619 } |
| 620 |
| 621 // Verifies that the JSON in the input ArrayBuffer contains the provided |
| 622 // expected values. Exact matches are required on the fields examined. |
| 623 ::testing::AssertionResult VerifyPublicJwk( |
| 624 const blink::WebArrayBuffer& json, |
| 625 const std::string& alg_expected, |
| 626 const std::string& n_expected_hex, |
| 627 const std::string& e_expected_hex, |
| 628 blink::WebCryptoKeyUsageMask use_mask_expected) { |
| 629 scoped_ptr<base::DictionaryValue> dict = GetJwkDictionary(json); |
| 630 if (!dict.get() || dict->empty()) |
| 631 return ::testing::AssertionFailure() << "JSON parsing failed"; |
| 632 |
| 633 // ---- n |
| 634 std::string value_string; |
| 635 if (!dict->GetString("n", &value_string)) |
| 636 return ::testing::AssertionFailure() << "Missing 'n'"; |
| 637 std::string n_value; |
| 638 if (!webcrypto::Base64DecodeUrlSafe(value_string, &n_value)) |
| 639 return ::testing::AssertionFailure() << "Base64DecodeUrlSafe(n) failed"; |
| 640 if (base::HexEncode(n_value.data(), n_value.size()) != n_expected_hex) { |
| 641 return ::testing::AssertionFailure() << "'n' does not match the expected " |
| 642 "value"; |
| 643 } |
| 644 // TODO(padolph): LowerCaseEqualsASCII() does not work for above! |
| 645 |
| 646 // ---- e |
| 647 if (!dict->GetString("e", &value_string)) |
| 648 return ::testing::AssertionFailure() << "Missing 'e'"; |
| 649 std::string e_value; |
| 650 if (!webcrypto::Base64DecodeUrlSafe(value_string, &e_value)) |
| 651 return ::testing::AssertionFailure() << "Base64DecodeUrlSafe(e) failed"; |
| 652 if (!LowerCaseEqualsASCII(base::HexEncode(e_value.data(), e_value.size()), |
| 653 e_expected_hex.c_str())) { |
| 654 return ::testing::AssertionFailure() << "Expected 'e' to be " |
| 655 << e_expected_hex |
| 656 << " but found something different"; |
| 657 } |
| 658 |
| 659 return VerifyJwk(dict, "RSA", alg_expected, use_mask_expected); |
| 660 } |
| 661 |
| 608 } // namespace | 662 } // namespace |
| 609 | 663 |
| 610 TEST_F(SharedCryptoTest, CheckAesGcm) { | 664 TEST_F(SharedCryptoTest, CheckAesGcm) { |
| 611 if (!SupportsAesGcm()) { | 665 if (!SupportsAesGcm()) { |
| 612 LOG(WARNING) << "AES GCM not supported on this platform, so some tests " | 666 LOG(WARNING) << "AES GCM not supported on this platform, so some tests " |
| 613 "will be skipped. Consider upgrading local NSS libraries"; | 667 "will be skipped. Consider upgrading local NSS libraries"; |
| 614 return; | 668 return; |
| 615 } | 669 } |
| 616 } | 670 } |
| 617 | 671 |
| (...skipping 645 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1263 RestoreJwkOctDictionary(&dict); | 1317 RestoreJwkOctDictionary(&dict); |
| 1264 | 1318 |
| 1265 // Fail on k actual length (192 bits) inconsistent with the embedded JWK alg | 1319 // Fail on k actual length (192 bits) inconsistent with the embedded JWK alg |
| 1266 // value (128) for an AES key. | 1320 // value (128) for an AES key. |
| 1267 dict.SetString("k", "dGhpcyAgaXMgIDI0ICBieXRlcyBsb25n"); | 1321 dict.SetString("k", "dGhpcyAgaXMgIDI0ICBieXRlcyBsb25n"); |
| 1268 EXPECT_STATUS(Status::ErrorJwkIncorrectKeyLength(), | 1322 EXPECT_STATUS(Status::ErrorJwkIncorrectKeyLength(), |
| 1269 ImportKeyJwkFromDict(dict, algorithm, false, usage_mask, &key)); | 1323 ImportKeyJwkFromDict(dict, algorithm, false, usage_mask, &key)); |
| 1270 RestoreJwkOctDictionary(&dict); | 1324 RestoreJwkOctDictionary(&dict); |
| 1271 } | 1325 } |
| 1272 | 1326 |
| 1327 TEST_F(SharedCryptoTest, MAYBE(ImportExportJwkRsaPublicKey)) { |
| 1328 // This test uses kPublicKeySpkiDerHex as the RSA key. The data below |
| 1329 // represents the modulus and public exponent extracted from this SPKI blob. |
| 1330 // These values appear explicitly in the JWK rendering of the key. |
| 1331 const std::string n_hex = |
| 1332 "A56E4A0E701017589A5187DC7EA841D156F2EC0E36AD52A44DFEB1E61F7AD991D8C51056" |
| 1333 "FFEDB162B4C0F283A12A88A394DFF526AB7291CBB307CEABFCE0B1DFD5CD9508096D5B2B" |
| 1334 "8B6DF5D671EF6377C0921CB23C270A70E2598E6FF89D19F105ACC2D3F0CB35F29280E138" |
| 1335 "6B6F64C4EF22E1E1F20D0CE8CFFB2249BD9A2137"; |
| 1336 const std::string e_hex = "010001"; |
| 1337 |
| 1338 struct TestCase { |
| 1339 const blink::WebCryptoAlgorithm algorithm; |
| 1340 const blink::WebCryptoKeyUsageMask usage; |
| 1341 const char* const jwk_alg; |
| 1342 }; |
| 1343 const TestCase kTests[] = { |
| 1344 // RSAES-PKCS1-v1_5 |
| 1345 {CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5), |
| 1346 blink::WebCryptoKeyUsageEncrypt, "RSA1_5"}, |
| 1347 // RSASSA-PKCS1-v1_5 SHA-1 |
| 1348 {CreateRsaHashedImportAlgorithm( |
| 1349 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, |
| 1350 blink::WebCryptoAlgorithmIdSha1), |
| 1351 blink::WebCryptoKeyUsageSign, "RS1"}, |
| 1352 // RSASSA-PKCS1-v1_5 SHA-256 |
| 1353 {CreateRsaHashedImportAlgorithm( |
| 1354 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, |
| 1355 blink::WebCryptoAlgorithmIdSha256), |
| 1356 blink::WebCryptoKeyUsageSign, "RS256"}, |
| 1357 // RSASSA-PKCS1-v1_5 SHA-384 |
| 1358 {CreateRsaHashedImportAlgorithm( |
| 1359 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, |
| 1360 blink::WebCryptoAlgorithmIdSha384), |
| 1361 blink::WebCryptoKeyUsageSign, "RS384"}, |
| 1362 // RSASSA-PKCS1-v1_5 SHA-512 |
| 1363 {CreateRsaHashedImportAlgorithm( |
| 1364 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, |
| 1365 blink::WebCryptoAlgorithmIdSha512), |
| 1366 blink::WebCryptoKeyUsageSign, "RS512"}}; |
| 1367 |
| 1368 for (size_t test_index = 0; test_index < ARRAYSIZE_UNSAFE(kTests); |
| 1369 ++test_index) { |
| 1370 SCOPED_TRACE(test_index); |
| 1371 const TestCase& test = kTests[test_index]; |
| 1372 |
| 1373 // Import the spki to create a public key |
| 1374 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); |
| 1375 ASSERT_STATUS_SUCCESS( |
| 1376 ImportKey(blink::WebCryptoKeyFormatSpki, |
| 1377 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)), |
| 1378 test.algorithm, |
| 1379 true, |
| 1380 test.usage, |
| 1381 &public_key)); |
| 1382 |
| 1383 // Export the public key as JWK and verify its contents |
| 1384 blink::WebArrayBuffer jwk; |
| 1385 ASSERT_STATUS_SUCCESS( |
| 1386 ExportKey(blink::WebCryptoKeyFormatJwk, public_key, &jwk)); |
| 1387 EXPECT_TRUE(VerifyPublicJwk(jwk, test.jwk_alg, n_hex, e_hex, test.usage)); |
| 1388 |
| 1389 // Import the JWK back in to create a new key |
| 1390 blink::WebCryptoKey public_key2 = blink::WebCryptoKey::createNull(); |
| 1391 EXPECT_STATUS_SUCCESS(ImportKeyJwk( |
| 1392 CryptoData(jwk), test.algorithm, true, test.usage, &public_key2)); |
| 1393 EXPECT_TRUE(public_key2.handle()); |
| 1394 EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key2.type()); |
| 1395 EXPECT_EQ(true, public_key2.extractable()); |
| 1396 EXPECT_EQ(test.algorithm.id(), public_key2.algorithm().id()); |
| 1397 |
| 1398 // Export the new key as spki and compare to the original. |
| 1399 blink::WebArrayBuffer spki; |
| 1400 ASSERT_STATUS_SUCCESS( |
| 1401 ExportKey(blink::WebCryptoKeyFormatSpki, public_key2, &spki)); |
| 1402 ExpectCryptoDataMatchesHex(kPublicKeySpkiDerHex, CryptoData(spki)); |
| 1403 } |
| 1404 } |
| 1405 |
| 1273 TEST_F(SharedCryptoTest, MAYBE(ImportJwkRsaFailures)) { | 1406 TEST_F(SharedCryptoTest, MAYBE(ImportJwkRsaFailures)) { |
| 1274 base::DictionaryValue dict; | 1407 base::DictionaryValue dict; |
| 1275 RestoreJwkRsaDictionary(&dict); | 1408 RestoreJwkRsaDictionary(&dict); |
| 1276 blink::WebCryptoAlgorithm algorithm = | 1409 blink::WebCryptoAlgorithm algorithm = |
| 1277 CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5); | 1410 CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5); |
| 1278 blink::WebCryptoKeyUsageMask usage_mask = blink::WebCryptoKeyUsageEncrypt; | 1411 blink::WebCryptoKeyUsageMask usage_mask = blink::WebCryptoKeyUsageEncrypt; |
| 1279 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 1412 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
| 1280 | 1413 |
| 1281 // An RSA public key JWK _must_ have an "n" (modulus) and an "e" (exponent) | 1414 // An RSA public key JWK _must_ have an "n" (modulus) and an "e" (exponent) |
| 1282 // entry, while an RSA private key must have those plus at least a "d" | 1415 // entry, while an RSA private key must have those plus at least a "d" |
| (...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1581 !SupportsAesGcm()) { | 1714 !SupportsAesGcm()) { |
| 1582 continue; | 1715 continue; |
| 1583 } | 1716 } |
| 1584 | 1717 |
| 1585 // Import a raw key. | 1718 // Import a raw key. |
| 1586 key = ImportSecretKeyFromRaw( | 1719 key = ImportSecretKeyFromRaw( |
| 1587 HexStringToBytes(test.key_hex), test.algorithm, test.usage); | 1720 HexStringToBytes(test.key_hex), test.algorithm, test.usage); |
| 1588 | 1721 |
| 1589 // Export the key in JWK format and validate. | 1722 // Export the key in JWK format and validate. |
| 1590 ASSERT_STATUS_SUCCESS(ExportKeyJwk(key, &json)); | 1723 ASSERT_STATUS_SUCCESS(ExportKeyJwk(key, &json)); |
| 1591 EXPECT_TRUE( | 1724 EXPECT_TRUE(VerifySecretJwk(json, test.jwk_alg, test.key_hex, test.usage)); |
| 1592 VerifySymmetricJwk(json, test.jwk_alg, test.key_hex, test.usage)); | |
| 1593 | 1725 |
| 1594 // Import the JWK-formatted key. | 1726 // Import the JWK-formatted key. |
| 1595 ASSERT_STATUS_SUCCESS( | 1727 ASSERT_STATUS_SUCCESS( |
| 1596 ImportKeyJwk(CryptoData(json), test.algorithm, true, test.usage, &key)); | 1728 ImportKeyJwk(CryptoData(json), test.algorithm, true, test.usage, &key)); |
| 1597 EXPECT_TRUE(key.handle()); | 1729 EXPECT_TRUE(key.handle()); |
| 1598 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | 1730 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); |
| 1599 EXPECT_EQ(test.algorithm.id(), key.algorithm().id()); | 1731 EXPECT_EQ(test.algorithm.id(), key.algorithm().id()); |
| 1600 EXPECT_EQ(true, key.extractable()); | 1732 EXPECT_EQ(true, key.extractable()); |
| 1601 EXPECT_EQ(test.usage, key.usages()); | 1733 EXPECT_EQ(test.usage, key.usages()); |
| 1602 | 1734 |
| (...skipping 1444 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3047 algorithm, | 3179 algorithm, |
| 3048 CreateAesCbcAlgorithm(std::vector<uint8>(0, 16)), | 3180 CreateAesCbcAlgorithm(std::vector<uint8>(0, 16)), |
| 3049 true, | 3181 true, |
| 3050 blink::WebCryptoKeyUsageEncrypt, | 3182 blink::WebCryptoKeyUsageEncrypt, |
| 3051 &unwrapped_key)); | 3183 &unwrapped_key)); |
| 3052 } | 3184 } |
| 3053 | 3185 |
| 3054 } // namespace webcrypto | 3186 } // namespace webcrypto |
| 3055 | 3187 |
| 3056 } // namespace content | 3188 } // namespace content |
| OLD | NEW |