Index: content/child/webcrypto/test/ecdh_unittest.cc |
diff --git a/content/child/webcrypto/test/ecdh_unittest.cc b/content/child/webcrypto/test/ecdh_unittest.cc |
index 56af8b4106f11a1c167ede7cce903651dc01bfe2..b49aaa8d2e2d54e3ae1f2e93809e3bcd81afe269 100644 |
--- a/content/child/webcrypto/test/ecdh_unittest.cc |
+++ b/content/child/webcrypto/test/ecdh_unittest.cc |
@@ -42,7 +42,41 @@ blink::WebCryptoAlgorithm CreateEcdhDeriveParams( |
new blink::WebCryptoEcdhKeyDeriveParams(public_key)); |
} |
-TEST(WebCryptoEcdhTest, VerifyKnownAnswer) { |
+blink::WebCryptoAlgorithm CreateAesGcmDerivedKeyParams( |
+ unsigned short length_bits) { |
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate( |
+ blink::WebCryptoAlgorithmIdAesGcm, |
+ new blink::WebCryptoAesDerivedKeyParams(length_bits)); |
+} |
+ |
+// Helper that loads a "public_key" and "private_key" from the test data. |
+void ImportKeysFromTest(const base::DictionaryValue* test, |
+ blink::WebCryptoKey* public_key, |
+ blink::WebCryptoKey* private_key) { |
+ // Import the public key. |
+ const base::DictionaryValue* public_key_json = NULL; |
+ EXPECT_TRUE(test->GetDictionary("public_key", &public_key_json)); |
+ blink::WebCryptoNamedCurve curve = |
+ GetCurveNameFromDictionary(public_key_json, "crv"); |
+ ASSERT_EQ(Status::Success(), |
+ ImportKey(blink::WebCryptoKeyFormatJwk, |
+ CryptoData(MakeJsonVector(*public_key_json)), |
+ CreateEcdhImportAlgorithm(curve), true, 0, public_key)); |
+ |
+ // Import the private key. |
+ const base::DictionaryValue* private_key_json = NULL; |
+ EXPECT_TRUE(test->GetDictionary("private_key", &private_key_json)); |
+ curve = GetCurveNameFromDictionary(private_key_json, "crv"); |
+ ASSERT_EQ(Status::Success(), |
+ ImportKey(blink::WebCryptoKeyFormatJwk, |
+ CryptoData(MakeJsonVector(*private_key_json)), |
+ CreateEcdhImportAlgorithm(curve), true, |
+ blink::WebCryptoKeyUsageDeriveBits | |
+ blink::WebCryptoKeyUsageDeriveKey, |
+ private_key)); |
+} |
+ |
+TEST(WebCryptoEcdhTest, DeriveBitsKnownAnswer) { |
if (!SupportsEcdh()) |
return; |
@@ -55,28 +89,10 @@ TEST(WebCryptoEcdhTest, VerifyKnownAnswer) { |
const base::DictionaryValue* test; |
ASSERT_TRUE(tests->GetDictionary(test_index, &test)); |
- // Import the public key. |
- const base::DictionaryValue* public_key_json = NULL; |
- EXPECT_TRUE(test->GetDictionary("public_key", &public_key_json)); |
- blink::WebCryptoNamedCurve curve = |
- GetCurveNameFromDictionary(public_key_json, "crv"); |
+ // Import the keys. |
blink::WebCryptoKey public_key; |
- ASSERT_EQ( |
- Status::Success(), |
- ImportKey(blink::WebCryptoKeyFormatJwk, |
- CryptoData(MakeJsonVector(*public_key_json)), |
- CreateEcdhImportAlgorithm(curve), true, 0, &public_key)); |
- |
- // Import the private key. |
- const base::DictionaryValue* private_key_json = NULL; |
- EXPECT_TRUE(test->GetDictionary("private_key", &private_key_json)); |
- curve = GetCurveNameFromDictionary(private_key_json, "crv"); |
blink::WebCryptoKey private_key; |
- ASSERT_EQ(Status::Success(), |
- ImportKey(blink::WebCryptoKeyFormatJwk, |
- CryptoData(MakeJsonVector(*private_key_json)), |
- CreateEcdhImportAlgorithm(curve), true, |
- blink::WebCryptoKeyUsageDeriveBits, &private_key)); |
+ ImportKeysFromTest(test, &public_key, &private_key); |
// Now try to derive bytes. |
std::vector<uint8_t> derived_bytes; |
@@ -100,6 +116,199 @@ TEST(WebCryptoEcdhTest, VerifyKnownAnswer) { |
} |
} |
+// Loads up a test ECDH public and private key for P-521. The keys |
+// come from different key pairs, and can be used for key derivation of up to |
+// 528 bits. |
+void LoadTestKeys(blink::WebCryptoKey* public_key, |
+ blink::WebCryptoKey* private_key) { |
+ // Assume that the 7th key in the test data is for P-521. |
+ scoped_ptr<base::ListValue> tests; |
+ ASSERT_TRUE(ReadJsonTestFileToList("ecdh.json", &tests)); |
+ |
+ const base::DictionaryValue* test; |
+ ASSERT_TRUE(tests->GetDictionary(6, &test)); |
+ |
+ ImportKeysFromTest(test, public_key, private_key); |
+ |
+ ASSERT_EQ(blink::WebCryptoNamedCurveP521, |
+ public_key->algorithm().ecParams()->namedCurve()); |
+} |
+ |
+// Try deriving an AES key of length 129 bits. |
+TEST(WebCryptoEcdhTest, DeriveKeyBadAesLength) { |
+ if (!SupportsEcdh()) |
+ return; |
+ |
+ blink::WebCryptoKey public_key; |
+ blink::WebCryptoKey base_key; |
+ LoadTestKeys(&public_key, &base_key); |
+ |
+ blink::WebCryptoKey derived_key; |
+ |
+ ASSERT_EQ(Status::ErrorGetAesKeyLength(), |
+ DeriveKey(CreateEcdhDeriveParams(public_key), base_key, |
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesGcm), |
+ CreateAesGcmDerivedKeyParams(129), true, |
+ blink::WebCryptoKeyUsageEncrypt, &derived_key)); |
+} |
+ |
+// Try deriving an AES key of length 192 bits. |
+TEST(WebCryptoEcdhTest, DeriveKeyUnsupportedAesLength) { |
+ if (!SupportsEcdh()) |
+ return; |
+ |
+ blink::WebCryptoKey public_key; |
+ blink::WebCryptoKey base_key; |
+ LoadTestKeys(&public_key, &base_key); |
+ |
+ blink::WebCryptoKey derived_key; |
+ |
+ ASSERT_EQ(Status::ErrorAes192BitUnsupported(), |
+ DeriveKey(CreateEcdhDeriveParams(public_key), base_key, |
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesGcm), |
+ CreateAesGcmDerivedKeyParams(192), true, |
+ blink::WebCryptoKeyUsageEncrypt, &derived_key)); |
+} |
+ |
+// Try deriving an HMAC key of length 0 bits. |
+TEST(WebCryptoEcdhTest, DeriveKeyZeroLengthHmac) { |
+ if (!SupportsEcdh()) |
+ return; |
+ |
+ blink::WebCryptoKey public_key; |
+ blink::WebCryptoKey base_key; |
+ LoadTestKeys(&public_key, &base_key); |
+ |
+ blink::WebCryptoKey derived_key; |
+ |
+ const blink::WebCryptoAlgorithm import_algorithm = |
+ CreateHmacImportAlgorithm(blink::WebCryptoAlgorithmIdSha1, 0); |
+ |
+ ASSERT_EQ(Status::ErrorGetHmacKeyLengthZero(), |
+ DeriveKey(CreateEcdhDeriveParams(public_key), base_key, |
+ import_algorithm, import_algorithm, true, |
+ blink::WebCryptoKeyUsageSign, &derived_key)); |
+} |
+ |
+// Derive an HMAC key of length 19 bits. |
+TEST(WebCryptoEcdhTest, DeriveKeyHmac19Bits) { |
+ if (!SupportsEcdh()) |
+ return; |
+ |
+ blink::WebCryptoKey public_key; |
+ blink::WebCryptoKey base_key; |
+ LoadTestKeys(&public_key, &base_key); |
+ |
+ blink::WebCryptoKey derived_key; |
+ |
+ const blink::WebCryptoAlgorithm import_algorithm = |
+ CreateHmacImportAlgorithm(blink::WebCryptoAlgorithmIdSha1, 19); |
+ |
+ ASSERT_EQ(Status::Success(), |
+ DeriveKey(CreateEcdhDeriveParams(public_key), base_key, |
+ import_algorithm, import_algorithm, true, |
+ blink::WebCryptoKeyUsageSign, &derived_key)); |
+ |
+ ASSERT_EQ(blink::WebCryptoAlgorithmIdHmac, derived_key.algorithm().id()); |
+ ASSERT_EQ(blink::WebCryptoAlgorithmIdSha1, |
+ derived_key.algorithm().hmacParams()->hash().id()); |
+ ASSERT_EQ(19u, derived_key.algorithm().hmacParams()->lengthBits()); |
+ |
+ // Export the key and verify its contents. |
+ std::vector<uint8_t> raw_key; |
+ EXPECT_EQ(Status::Success(), |
+ ExportKey(blink::WebCryptoKeyFormatRaw, derived_key, &raw_key)); |
+ EXPECT_EQ(3u, raw_key.size()); |
+ // The last 7 bits of the key should be zero. |
+ EXPECT_EQ(0, raw_key[raw_key.size() - 1] & 0x1f); |
+} |
+ |
+// Derive an HMAC key with no specified length (just the hash of SHA-256). |
+TEST(WebCryptoEcdhTest, DeriveKeyHmacSha256NoLength) { |
+ if (!SupportsEcdh()) |
+ return; |
+ |
+ blink::WebCryptoKey public_key; |
+ blink::WebCryptoKey base_key; |
+ LoadTestKeys(&public_key, &base_key); |
+ |
+ blink::WebCryptoKey derived_key; |
+ |
+ const blink::WebCryptoAlgorithm import_algorithm = |
+ CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha256); |
+ |
+ ASSERT_EQ(Status::Success(), |
+ DeriveKey(CreateEcdhDeriveParams(public_key), base_key, |
+ import_algorithm, import_algorithm, true, |
+ blink::WebCryptoKeyUsageSign, &derived_key)); |
+ |
+ ASSERT_EQ(blink::WebCryptoAlgorithmIdHmac, derived_key.algorithm().id()); |
+ ASSERT_EQ(blink::WebCryptoAlgorithmIdSha256, |
+ derived_key.algorithm().hmacParams()->hash().id()); |
+ ASSERT_EQ(512u, derived_key.algorithm().hmacParams()->lengthBits()); |
+ |
+ // Export the key and verify its contents. |
+ std::vector<uint8_t> raw_key; |
+ EXPECT_EQ(Status::Success(), |
+ ExportKey(blink::WebCryptoKeyFormatRaw, derived_key, &raw_key)); |
+ EXPECT_EQ(64u, raw_key.size()); |
+} |
+ |
+// Derive an HMAC key with no specified length (just the hash of SHA-512). |
+// |
+// This fails, because ECDH using P-521 can only generate 528 bits, however HMAC |
+// SHA-512 requires 1024 bits. |
+// |
+// In practice, authors won't be directly generating keys from key agreement |
+// schemes, as that is frequently insecure, and instead be using KDFs to expand |
+// and generate keys. For simplicity of testing, however, test using an HMAC |
+// key. |
+TEST(WebCryptoEcdhTest, DeriveKeyHmacSha512NoLength) { |
+ if (!SupportsEcdh()) |
+ return; |
+ |
+ blink::WebCryptoKey public_key; |
+ blink::WebCryptoKey base_key; |
+ LoadTestKeys(&public_key, &base_key); |
+ |
+ blink::WebCryptoKey derived_key; |
+ |
+ const blink::WebCryptoAlgorithm import_algorithm = |
+ CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha512); |
+ |
+ ASSERT_EQ(Status::ErrorEcdhLengthTooBig(528), |
+ DeriveKey(CreateEcdhDeriveParams(public_key), base_key, |
+ import_algorithm, import_algorithm, true, |
+ blink::WebCryptoKeyUsageSign, &derived_key)); |
+} |
+ |
+// Try deriving an AES key of length 128 bits. |
+TEST(WebCryptoEcdhTest, DeriveKeyAes128) { |
+ if (!SupportsEcdh()) |
+ return; |
+ |
+ blink::WebCryptoKey public_key; |
+ blink::WebCryptoKey base_key; |
+ LoadTestKeys(&public_key, &base_key); |
+ |
+ blink::WebCryptoKey derived_key; |
+ |
+ ASSERT_EQ(Status::Success(), |
+ DeriveKey(CreateEcdhDeriveParams(public_key), base_key, |
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesGcm), |
+ CreateAesGcmDerivedKeyParams(128), true, |
+ blink::WebCryptoKeyUsageEncrypt, &derived_key)); |
+ |
+ ASSERT_EQ(blink::WebCryptoAlgorithmIdAesGcm, derived_key.algorithm().id()); |
+ ASSERT_EQ(128, derived_key.algorithm().aesParams()->lengthBits()); |
+ |
+ // Export the key and verify its contents. |
+ std::vector<uint8_t> raw_key; |
+ EXPECT_EQ(Status::Success(), |
+ ExportKey(blink::WebCryptoKeyFormatRaw, derived_key, &raw_key)); |
+ EXPECT_EQ(16u, raw_key.size()); |
+} |
+ |
} // namespace |
} // namespace webcrypto |