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

Side by Side Diff: content/child/webcrypto/shared_crypto_unittest.cc

Issue 205913002: [webcrypto] Add JWK RSA public key export for NSS. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 6 years, 9 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
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698