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 that the JSON in the input ArrayBuffer contains the provided |
eroman
2014/03/24 22:05:51
This comment needs to be updated as well (no longe
padolph
2014/03/25 01:10:28
Done.
| |
544 // expected values. Exact matches are required on the fields examined. | 544 // expected values. Exact matches are 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! | |
eroman
2014/03/24 22:05:51
Not sure I follow, can you explain this comment? S
padolph
2014/03/25 01:10:28
LowerCaseEqual() did not behave properly in this c
eroman
2014/03/25 01:21:12
I would be very surprised if LowerCaseEqual() was
| |
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 {CreateRsaSsaImportAlgorithm(blink::WebCryptoAlgorithmIdSha1), | |
1349 blink::WebCryptoKeyUsageSign, "RS1"}, | |
1350 // RSASSA-PKCS1-v1_5 SHA-256 | |
1351 {CreateRsaSsaImportAlgorithm(blink::WebCryptoAlgorithmIdSha256), | |
1352 blink::WebCryptoKeyUsageSign, "RS256"}, | |
1353 // RSASSA-PKCS1-v1_5 SHA-384 | |
1354 {CreateRsaSsaImportAlgorithm(blink::WebCryptoAlgorithmIdSha384), | |
1355 blink::WebCryptoKeyUsageSign, "RS384"}, | |
1356 // RSASSA-PKCS1-v1_5 SHA-512 | |
1357 {CreateRsaSsaImportAlgorithm(blink::WebCryptoAlgorithmIdSha512), | |
1358 blink::WebCryptoKeyUsageSign, "RS512"}}; | |
1359 | |
1360 for (size_t test_index = 0; test_index < ARRAYSIZE_UNSAFE(kTests); | |
1361 ++test_index) { | |
1362 SCOPED_TRACE(test_index); | |
1363 const TestCase& test = kTests[test_index]; | |
1364 | |
1365 // Import the spki to create a public key | |
1366 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); | |
1367 ASSERT_STATUS_SUCCESS( | |
1368 ImportKey(blink::WebCryptoKeyFormatSpki, | |
1369 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)), | |
1370 test.algorithm, | |
1371 true, | |
1372 test.usage, | |
1373 &public_key)); | |
1374 | |
1375 // Export the public key as JWK and verify its contents | |
1376 blink::WebArrayBuffer jwk; | |
1377 ASSERT_STATUS_SUCCESS( | |
1378 ExportKey(blink::WebCryptoKeyFormatJwk, public_key, &jwk)); | |
1379 EXPECT_TRUE(VerifyPublicJwk(jwk, test.jwk_alg, n_hex, e_hex, test.usage)); | |
1380 | |
1381 // Import the JWK back in to create a new key | |
1382 blink::WebCryptoKey public_key2 = blink::WebCryptoKey::createNull(); | |
1383 EXPECT_STATUS_SUCCESS(ImportKeyJwk( | |
1384 CryptoData(jwk), test.algorithm, true, test.usage, &public_key2)); | |
1385 EXPECT_TRUE(public_key2.handle()); | |
1386 EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key2.type()); | |
1387 EXPECT_EQ(true, public_key2.extractable()); | |
1388 EXPECT_EQ(test.algorithm.id(), public_key2.algorithm().id()); | |
1389 | |
1390 // Export the new key as spki and compare to the original. | |
1391 blink::WebArrayBuffer spki; | |
1392 ASSERT_STATUS_SUCCESS( | |
1393 ExportKey(blink::WebCryptoKeyFormatSpki, public_key2, &spki)); | |
1394 ExpectCryptoDataMatchesHex(kPublicKeySpkiDerHex, CryptoData(spki)); | |
1395 } | |
1396 } | |
1397 | |
1273 TEST_F(SharedCryptoTest, MAYBE(ImportJwkRsaFailures)) { | 1398 TEST_F(SharedCryptoTest, MAYBE(ImportJwkRsaFailures)) { |
1274 base::DictionaryValue dict; | 1399 base::DictionaryValue dict; |
1275 RestoreJwkRsaDictionary(&dict); | 1400 RestoreJwkRsaDictionary(&dict); |
1276 blink::WebCryptoAlgorithm algorithm = | 1401 blink::WebCryptoAlgorithm algorithm = |
1277 CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5); | 1402 CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5); |
1278 blink::WebCryptoKeyUsageMask usage_mask = blink::WebCryptoKeyUsageEncrypt; | 1403 blink::WebCryptoKeyUsageMask usage_mask = blink::WebCryptoKeyUsageEncrypt; |
1279 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 1404 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
1280 | 1405 |
1281 // An RSA public key JWK _must_ have an "n" (modulus) and an "e" (exponent) | 1406 // 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" | 1407 // 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()) { | 1706 !SupportsAesGcm()) { |
1582 continue; | 1707 continue; |
1583 } | 1708 } |
1584 | 1709 |
1585 // Import a raw key. | 1710 // Import a raw key. |
1586 key = ImportSecretKeyFromRaw( | 1711 key = ImportSecretKeyFromRaw( |
1587 HexStringToBytes(test.key_hex), test.algorithm, test.usage); | 1712 HexStringToBytes(test.key_hex), test.algorithm, test.usage); |
1588 | 1713 |
1589 // Export the key in JWK format and validate. | 1714 // Export the key in JWK format and validate. |
1590 ASSERT_STATUS_SUCCESS(ExportKeyJwk(key, &json)); | 1715 ASSERT_STATUS_SUCCESS(ExportKeyJwk(key, &json)); |
1591 EXPECT_TRUE( | 1716 EXPECT_TRUE(VerifySecretJwk(json, test.jwk_alg, test.key_hex, test.usage)); |
1592 VerifySymmetricJwk(json, test.jwk_alg, test.key_hex, test.usage)); | |
1593 | 1717 |
1594 // Import the JWK-formatted key. | 1718 // Import the JWK-formatted key. |
1595 ASSERT_STATUS_SUCCESS( | 1719 ASSERT_STATUS_SUCCESS( |
1596 ImportKeyJwk(CryptoData(json), test.algorithm, true, test.usage, &key)); | 1720 ImportKeyJwk(CryptoData(json), test.algorithm, true, test.usage, &key)); |
1597 EXPECT_TRUE(key.handle()); | 1721 EXPECT_TRUE(key.handle()); |
1598 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | 1722 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); |
1599 EXPECT_EQ(test.algorithm.id(), key.algorithm().id()); | 1723 EXPECT_EQ(test.algorithm.id(), key.algorithm().id()); |
1600 EXPECT_EQ(true, key.extractable()); | 1724 EXPECT_EQ(true, key.extractable()); |
1601 EXPECT_EQ(test.usage, key.usages()); | 1725 EXPECT_EQ(test.usage, key.usages()); |
1602 | 1726 |
(...skipping 1439 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3042 algorithm, | 3166 algorithm, |
3043 CreateAesCbcAlgorithm(std::vector<uint8>(0, 16)), | 3167 CreateAesCbcAlgorithm(std::vector<uint8>(0, 16)), |
3044 true, | 3168 true, |
3045 blink::WebCryptoKeyUsageEncrypt, | 3169 blink::WebCryptoKeyUsageEncrypt, |
3046 &unwrapped_key)); | 3170 &unwrapped_key)); |
3047 } | 3171 } |
3048 | 3172 |
3049 } // namespace webcrypto | 3173 } // namespace webcrypto |
3050 | 3174 |
3051 } // namespace content | 3175 } // namespace content |
OLD | NEW |