Chromium Code Reviews| Index: content/renderer/webcrypto/webcrypto_impl_unittest.cc |
| diff --git a/content/renderer/webcrypto/webcrypto_impl_unittest.cc b/content/renderer/webcrypto/webcrypto_impl_unittest.cc |
| index 51a162433227338eb4e361e2f3a3a6093814446a..8360e592208507ed784565b9b2ca562df95f0091 100644 |
| --- a/content/renderer/webcrypto/webcrypto_impl_unittest.cc |
| +++ b/content/renderer/webcrypto/webcrypto_impl_unittest.cc |
| @@ -5,12 +5,14 @@ |
| #include "webcrypto_impl.h" |
| #include "base/basictypes.h" |
| +#include "base/json/json_writer.h" |
| #include "base/logging.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "content/public/renderer/content_renderer_client.h" |
| #include "content/renderer/renderer_webkitplatformsupport_impl.h" |
| #include "content/renderer/webcrypto/webcrypto_impl.h" |
| +#include "content/renderer/webcrypto/webcrypto_util.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/WebKit/public/platform/WebArrayBuffer.h" |
| #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" |
| @@ -32,49 +34,14 @@ void ExpectArrayBufferMatchesHex(const std::string& expected_hex, |
| array_buffer.data(), array_buffer.byteLength()).c_str()); |
| } |
| -WebKit::WebCryptoAlgorithm CreateAlgorithm(WebKit::WebCryptoAlgorithmId id) { |
| - return WebKit::WebCryptoAlgorithm::adoptParamsAndCreate(id, NULL); |
| +std::vector<uint8> MakeJsonVector(const std::string& json_string) { |
| + return std::vector<uint8>(json_string.begin(), json_string.end()); |
| } |
| -WebKit::WebCryptoAlgorithm CreateHmacAlgorithm( |
| - WebKit::WebCryptoAlgorithmId hashId) { |
| - return WebKit::WebCryptoAlgorithm::adoptParamsAndCreate( |
| - WebKit::WebCryptoAlgorithmIdHmac, |
| - new WebKit::WebCryptoHmacParams(CreateAlgorithm(hashId))); |
| -} |
| - |
| -WebKit::WebCryptoAlgorithm CreateHmacKeyAlgorithm( |
| - WebKit::WebCryptoAlgorithmId hashId, |
| - unsigned hash_length) { |
| - // hash_length < 0 means unspecified |
| - return WebKit::WebCryptoAlgorithm::adoptParamsAndCreate( |
| - WebKit::WebCryptoAlgorithmIdHmac, |
| - new WebKit::WebCryptoHmacKeyParams(CreateAlgorithm(hashId), |
| - (hash_length != 0), |
| - hash_length)); |
| -} |
| - |
| -// Returns a pointer to the start of |data|, or NULL if it is empty. This is a |
| -// convenience function for getting the pointer, and should not be used beyond |
| -// the expected lifetime of |data|. |
| -const uint8* Start(const std::vector<uint8>& data) { |
| - if (data.empty()) |
| - return NULL; |
| - return &data[0]; |
| -} |
| - |
| -WebKit::WebCryptoAlgorithm CreateAesCbcAlgorithm( |
| - const std::vector<uint8>& iv) { |
| - return WebKit::WebCryptoAlgorithm::adoptParamsAndCreate( |
| - WebKit::WebCryptoAlgorithmIdAesCbc, |
| - new WebKit::WebCryptoAesCbcParams(Start(iv), iv.size())); |
| -} |
| - |
| -WebKit::WebCryptoAlgorithm CreateAesCbcAlgorithm( |
| - unsigned short key_length_bits) { |
| - return WebKit::WebCryptoAlgorithm::adoptParamsAndCreate( |
| - WebKit::WebCryptoAlgorithmIdAesCbc, |
| - new WebKit::WebCryptoAesKeyGenParams(key_length_bits)); |
| +std::vector<uint8> MakeJsonVector(const base::DictionaryValue& dict) { |
| + std::string json; |
| + base::JSONWriter::Write(&dict, &json); |
| + return MakeJsonVector(json); |
| } |
| } // namespace |
| @@ -201,6 +168,22 @@ class WebCryptoImplTest : public testing::Test { |
| algorithm, key, Start(data), data.size(), buffer); |
| } |
| + bool ImportKeyJwk( |
| + const std::vector<uint8>& key_data, |
| + bool extractable, |
| + const WebKit::WebCryptoAlgorithm& algorithm, |
| + WebKit::WebCryptoKeyUsageMask usage_mask, |
| + scoped_ptr<WebKit::WebCryptoKeyHandle>* handle, |
| + WebKit::WebCryptoKeyType* type) { |
| + return crypto_.ImportKeyJwk(Start(key_data), |
| + key_data.size(), |
| + extractable, |
| + algorithm, |
| + usage_mask, |
| + handle, |
| + type); |
| + } |
| + |
| private: |
| WebCryptoImpl crypto_; |
| }; |
| @@ -379,7 +362,8 @@ TEST_F(WebCryptoImplTest, HMACSampleSets) { |
| SCOPED_TRACE(test_index); |
| const TestCase& test = kTests[test_index]; |
| - WebKit::WebCryptoAlgorithm algorithm = CreateHmacAlgorithm(test.algorithm); |
| + WebKit::WebCryptoAlgorithm algorithm = |
| + CreateHmacAlgorithmByHashId(test.algorithm); |
| WebKit::WebCryptoKey key = ImportSecretKeyFromRawHexString( |
| test.key, algorithm, WebKit::WebCryptoKeyUsageSign); |
| @@ -425,6 +409,8 @@ TEST_F(WebCryptoImplTest, HMACSampleSets) { |
| } |
| } |
| +#if !defined(USE_OPENSSL) |
| + |
| TEST_F(WebCryptoImplTest, AesCbcFailures) { |
| WebKit::WebCryptoKey key = ImportSecretKeyFromRawHexString( |
| "2b7e151628aed2a6abf7158809cf4f3c", |
| @@ -620,11 +606,11 @@ TEST_F(WebCryptoImplTest, AesCbcSampleSets) { |
| // TODO (padolph): Add test to verify generated symmetric keys appear random. |
| - |
| TEST_F(WebCryptoImplTest, GenerateKeyAes) { |
| scoped_ptr<WebKit::WebCryptoKeyHandle> result; |
| WebKit::WebCryptoKeyType type = WebKit::WebCryptoKeyTypePublic; |
| - ASSERT_TRUE(GenerateKeyInternal(CreateAesCbcAlgorithm(128), &result, &type)); |
| + ASSERT_TRUE( |
| + GenerateKeyInternal(CreateAesCbcKeyGenAlgorithm(128), &result, &type)); |
| EXPECT_TRUE(result); |
| EXPECT_EQ(type, WebKit::WebCryptoKeyTypeSecret); |
| } |
| @@ -632,15 +618,18 @@ TEST_F(WebCryptoImplTest, GenerateKeyAes) { |
| TEST_F(WebCryptoImplTest, GenerateKeyAesBadLength) { |
| scoped_ptr<WebKit::WebCryptoKeyHandle> result; |
| WebKit::WebCryptoKeyType type = WebKit::WebCryptoKeyTypePublic; |
| - EXPECT_FALSE(GenerateKeyInternal(CreateAesCbcAlgorithm(0), &result, &type)); |
| - EXPECT_FALSE(GenerateKeyInternal(CreateAesCbcAlgorithm(129), &result, &type)); |
| + EXPECT_FALSE( |
| + GenerateKeyInternal(CreateAesCbcKeyGenAlgorithm(0), &result, &type)); |
| + EXPECT_FALSE( |
| + GenerateKeyInternal(CreateAesCbcKeyGenAlgorithm(129), &result, &type)); |
| } |
| + |
| TEST_F(WebCryptoImplTest, GenerateKeyHmac) { |
| scoped_ptr<WebKit::WebCryptoKeyHandle> result; |
| WebKit::WebCryptoKeyType type = WebKit::WebCryptoKeyTypePublic; |
| WebKit::WebCryptoAlgorithm algorithm = |
| - CreateHmacKeyAlgorithm(WebKit::WebCryptoAlgorithmIdSha1, 128); |
| + CreateHmacKeyGenAlgorithm(WebKit::WebCryptoAlgorithmIdSha1, 128); |
| ASSERT_TRUE(GenerateKeyInternal(algorithm, &result, &type)); |
| EXPECT_TRUE(result); |
| EXPECT_EQ(type, WebKit::WebCryptoKeyTypeSecret); |
| @@ -650,10 +639,261 @@ TEST_F(WebCryptoImplTest, GenerateKeyHmacNoLength) { |
| scoped_ptr<WebKit::WebCryptoKeyHandle> result; |
| WebKit::WebCryptoKeyType type = WebKit::WebCryptoKeyTypePublic; |
| WebKit::WebCryptoAlgorithm algorithm = |
| - CreateHmacKeyAlgorithm(WebKit::WebCryptoAlgorithmIdSha1, 0); |
| + CreateHmacKeyGenAlgorithm(WebKit::WebCryptoAlgorithmIdSha1, 0); |
| ASSERT_TRUE(GenerateKeyInternal(algorithm, &result, &type)); |
| EXPECT_TRUE(result); |
| EXPECT_EQ(type, WebKit::WebCryptoKeyTypeSecret); |
| } |
| +#endif //#if !defined(USE_OPENSSL) |
| + |
| +TEST_F(WebCryptoImplTest, ImportJwkBadJwk) { |
| + |
| + WebKit::WebCryptoKeyType type = WebKit::WebCryptoKeyTypeSecret; |
| + scoped_ptr<WebKit::WebCryptoKeyHandle> handle; |
| + WebKit::WebCryptoAlgorithm algorithm = CreateHmacAlgorithmByKeyLen(256); |
| + const bool extractable = false; |
| + WebKit::WebCryptoKeyUsageMask usage_mask = WebKit::WebCryptoKeyUsageSign; |
| + |
| + // Baseline pass: each test below breaks a single item, so we start with a |
| + // passing case to make sure each failure caused by the isolated break. Each |
| + // breaking subtest below resets the dictionary to this passing case when |
| + // complete. |
| + const std::string key_val("oct"); |
| + const std::string alg_val("HS256"); |
| + const std::string use_val("sig"); |
| + const std::string k_val("Qk3f0DsytU8lfza2auHtaw2xpop9GYyTuH0p5GghxTI="); |
| + base::DictionaryValue dict; |
| + dict.SetString("kty", key_val); |
| + dict.SetString("alg", alg_val); |
| + dict.SetString("use", use_val); |
| + dict.SetBoolean("extractable", extractable); |
| + dict.SetString("k", k_val); |
| + std::vector<uint8> json_vec = MakeJsonVector(dict); |
| + EXPECT_TRUE(ImportKeyJwk( |
| + json_vec, extractable, algorithm, usage_mask, &handle, &type)); |
| + |
| + // Fail on empty JSON. |
| + EXPECT_FALSE(ImportKeyJwk( |
| + MakeJsonVector(""), extractable, algorithm, usage_mask, &handle, &type)); |
| + |
| + // Fail on invalid JSON. |
| + const std::vector<uint8> bad_json_vec = MakeJsonVector( |
| + "{" |
| + "\"kty\" : \"oct\"," |
| + "\"alg\" : \"HS256\"," |
| + "\"use\" : " |
| + ); |
| + EXPECT_FALSE(ImportKeyJwk( |
| + bad_json_vec, extractable, algorithm, usage_mask, &handle, &type)); |
| + |
| + // Fail on Null input algorithm. |
| + EXPECT_FALSE(ImportKeyJwk(json_vec, |
| + extractable, |
| + WebKit::WebCryptoAlgorithm::createNull(), |
| + usage_mask, |
| + &handle, |
| + &type)); |
| + |
| + // Fail on Null input handle pointer. |
| + EXPECT_FALSE( |
| + ImportKeyJwk(json_vec, extractable, algorithm, usage_mask, NULL, &type)); |
| + |
| + // Fail on Null input type pointer. |
| + EXPECT_FALSE(ImportKeyJwk( |
| + json_vec, extractable, algorithm, usage_mask, &handle, NULL)); |
| + |
| + // Fail on input algorithm mismatch. |
| + EXPECT_FALSE(ImportKeyJwk(json_vec, |
| + extractable, |
| + CreateAlgorithm(WebKit::WebCryptoAlgorithmIdAesCbc), |
| + usage_mask, |
| + &handle, |
| + &type)); |
| + |
| + // Fail on input algorithm mismatch (inner hash algorithm). |
| + EXPECT_FALSE(ImportKeyJwk(json_vec, |
| + extractable, |
| + CreateHmacAlgorithmByKeyLen(512), |
| + usage_mask, |
| + &handle, |
| + &type)); |
| + |
| + // Fail on invalid kty. |
| + dict.SetString("kty", "foo"); |
| + json_vec = MakeJsonVector(dict); |
| + EXPECT_FALSE(ImportKeyJwk( |
| + json_vec, extractable, algorithm, usage_mask, &handle, &type)); |
| + dict.SetString("kty", key_val); |
|
eroman
2013/10/29 03:03:46
I actually preferred the duplication of these cons
padolph
2013/10/29 22:57:01
Done.
|
| + |
| + // Fail on missing kty. |
| + dict.Remove("kty", NULL); |
| + json_vec = MakeJsonVector(dict); |
| + EXPECT_FALSE(ImportKeyJwk( |
| + json_vec, extractable, algorithm, usage_mask, &handle, &type)); |
| + dict.SetString("kty", key_val); |
| + |
| + // Fail on invalid alg. |
| + dict.SetString("alg", "foo"); |
| + json_vec = MakeJsonVector(dict); |
| + EXPECT_FALSE(ImportKeyJwk( |
| + json_vec, extractable, algorithm, usage_mask, &handle, &type)); |
| + dict.SetString("alg", alg_val); |
| + |
| + // Fail on invalid use. |
| + dict.SetString("use", "foo"); |
| + json_vec = MakeJsonVector(dict); |
| + EXPECT_FALSE(ImportKeyJwk( |
| + json_vec, extractable, algorithm, usage_mask, &handle, &type)); |
| + dict.SetString("use", use_val); |
| + |
| + // Fail on missing k when kty = "oct". |
| + dict.Remove("k", NULL); |
| + json_vec = MakeJsonVector(dict); |
| + EXPECT_FALSE(ImportKeyJwk( |
| + json_vec, extractable, algorithm, usage_mask, &handle, &type)); |
| + dict.SetString("k", k_val); |
| + |
| + // Fail on bad b64 encoding for k. |
| + dict.SetString("k", "Qk3f0DsytU8lfza2au #$% Htaw2xpop9GYyTuH0p5GghxTI="); |
| + json_vec = MakeJsonVector(dict); |
| + EXPECT_FALSE(ImportKeyJwk( |
| + json_vec, extractable, algorithm, usage_mask, &handle, &type)); |
| + dict.SetString("k", k_val); |
| + |
| + // Fail on empty k. |
| + dict.SetString("k", ""); |
| + json_vec = MakeJsonVector(dict); |
| + EXPECT_FALSE(ImportKeyJwk( |
| + json_vec, extractable, algorithm, usage_mask, &handle, &type)); |
| + dict.SetString("k", k_val); |
| + |
| + // TODO(padolph) RSA public key bad data: |
| + // Missing n or e when kty = "RSA" |
| + // Bad encoding for n or e |
| + // Size check on n?? |
| + // Value check on e?? |
| +} |
| + |
| +TEST_F(WebCryptoImplTest, ImportJwkInputInconsistent) { |
| + // The Web Crypto spec says that if a JWK value is present, but is |
| + // inconsistent with the input value, the operation must fail. |
| + |
| + // Collision rules when JWK value is not present: Inputs should be unmodified. |
| + scoped_ptr<WebKit::WebCryptoKeyHandle> handle; |
| + WebKit::WebCryptoKeyType type = WebKit::WebCryptoKeyTypeSecret; |
| + bool extractable = true; |
| + WebKit::WebCryptoAlgorithm algorithm = |
| + CreateHmacAlgorithmByHashId(WebKit::WebCryptoAlgorithmIdSha256); |
| + WebKit::WebCryptoKeyUsageMask usage_mask = WebKit::WebCryptoKeyUsageVerify; |
| + base::DictionaryValue dict; |
| + dict.SetString("kty", "oct"); |
| + dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg"); |
| + std::vector<uint8> json_vec = MakeJsonVector(dict); |
| + EXPECT_TRUE(ImportKeyJwk( |
| + json_vec, extractable, algorithm, usage_mask, &handle, &type)); |
| + EXPECT_TRUE(handle.get() != NULL); |
| + EXPECT_EQ(WebKit::WebCryptoKeyTypeSecret, type); |
| + EXPECT_TRUE(extractable); |
| + EXPECT_EQ(WebKit::WebCryptoAlgorithmIdHmac, algorithm.id()); |
| + EXPECT_EQ(WebKit::WebCryptoAlgorithmIdSha256, |
| + algorithm.hmacParams()->hash().id()); |
| + EXPECT_EQ(WebKit::WebCryptoKeyUsageVerify, usage_mask); |
| + handle.reset(); |
| + |
| + // Collision rules when JWK value exists: Fail if inconsistency is found. |
| + // Happy path: all input values are consistent with the JWK values |
| + dict.Clear(); |
| + dict.SetString("kty", "oct"); |
| + dict.SetString("alg", "HS256"); |
| + dict.SetString("use", "sig"); |
| + dict.SetBoolean("extractable", true); |
| + dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg"); |
| + json_vec = MakeJsonVector(dict); |
| + EXPECT_TRUE(ImportKeyJwk( |
| + json_vec, extractable, algorithm, usage_mask, &handle, &type)); |
| + |
| + // Fail: Input type (public) is inconsistent with JWK value (secret). |
| + type = WebKit::WebCryptoKeyTypePublic; |
| + EXPECT_FALSE(ImportKeyJwk( |
| + json_vec, extractable, algorithm, usage_mask, &handle, &type)); |
| + type = WebKit::WebCryptoKeyTypeSecret; |
| + |
| + // Fail: Input extractable (false) is inconsistent with JWK value (true). |
| + extractable = false; |
| + EXPECT_FALSE(ImportKeyJwk( |
| + json_vec, extractable, algorithm, usage_mask, &handle, &type)); |
| + extractable = true; |
| + |
| + // Fail: Input algorithm (HMAC SHA1) is inconsistent with JWK value |
| + // (HMAC SHA256). |
| + algorithm = CreateHmacAlgorithmByHashId(WebKit::WebCryptoAlgorithmIdSha1); |
| + EXPECT_FALSE(ImportKeyJwk( |
| + json_vec, extractable, algorithm, usage_mask, &handle, &type)); |
| + algorithm = CreateHmacAlgorithmByHashId(WebKit::WebCryptoAlgorithmIdSha256); |
| + |
| + // Fail: Input usage_mask (encrypt) is not a subset of the JWK value |
| + // (sign|verify) |
| + usage_mask = WebKit::WebCryptoKeyUsageEncrypt; |
| + EXPECT_FALSE(ImportKeyJwk( |
| + json_vec, extractable, algorithm, usage_mask, &handle, &type)); |
| + usage_mask = WebKit::WebCryptoKeyUsageSign | WebKit::WebCryptoKeyUsageVerify; |
| + |
| + // Fail: Input usage_mask (encrypt|sign|verify) is not a subset of the JWK |
| + // value (sign|verify) |
| + usage_mask = WebKit::WebCryptoKeyUsageEncrypt | |
| + WebKit::WebCryptoKeyUsageSign | WebKit::WebCryptoKeyUsageVerify; |
| + EXPECT_FALSE(ImportKeyJwk( |
| + json_vec, extractable, algorithm, usage_mask, &handle, &type)); |
| + usage_mask = WebKit::WebCryptoKeyUsageSign | WebKit::WebCryptoKeyUsageVerify; |
| +} |
| + |
| +TEST_F(WebCryptoImplTest, ImportJwkHappy) { |
| + |
| + // This test verifies the happy path of JWK import, including the application |
| + // of the imported key material. |
| + |
| + scoped_ptr<WebKit::WebCryptoKeyHandle> handle; |
| + WebKit::WebCryptoKeyType type = WebKit::WebCryptoKeyTypeSecret; |
| + bool extractable = false; |
| + WebKit::WebCryptoAlgorithm algorithm = |
| + CreateHmacAlgorithmByHashId(WebKit::WebCryptoAlgorithmIdSha256); |
| + WebKit::WebCryptoKeyUsageMask usage_mask = WebKit::WebCryptoKeyUsageSign; |
| + |
| + // Import a symmetric key JWK and HMAC-SHA256 sign() |
| + // Uses the first SHA256 test vector from the HMAC sample set above. |
| + |
| + base::DictionaryValue dict; |
| + dict.SetString("kty", "oct"); |
| + dict.SetString("alg", "HS256"); |
| + dict.SetString("use", "sig"); |
| + dict.SetBoolean("extractable", false); |
| + dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg"); |
| + std::vector<uint8> json_vec = MakeJsonVector(dict); |
| + |
| + ASSERT_TRUE(ImportKeyJwk( |
| + json_vec, extractable, algorithm, usage_mask, &handle, &type)); |
| + |
| + WebKit::WebCryptoKey key = WebKit::WebCryptoKey::create( |
| + handle.release(), type, extractable, algorithm, usage_mask); |
| + |
| + const std::vector<uint8> message_raw = HexStringToBytes( |
| + "b1689c2591eaf3c9e66070f8a77954ffb81749f1b00346f9dfe0b2ee905dcc288baf4a" |
| + "92de3f4001dd9f44c468c3d07d6c6ee82faceafc97c2fc0fc0601719d2dcd0aa2aec92" |
| + "d1b0ae933c65eb06a03c9c935c2bad0459810241347ab87e9f11adb30415424c6c7f5f" |
| + "22a003b8ab8de54f6ded0e3ab9245fa79568451dfa258e"); |
| + |
| + WebKit::WebArrayBuffer output; |
| + |
| + ASSERT_TRUE(SignInternal(algorithm, key, message_raw, &output)); |
| + |
| + const std::string mac_raw = |
| + "769f00d3e6a6cc1fb426a14a4f76c6462e6149726e0dee0ec0cf97a16605ac8b"; |
| + |
| + ExpectArrayBufferMatchesHex(mac_raw, output); |
| + |
| + // TODO(padolph) |
| + // Import an RSA public key JWK and use it |
| +} |
| + |
| } // namespace content |