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 99d71ea395b3df2c06b78aa9528994568fd86178..5fa818d55bf8e464c593bae996b73b1d8b75c22b 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,23 @@ 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))); |
+std::vector<uint8> MakeJsonVector(const base::DictionaryValue& dict) { |
+ std::string json; |
+ base::JSONWriter::Write(&dict, &json); |
+ return MakeJsonVector(json); |
} |
-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)); |
+// Helper for ImportJwkBadJwk; restores JWK JSON dictionary to a good state |
+void RestoreDictionary(base::DictionaryValue* dict) { |
eroman
2013/11/01 20:59:58
nit: can you give it a more specific name?
padolph
2013/11/01 23:08:50
Done.
|
+ dict->SetString("kty", "oct"); |
eroman
2013/11/01 20:59:58
How about calling dict->Clear() first, to remove a
padolph
2013/11/01 23:08:50
Done.
|
+ dict->SetString("alg", "HS256"); |
+ dict->SetString("use", "sig"); |
+ dict->SetBoolean("extractable", false); |
+ dict->SetString("k", "Qk3f0DsytU8lfza2auHtaw2xpop9GYyTuH0p5GghxTI="); |
} |
} // namespace |
@@ -199,6 +175,20 @@ class WebCryptoImplTest : public testing::Test { |
algorithm, key, Start(data), data.size(), buffer); |
} |
+ bool ImportKeyJwk( |
+ const std::vector<uint8>& key_data, |
+ const WebKit::WebCryptoAlgorithm& algorithm, |
+ bool extractable, |
+ WebKit::WebCryptoKeyUsageMask usage_mask, |
+ WebKit::WebCryptoKey* key) { |
+ return crypto_.ImportKeyJwk(Start(key_data), |
+ key_data.size(), |
+ algorithm, |
+ extractable, |
+ usage_mask, |
+ key); |
+ } |
+ |
private: |
WebCryptoImpl crypto_; |
}; |
@@ -377,7 +367,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); |
@@ -423,6 +414,8 @@ TEST_F(WebCryptoImplTest, HMACSampleSets) { |
} |
} |
+#if !defined(USE_OPENSSL) |
+ |
TEST_F(WebCryptoImplTest, AesCbcFailures) { |
WebKit::WebCryptoKey key = ImportSecretKeyFromRawHexString( |
"2b7e151628aed2a6abf7158809cf4f3c", |
@@ -618,21 +611,26 @@ TEST_F(WebCryptoImplTest, AesCbcSampleSets) { |
TEST_F(WebCryptoImplTest, GenerateKeyAes) { |
WebKit::WebCryptoKey key = WebCryptoImpl::NullKey(); |
- ASSERT_TRUE(GenerateKeyInternal(CreateAesCbcAlgorithm(128), &key)); |
+ ASSERT_TRUE(GenerateKeyInternal(CreateAesCbcKeyGenAlgorithm(128), &key)); |
EXPECT_TRUE(key.handle()); |
EXPECT_EQ(WebKit::WebCryptoKeyTypeSecret, key.type()); |
} |
TEST_F(WebCryptoImplTest, GenerateKeyAesBadLength) { |
WebKit::WebCryptoKey key = WebCryptoImpl::NullKey(); |
- EXPECT_FALSE(GenerateKeyInternal(CreateAesCbcAlgorithm(0), &key)); |
- EXPECT_FALSE(GenerateKeyInternal(CreateAesCbcAlgorithm(129), &key)); |
+ EXPECT_FALSE( |
+ GenerateKeyInternal(CreateAesCbcKeyGenAlgorithm(0), &key)); |
+ EXPECT_FALSE( |
+ GenerateKeyInternal(CreateAesCbcKeyGenAlgorithm(0), &key)); |
+ EXPECT_FALSE( |
+ GenerateKeyInternal(CreateAesCbcKeyGenAlgorithm(129), &key)); |
} |
+ |
TEST_F(WebCryptoImplTest, GenerateKeyHmac) { |
WebKit::WebCryptoKey key = WebCryptoImpl::NullKey(); |
WebKit::WebCryptoAlgorithm algorithm = |
- CreateHmacKeyAlgorithm(WebKit::WebCryptoAlgorithmIdSha1, 128); |
+ CreateHmacKeyGenAlgorithm(WebKit::WebCryptoAlgorithmIdSha1, 128); |
ASSERT_TRUE(GenerateKeyInternal(algorithm, &key)); |
EXPECT_TRUE(key.handle()); |
EXPECT_EQ(WebKit::WebCryptoKeyTypeSecret, key.type()); |
@@ -641,7 +639,7 @@ TEST_F(WebCryptoImplTest, GenerateKeyHmac) { |
TEST_F(WebCryptoImplTest, GenerateKeyHmacNoLength) { |
WebKit::WebCryptoKey key = WebCryptoImpl::NullKey(); |
WebKit::WebCryptoAlgorithm algorithm = |
- CreateHmacKeyAlgorithm(WebKit::WebCryptoAlgorithmIdSha1, 0); |
+ CreateHmacKeyGenAlgorithm(WebKit::WebCryptoAlgorithmIdSha1, 0); |
eroman
2013/11/01 20:59:58
thanks, that is a better name.
|
ASSERT_TRUE(GenerateKeyInternal(algorithm, &key)); |
EXPECT_TRUE(key.handle()); |
EXPECT_EQ(WebKit::WebCryptoKeyTypeSecret, key.type()); |
@@ -659,4 +657,230 @@ TEST_F(WebCryptoImplTest, ImportSecretKeyNoAlgorithm) { |
&key)); |
} |
+#endif //#if !defined(USE_OPENSSL) |
+ |
+TEST_F(WebCryptoImplTest, ImportJwkBadJwk) { |
+ |
+ WebKit::WebCryptoKey key = WebCryptoImpl::NullKey(); |
eroman
2013/11/01 20:59:58
please use WebKit::WebCryptoKey::createNull()
padolph
2013/11/01 23:08:50
Done.
|
+ WebKit::WebCryptoAlgorithm algorithm = CreateHmacAlgorithmByDigestLen(256); |
+ 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. |
eroman
2013/11/01 20:59:58
useful comment, thanks
|
+ base::DictionaryValue dict; |
+ RestoreDictionary(&dict); |
+ std::vector<uint8> json_vec = MakeJsonVector(dict); |
+ EXPECT_TRUE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); |
+ |
+ // Fail on empty JSON. |
+ EXPECT_FALSE(ImportKeyJwk( |
+ MakeJsonVector(""), algorithm, false, usage_mask, &key)); |
+ |
+ // Fail on invalid JSON. |
+ const std::vector<uint8> bad_json_vec = MakeJsonVector( |
+ "{" |
+ "\"kty\" : \"oct\"," |
+ "\"alg\" : \"HS256\"," |
+ "\"use\" : " |
+ ); |
+ EXPECT_FALSE(ImportKeyJwk(bad_json_vec, algorithm, false, usage_mask, &key)); |
+ |
+ // Fail on JWK alg present but unrecognized. |
+ dict.SetString("alg", "foo"); |
+ json_vec = MakeJsonVector(dict); |
+ EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); |
+ RestoreDictionary(&dict); |
+ |
+ // Fail on both JWK and input algorithm missing. |
+ dict.Remove("alg", NULL); |
+ json_vec = MakeJsonVector(dict); |
+ EXPECT_FALSE(ImportKeyJwk(json_vec, |
+ WebKit::WebCryptoAlgorithm::createNull(), |
+ false, |
+ usage_mask, |
+ &key)); |
+ RestoreDictionary(&dict); |
+ |
+ // Fail on invalid kty. |
+ dict.SetString("kty", "foo"); |
+ json_vec = MakeJsonVector(dict); |
+ EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); |
+ RestoreDictionary(&dict); |
+ |
+ // Fail on missing kty. |
+ dict.Remove("kty", NULL); |
+ json_vec = MakeJsonVector(dict); |
+ EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); |
+ RestoreDictionary(&dict); |
+ |
+ // Fail on invalid use. |
+ dict.SetString("use", "foo"); |
+ json_vec = MakeJsonVector(dict); |
+ EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); |
+ RestoreDictionary(&dict); |
+ |
+ // Fail on missing k when kty = "oct". |
+ dict.Remove("k", NULL); |
+ json_vec = MakeJsonVector(dict); |
+ EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); |
+ RestoreDictionary(&dict); |
+ |
+ // Fail on bad b64 encoding for k. |
+ dict.SetString("k", "Qk3f0DsytU8lfza2au #$% Htaw2xpop9GYyTuH0p5GghxTI="); |
+ json_vec = MakeJsonVector(dict); |
+ EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); |
+ RestoreDictionary(&dict); |
+ |
+ // Fail on empty k. |
+ dict.SetString("k", ""); |
+ json_vec = MakeJsonVector(dict); |
+ EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); |
+ RestoreDictionary(&dict); |
+ |
+ // 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. |
+ |
+ // Consistency rules when JWK value is not present: Inputs should be used. |
+ WebKit::WebCryptoKey key = WebCryptoImpl::NullKey(); |
eroman
2013/11/01 20:59:58
WebCryptoKey::createNull()
padolph
2013/11/01 23:08:50
Done.
|
+ 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, algorithm, extractable, usage_mask, &key)); |
+ EXPECT_TRUE(key.handle()); |
+ EXPECT_EQ(WebKit::WebCryptoKeyTypeSecret, key.type()); |
+ EXPECT_EQ(extractable, key.extractable()); |
+ EXPECT_EQ(WebKit::WebCryptoAlgorithmIdHmac, key.algorithm().id()); |
+ EXPECT_EQ(WebKit::WebCryptoAlgorithmIdSha256, |
+ key.algorithm().hmacParams()->hash().id()); |
+ EXPECT_EQ(WebKit::WebCryptoKeyUsageVerify, key.usages()); |
+ key = WebCryptoImpl::NullKey(); |
+ |
+ // Consistency 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, algorithm, extractable, usage_mask, &key)); |
+ |
+ // Fail: Input extractable (false) is inconsistent with JWK value (true). |
+ EXPECT_FALSE( |
+ ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); |
+ |
+ // Fail: Input algorithm (AES-CBC) is inconsistent with JWK value |
+ // (HMAC SHA256). |
+ EXPECT_FALSE(ImportKeyJwk(json_vec, |
+ CreateAlgorithm(WebKit::WebCryptoAlgorithmIdAesCbc), |
+ extractable, |
+ usage_mask, |
+ &key)); |
+ |
+ // Fail: Input algorithm (HMAC SHA1) is inconsistent with JWK value |
+ // (HMAC SHA256). |
+ EXPECT_FALSE(ImportKeyJwk( |
+ json_vec, |
+ CreateHmacAlgorithmByHashId(WebKit::WebCryptoAlgorithmIdSha1), |
+ extractable, |
+ usage_mask, |
+ &key)); |
+ |
+ // Pass: JWK alg valid but input algorithm isNull: use JWK algorithm value. |
+ EXPECT_TRUE(ImportKeyJwk(json_vec, |
+ WebKit::WebCryptoAlgorithm::createNull(), |
+ extractable, |
+ usage_mask, |
+ &key)); |
+ EXPECT_EQ(WebKit::WebCryptoAlgorithmIdHmac, algorithm.id()); |
+ |
+ // Pass: JWK alg missing but input algorithm specified: use input value |
+ dict.Remove("alg", NULL); |
+ EXPECT_TRUE(ImportKeyJwk( |
+ MakeJsonVector(dict), |
+ CreateHmacAlgorithmByHashId(WebKit::WebCryptoAlgorithmIdSha256), |
+ extractable, |
+ usage_mask, |
+ &key)); |
+ EXPECT_EQ(WebKit::WebCryptoAlgorithmIdHmac, algorithm.id()); |
+ dict.SetString("alg", "HS256"); |
+ |
+ // Fail: Input usage_mask (encrypt) is not a subset of the JWK value |
+ // (sign|verify) |
+ EXPECT_FALSE(ImportKeyJwk(json_vec, |
+ algorithm, |
+ extractable, |
+ WebKit::WebCryptoKeyUsageEncrypt, |
+ &key)); |
+ |
+ // 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, algorithm, extractable, usage_mask, &key)); |
+ 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. |
+ |
+ WebKit::WebCryptoKey key = WebCryptoImpl::NullKey(); |
+ 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, algorithm, extractable, usage_mask, &key)); |
+ |
+ 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 |