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 e448c5267d22b05aa2d99400c3fc8f6896a25139..4a67356b440090e1bb890456f1c64bedb81f5711 100644 |
--- a/content/renderer/webcrypto/webcrypto_impl_unittest.cc |
+++ b/content/renderer/webcrypto/webcrypto_impl_unittest.cc |
@@ -5,6 +5,7 @@ |
#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" |
@@ -59,6 +60,16 @@ WebKit::WebCryptoAlgorithm CreateAesCbcAlgorithm( |
new WebKit::WebCryptoAesCbcParams(Start(iv), iv.size())); |
} |
+std::vector<unsigned char> MakeJsonVector(const std::string& json_string) { |
+ return std::vector<unsigned char>(json_string.begin(), json_string.end()); |
+} |
+ |
+std::vector<unsigned char> MakeJsonVector(const base::DictionaryValue& dict) { |
+ std::string json; |
+ base::JSONWriter::Write(&dict, &json); |
+ return MakeJsonVector(json); |
+} |
+ |
} // namespace |
namespace content { |
@@ -176,6 +187,23 @@ class WebCryptoImplTest : public testing::Test { |
algorithm, key, Start(data), data.size(), buffer); |
} |
+ bool ImportKeyJwk( |
+ const unsigned char* key_data, |
+ unsigned key_data_size, |
+ scoped_ptr<WebKit::WebCryptoKeyHandle>* handle, |
+ WebKit::WebCryptoKeyType* type, |
+ bool* extractable, |
+ WebKit::WebCryptoAlgorithm* algorithm, |
+ WebKit::WebCryptoKeyUsageMask* usage_mask) { |
+ return crypto_.ImportKeyJwk(key_data, |
+ key_data_size, |
+ handle, |
+ type, |
+ extractable, |
+ algorithm, |
+ usage_mask); |
+ } |
+ |
private: |
WebCryptoImpl crypto_; |
}; |
@@ -264,7 +292,7 @@ TEST_F(WebCryptoImplTest, DigestSampleSets) { |
} |
} |
-#endif // #if !defined(USE_OPENSSL) |
+#endif // #if !defined(USE_OPENSSL) |
TEST_F(WebCryptoImplTest, HMACSampleSets) { |
struct TestCase { |
@@ -601,6 +629,243 @@ TEST_F(WebCryptoImplTest, AesCbcSampleSets) { |
} |
} |
-#endif // !defined(USE_OPENSSL) |
+#endif // !defined(USE_OPENSSL) |
+ |
+TEST_F(WebCryptoImplTest, ImportJwkBadJwk) { |
+ |
+ WebKit::WebCryptoKeyType type; |
+ scoped_ptr<WebKit::WebCryptoKeyHandle> handle; |
+ std::vector<uint8> iv(16); |
+ WebKit::WebCryptoAlgorithm algorithm = CreateAesCbcAlgorithm(iv); |
+ bool extractable = false; |
+ WebKit::WebCryptoKeyUsageMask usage_mask = WebKit::WebCryptoKeyUsageSign; |
+ |
+ // Empty JSON |
+ std::vector<unsigned char> json_vec = MakeJsonVector(""); |
+ EXPECT_FALSE(ImportKeyJwk(Start(json_vec), |
+ json_vec.size(), |
+ &handle, |
+ &type, |
+ &extractable, |
+ &algorithm, |
+ &usage_mask)); |
+ |
+ // Bad JSON |
+ json_vec = MakeJsonVector( |
+ "{" |
+ "\"kty\" : \"oct\"," |
+ "\"alg\" : \"HS256\"," |
+ "\"use\" : " |
+ ); |
+ EXPECT_FALSE(ImportKeyJwk(Start(json_vec), |
+ json_vec.size(), |
+ &handle, |
+ &type, |
+ &extractable, |
+ &algorithm, |
+ &usage_mask)); |
+ |
+ // Note, each subtest below resets the dictionary so there is less chance of |
+ // failure if they happen to be reordered. |
+ |
+ // Invalid kty |
+ base::DictionaryValue dict; |
+ dict.SetString("kty", "foo"); |
+ dict.SetString("alg", "HS256"); |
+ dict.SetString("use", "sig"); |
+ dict.SetBoolean("extractable", true); |
+ dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg"); |
+ json_vec = MakeJsonVector(dict); |
+ EXPECT_FALSE(ImportKeyJwk(Start(json_vec), |
+ json_vec.size(), |
+ &handle, |
+ &type, |
+ &extractable, |
+ &algorithm, |
+ &usage_mask)); |
+ dict.SetString("kty", "oct"); |
+ |
+ // Missing kty |
+ dict.Remove("kty", NULL); |
+ json_vec = MakeJsonVector(dict); |
+ EXPECT_FALSE(ImportKeyJwk(Start(json_vec), |
+ json_vec.size(), |
+ &handle, |
+ &type, |
+ &extractable, |
+ &algorithm, |
+ &usage_mask)); |
+ dict.SetString("kty", "oct"); |
+ |
+ // Invalid alg |
+ dict.SetString("alg", "foo"); |
+ json_vec = MakeJsonVector(dict); |
+ EXPECT_FALSE(ImportKeyJwk(Start(json_vec), |
+ json_vec.size(), |
+ &handle, |
+ &type, |
+ &extractable, |
+ &algorithm, |
+ &usage_mask)); |
+ dict.SetString("alg", "HS256"); |
+ |
+ // Invalid use |
+ dict.SetString("use", "foo"); |
+ json_vec = MakeJsonVector(dict); |
+ EXPECT_FALSE(ImportKeyJwk(Start(json_vec), |
+ json_vec.size(), |
+ &handle, |
+ &type, |
+ &extractable, |
+ &algorithm, |
+ &usage_mask)); |
+ dict.SetString("use", "sig"); |
+ |
+ // Missing k when kty = "oct" |
+ dict.Remove("k", NULL); |
+ json_vec = MakeJsonVector(dict); |
+ EXPECT_FALSE(ImportKeyJwk(Start(json_vec), |
+ json_vec.size(), |
+ &handle, |
+ &type, |
+ &extractable, |
+ &algorithm, |
+ &usage_mask)); |
+ dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg"); |
+ |
+ // Bad encoding for k |
+ dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3r #$% jhdY8vOkbIvh4lxTuMao9Y_--hdg"); |
+ json_vec = MakeJsonVector(dict); |
+ EXPECT_FALSE(ImportKeyJwk(Start(json_vec), |
+ json_vec.size(), |
+ &handle, |
+ &type, |
+ &extractable, |
+ &algorithm, |
+ &usage_mask)); |
+ dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg"); |
+ |
+ // 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, ImportJwkCollision) { |
+ |
+ WebKit::WebCryptoKeyType type; |
+ scoped_ptr<WebKit::WebCryptoKeyHandle> handle; |
+ std::vector<uint8> iv(16); |
+ WebKit::WebCryptoAlgorithm algorithm = CreateAesCbcAlgorithm(iv); |
+ bool extractable = false; |
+ WebKit::WebCryptoKeyUsageMask usage_mask = WebKit::WebCryptoKeyUsageSign; |
+ |
+ // Collision rules when JWK value exists: |
+ // Input _type_ should be ignored. |
+ // Input _algorithm_ should be overridden by the JWK value. |
+ // Output _extractable_ should be AND of input and JWK value. |
+ // Input _usage_mask_ should be overridden by the JWK value. |
+ type = WebKit::WebCryptoKeyTypePublic; |
+ algorithm = CreateAesCbcAlgorithm(iv); |
+ extractable = true; |
+ usage_mask = WebKit::WebCryptoKeyUsageWrapKey; |
+ |
+ 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<unsigned char> json_vec = MakeJsonVector(dict); |
+ |
+ EXPECT_TRUE(ImportKeyJwk(Start(json_vec), |
+ json_vec.size(), |
+ &handle, |
+ &type, |
+ &extractable, |
+ &algorithm, |
+ &usage_mask)); |
+ EXPECT_EQ(WebKit::WebCryptoKeyTypeSecret, type); |
+ EXPECT_EQ(WebKit::WebCryptoAlgorithmIdHmac, algorithm.id()); |
+ const WebKit::WebCryptoHmacParams* const hmac_params = algorithm.hmacParams(); |
+ ASSERT_TRUE(hmac_params != NULL); |
+ EXPECT_EQ(hmac_params->hash().id(), WebKit::WebCryptoAlgorithmIdSha256); |
+ EXPECT_FALSE(extractable); |
+ EXPECT_EQ(WebKit::WebCryptoKeyUsageSign | WebKit::WebCryptoKeyUsageVerify, |
+ usage_mask); |
+ |
+ // Collision rules when JWK value is not present: |
+ // Inputs should be unmodified. |
+ algorithm = CreateHmacAlgorithm(WebKit::WebCryptoAlgorithmIdSha256); |
+ extractable = true; |
+ usage_mask = WebKit::WebCryptoKeyUsageSign; |
+ |
+ dict.Clear(); |
+ dict.SetString("kty", "oct"); |
+ dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg"); |
+ json_vec = MakeJsonVector(dict); |
+ |
+ EXPECT_TRUE(ImportKeyJwk(Start(json_vec), |
+ json_vec.size(), |
+ &handle, |
+ &type, |
+ &extractable, |
+ &algorithm, |
+ &usage_mask)); |
+ EXPECT_EQ(WebKit::WebCryptoAlgorithmIdHmac, algorithm.id()); |
+ EXPECT_TRUE(extractable); |
+ EXPECT_EQ(WebKit::WebCryptoKeyUsageSign, usage_mask); |
+} |
+ |
+TEST_F(WebCryptoImplTest, ImportJwkHappy) { |
+ |
+ WebKit::WebCryptoKeyType type; |
+ scoped_ptr<WebKit::WebCryptoKeyHandle> handle; |
+ std::vector<uint8> iv(16); |
+ WebKit::WebCryptoAlgorithm algorithm = CreateAesCbcAlgorithm(iv); |
+ bool extractable = false; |
+ 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", true); |
+ dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg"); |
+ std::vector<unsigned char> json_vec = MakeJsonVector(dict); |
+ |
+ EXPECT_TRUE(ImportKeyJwk(Start(json_vec), |
+ json_vec.size(), |
+ &handle, |
+ &type, |
+ &extractable, |
+ &algorithm, |
+ &usage_mask)); |
+ |
+ 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 |