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

Unified Diff: content/renderer/webcrypto/webcrypto_impl_unittest.cc

Issue 25906002: [webcrypto] Add JWK import for HMAC and AES-CBC key. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 7 years, 1 month 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 side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698