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 f9ff0d67f232b6d36e1fa38689175c289d2fa9f5..c59de0e3d856f5c1fe171d3a73e775dad341134f 100644 |
--- a/content/renderer/webcrypto/webcrypto_impl_unittest.cc |
+++ b/content/renderer/webcrypto/webcrypto_impl_unittest.cc |
@@ -9,17 +9,21 @@ |
#include <vector> |
#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_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" |
#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" |
#include "third_party/WebKit/public/platform/WebCryptoKey.h" |
+namespace content { |
+ |
namespace { |
std::vector<uint8> HexStringToBytes(const std::string& hex) { |
@@ -32,55 +36,28 @@ void ExpectArrayBufferMatchesHex(const std::string& expected_hex, |
const blink::WebArrayBuffer& array_buffer) { |
EXPECT_STRCASEEQ( |
expected_hex.c_str(), |
- base::HexEncode( |
- array_buffer.data(), array_buffer.byteLength()).c_str()); |
-} |
- |
-blink::WebCryptoAlgorithm CreateAlgorithm(blink::WebCryptoAlgorithmId id) { |
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(id, NULL); |
-} |
- |
-blink::WebCryptoAlgorithm CreateHmacAlgorithm( |
- blink::WebCryptoAlgorithmId hashId) { |
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate( |
- blink::WebCryptoAlgorithmIdHmac, |
- new blink::WebCryptoHmacParams(CreateAlgorithm(hashId))); |
-} |
- |
-blink::WebCryptoAlgorithm CreateHmacKeyAlgorithm( |
- blink::WebCryptoAlgorithmId hashId, |
- unsigned hash_length) { |
- // hash_length < 0 means unspecified |
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate( |
- blink::WebCryptoAlgorithmIdHmac, |
- new blink::WebCryptoHmacKeyParams(CreateAlgorithm(hashId), |
- (hash_length != 0), |
- hash_length)); |
+ base::HexEncode(array_buffer.data(), array_buffer.byteLength()).c_str()); |
} |
-// 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]; |
+std::vector<uint8> MakeJsonVector(const std::string& json_string) { |
+ return std::vector<uint8>(json_string.begin(), json_string.end()); |
} |
-blink::WebCryptoAlgorithm CreateAesCbcAlgorithm( |
- const std::vector<uint8>& iv) { |
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate( |
- blink::WebCryptoAlgorithmIdAesCbc, |
- new blink::WebCryptoAesCbcParams(Start(iv), iv.size())); |
+std::vector<uint8> MakeJsonVector(const base::DictionaryValue& dict) { |
+ std::string json; |
+ base::JSONWriter::Write(&dict, &json); |
+ return MakeJsonVector(json); |
} |
-blink::WebCryptoAlgorithm CreateAesCbcAlgorithm( |
- unsigned short key_length_bits) { // NOLINT |
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate( |
- blink::WebCryptoAlgorithmIdAesCbc, |
- new blink::WebCryptoAesKeyGenParams(key_length_bits)); |
+// Helper for ImportJwkBadJwk; restores JWK JSON dictionary to a good state |
+void RestoreDictionaryForImportBadJwkTest(base::DictionaryValue* dict) { |
+ dict->Clear(); |
+ dict->SetString("kty", "oct"); |
+ dict->SetString("alg", "A128CBC"); |
+ dict->SetString("use", "enc"); |
+ dict->SetBoolean("extractable", false); |
+ dict->SetString("k", "GADWrMRHwQfoNaXU5fZvTg=="); |
} |
- |
#if !defined(USE_OPENSSL) |
blink::WebCryptoAlgorithm CreateRsaKeyGenAlgorithm( |
@@ -93,15 +70,15 @@ blink::WebCryptoAlgorithm CreateRsaKeyGenAlgorithm( |
return blink::WebCryptoAlgorithm::adoptParamsAndCreate( |
algorithm_id, |
new blink::WebCryptoRsaKeyGenParams( |
- modulus_length, Start(public_exponent), public_exponent.size())); |
+ modulus_length, |
+ webcrypto::Uint8VectorStart(public_exponent), |
+ public_exponent.size())); |
} |
#endif // #if !defined(USE_OPENSSL) |
} // namespace |
-namespace content { |
- |
class WebCryptoImplTest : public testing::Test { |
protected: |
blink::WebCryptoKey ImportSecretKeyFromRawHexString( |
@@ -113,7 +90,7 @@ class WebCryptoImplTest : public testing::Test { |
blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
bool extractable = true; |
EXPECT_TRUE(crypto_.ImportKeyInternal(blink::WebCryptoKeyFormatRaw, |
- Start(key_raw), |
+ webcrypto::Uint8VectorStart(key_raw), |
key_raw.size(), |
algorithm, |
extractable, |
@@ -133,7 +110,8 @@ class WebCryptoImplTest : public testing::Test { |
const blink::WebCryptoAlgorithm& algorithm, |
const std::vector<uint8>& data, |
blink::WebArrayBuffer* buffer) { |
- return crypto_.DigestInternal(algorithm, Start(data), data.size(), buffer); |
+ return crypto_.DigestInternal( |
+ algorithm, webcrypto::Uint8VectorStart(data), data.size(), buffer); |
} |
bool GenerateKeyInternal( |
@@ -162,7 +140,7 @@ class WebCryptoImplTest : public testing::Test { |
blink::WebCryptoKeyUsageMask usage_mask, |
blink::WebCryptoKey* key) { |
return crypto_.ImportKeyInternal(format, |
- Start(key_data), |
+ webcrypto::Uint8VectorStart(key_data), |
key_data.size(), |
algorithm, |
extractable, |
@@ -183,7 +161,7 @@ class WebCryptoImplTest : public testing::Test { |
const std::vector<uint8>& data, |
blink::WebArrayBuffer* buffer) { |
return crypto_.SignInternal( |
- algorithm, key, Start(data), data.size(), buffer); |
+ algorithm, key, webcrypto::Uint8VectorStart(data), data.size(), buffer); |
} |
bool VerifySignatureInternal( |
@@ -197,7 +175,7 @@ class WebCryptoImplTest : public testing::Test { |
key, |
signature, |
signature_size, |
- Start(data), |
+ webcrypto::Uint8VectorStart(data), |
data.size(), |
signature_match); |
} |
@@ -217,7 +195,7 @@ class WebCryptoImplTest : public testing::Test { |
const std::vector<uint8>& data, |
blink::WebArrayBuffer* buffer) { |
return crypto_.EncryptInternal( |
- algorithm, key, Start(data), data.size(), buffer); |
+ algorithm, key, webcrypto::Uint8VectorStart(data), data.size(), buffer); |
} |
bool DecryptInternal( |
@@ -235,7 +213,21 @@ class WebCryptoImplTest : public testing::Test { |
const std::vector<uint8>& data, |
blink::WebArrayBuffer* buffer) { |
return crypto_.DecryptInternal( |
- algorithm, key, Start(data), data.size(), buffer); |
+ algorithm, key, webcrypto::Uint8VectorStart(data), data.size(), buffer); |
+ } |
+ |
+ bool ImportKeyJwk( |
+ const std::vector<uint8>& key_data, |
+ const blink::WebCryptoAlgorithm& algorithm, |
+ bool extractable, |
+ blink::WebCryptoKeyUsageMask usage_mask, |
+ blink::WebCryptoKey* key) { |
+ return crypto_.ImportKeyJwk(webcrypto::Uint8VectorStart(key_data), |
+ key_data.size(), |
+ algorithm, |
+ extractable, |
+ usage_mask, |
+ key); |
} |
private: |
@@ -314,7 +306,8 @@ TEST_F(WebCryptoImplTest, DigestSampleSets) { |
SCOPED_TRACE(test_index); |
const TestCase& test = kTests[test_index]; |
- blink::WebCryptoAlgorithm algorithm = CreateAlgorithm(test.algorithm); |
+ blink::WebCryptoAlgorithm algorithm = |
+ webcrypto::CreateAlgorithm(test.algorithm); |
std::vector<uint8> input = HexStringToBytes(test.hex_input); |
blink::WebArrayBuffer output; |
@@ -416,7 +409,8 @@ TEST_F(WebCryptoImplTest, HMACSampleSets) { |
SCOPED_TRACE(test_index); |
const TestCase& test = kTests[test_index]; |
- blink::WebCryptoAlgorithm algorithm = CreateHmacAlgorithm(test.algorithm); |
+ blink::WebCryptoAlgorithm algorithm = |
+ webcrypto::CreateHmacAlgorithmByHashId(test.algorithm); |
blink::WebCryptoKey key = ImportSecretKeyFromRawHexString( |
test.key, algorithm, blink::WebCryptoKeyUsageSign); |
@@ -462,10 +456,12 @@ TEST_F(WebCryptoImplTest, HMACSampleSets) { |
} |
} |
+#if !defined(USE_OPENSSL) |
+ |
TEST_F(WebCryptoImplTest, AesCbcFailures) { |
blink::WebCryptoKey key = ImportSecretKeyFromRawHexString( |
"2b7e151628aed2a6abf7158809cf4f3c", |
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), |
+ webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), |
blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); |
blink::WebArrayBuffer output; |
@@ -474,20 +470,20 @@ TEST_F(WebCryptoImplTest, AesCbcFailures) { |
{ |
std::vector<uint8> input(32); |
std::vector<uint8> iv; |
- EXPECT_FALSE( |
- EncryptInternal(CreateAesCbcAlgorithm(iv), key, input, &output)); |
- EXPECT_FALSE( |
- DecryptInternal(CreateAesCbcAlgorithm(iv), key, input, &output)); |
+ EXPECT_FALSE(EncryptInternal( |
+ webcrypto::CreateAesCbcAlgorithm(iv), key, input, &output)); |
+ EXPECT_FALSE(DecryptInternal( |
+ webcrypto::CreateAesCbcAlgorithm(iv), key, input, &output)); |
} |
// Use an invalid |iv| (more than 16 bytes) |
{ |
std::vector<uint8> input(32); |
std::vector<uint8> iv(17); |
- EXPECT_FALSE( |
- EncryptInternal(CreateAesCbcAlgorithm(iv), key, input, &output)); |
- EXPECT_FALSE( |
- DecryptInternal(CreateAesCbcAlgorithm(iv), key, input, &output)); |
+ EXPECT_FALSE(EncryptInternal( |
+ webcrypto::CreateAesCbcAlgorithm(iv), key, input, &output)); |
+ EXPECT_FALSE(DecryptInternal( |
+ webcrypto::CreateAesCbcAlgorithm(iv), key, input, &output)); |
} |
// Give an input that is too large (would cause integer overflow when |
@@ -502,9 +498,9 @@ TEST_F(WebCryptoImplTest, AesCbcFailures) { |
unsigned input_len = INT_MAX - 3; |
EXPECT_FALSE(EncryptInternal( |
- CreateAesCbcAlgorithm(iv), key, input, input_len, &output)); |
+ webcrypto::CreateAesCbcAlgorithm(iv), key, input, input_len, &output)); |
EXPECT_FALSE(DecryptInternal( |
- CreateAesCbcAlgorithm(iv), key, input, input_len, &output)); |
+ webcrypto::CreateAesCbcAlgorithm(iv), key, input, input_len, &output)); |
} |
// Fail importing the key (too few bytes specified) |
@@ -515,7 +511,7 @@ TEST_F(WebCryptoImplTest, AesCbcFailures) { |
blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
EXPECT_FALSE(ImportKeyInternal(blink::WebCryptoKeyFormatRaw, |
key_raw, |
- CreateAesCbcAlgorithm(iv), |
+ webcrypto::CreateAesCbcAlgorithm(iv), |
true, |
blink::WebCryptoKeyUsageEncrypt, |
&key)); |
@@ -610,7 +606,7 @@ TEST_F(WebCryptoImplTest, AesCbcSampleSets) { |
blink::WebCryptoKey key = ImportSecretKeyFromRawHexString( |
test.key, |
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), |
+ webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), |
blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); |
std::vector<uint8> plain_text = HexStringToBytes(test.plain_text); |
@@ -619,7 +615,7 @@ TEST_F(WebCryptoImplTest, AesCbcSampleSets) { |
blink::WebArrayBuffer output; |
// Test encryption. |
- EXPECT_TRUE(EncryptInternal(CreateAesCbcAlgorithm(iv), |
+ EXPECT_TRUE(EncryptInternal(webcrypto::CreateAesCbcAlgorithm(iv), |
key, |
plain_text, |
&output)); |
@@ -627,7 +623,7 @@ TEST_F(WebCryptoImplTest, AesCbcSampleSets) { |
// Test decryption. |
std::vector<uint8> cipher_text = HexStringToBytes(test.cipher_text); |
- EXPECT_TRUE(DecryptInternal(CreateAesCbcAlgorithm(iv), |
+ EXPECT_TRUE(DecryptInternal(webcrypto::CreateAesCbcAlgorithm(iv), |
key, |
cipher_text, |
&output)); |
@@ -638,7 +634,7 @@ TEST_F(WebCryptoImplTest, AesCbcSampleSets) { |
// Decrypt with a padding error by stripping the last block. This also ends |
// up testing decryption over empty cipher text. |
if (cipher_text.size() >= kAesCbcBlockSize) { |
- EXPECT_FALSE(DecryptInternal(CreateAesCbcAlgorithm(iv), |
+ EXPECT_FALSE(DecryptInternal(webcrypto::CreateAesCbcAlgorithm(iv), |
key, |
&cipher_text[0], |
cipher_text.size() - kAesCbcBlockSize, |
@@ -648,7 +644,7 @@ TEST_F(WebCryptoImplTest, AesCbcSampleSets) { |
// Decrypt cipher text which is not a multiple of block size by stripping |
// a few bytes off the cipher text. |
if (cipher_text.size() > 3) { |
- EXPECT_FALSE(DecryptInternal(CreateAesCbcAlgorithm(iv), |
+ EXPECT_FALSE(DecryptInternal(webcrypto::CreateAesCbcAlgorithm(iv), |
key, |
&cipher_text[0], |
cipher_text.size() - 3, |
@@ -661,21 +657,26 @@ TEST_F(WebCryptoImplTest, AesCbcSampleSets) { |
TEST_F(WebCryptoImplTest, GenerateKeyAes) { |
blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
- ASSERT_TRUE(GenerateKeyInternal(CreateAesCbcAlgorithm(128), &key)); |
+ ASSERT_TRUE( |
+ GenerateKeyInternal(webcrypto::CreateAesCbcKeyGenAlgorithm(128), &key)); |
EXPECT_TRUE(key.handle()); |
EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); |
} |
TEST_F(WebCryptoImplTest, GenerateKeyAesBadLength) { |
blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
- EXPECT_FALSE(GenerateKeyInternal(CreateAesCbcAlgorithm(0), &key)); |
- EXPECT_FALSE(GenerateKeyInternal(CreateAesCbcAlgorithm(129), &key)); |
+ EXPECT_FALSE( |
+ GenerateKeyInternal(webcrypto::CreateAesCbcKeyGenAlgorithm(0), &key)); |
+ EXPECT_FALSE( |
+ GenerateKeyInternal(webcrypto::CreateAesCbcKeyGenAlgorithm(0), &key)); |
+ EXPECT_FALSE( |
+ GenerateKeyInternal(webcrypto::CreateAesCbcKeyGenAlgorithm(129), &key)); |
} |
TEST_F(WebCryptoImplTest, GenerateKeyHmac) { |
blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
- blink::WebCryptoAlgorithm algorithm = |
- CreateHmacKeyAlgorithm(blink::WebCryptoAlgorithmIdSha1, 128); |
+ blink::WebCryptoAlgorithm algorithm = webcrypto::CreateHmacKeyGenAlgorithm( |
+ blink::WebCryptoAlgorithmIdSha1, 128); |
ASSERT_TRUE(GenerateKeyInternal(algorithm, &key)); |
EXPECT_FALSE(key.isNull()); |
EXPECT_TRUE(key.handle()); |
@@ -685,7 +686,7 @@ TEST_F(WebCryptoImplTest, GenerateKeyHmac) { |
TEST_F(WebCryptoImplTest, GenerateKeyHmacNoLength) { |
blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
blink::WebCryptoAlgorithm algorithm = |
- CreateHmacKeyAlgorithm(blink::WebCryptoAlgorithmIdSha1, 0); |
+ webcrypto::CreateHmacKeyGenAlgorithm(blink::WebCryptoAlgorithmIdSha1, 0); |
ASSERT_TRUE(GenerateKeyInternal(algorithm, &key)); |
EXPECT_TRUE(key.handle()); |
EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); |
@@ -704,6 +705,250 @@ TEST_F(WebCryptoImplTest, ImportSecretKeyNoAlgorithm) { |
&key)); |
} |
+#endif //#if !defined(USE_OPENSSL) |
+ |
+TEST_F(WebCryptoImplTest, ImportJwkBadJwk) { |
+ |
+ blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
+ blink::WebCryptoAlgorithm algorithm = |
+ webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc); |
+ blink::WebCryptoKeyUsageMask usage_mask = blink::WebCryptoKeyUsageEncrypt; |
+ |
+ // Baseline pass: each test below breaks a single item, so we start with a |
+ // passing case to make sure each failure is caused by the isolated break. |
+ // Each breaking subtest below resets the dictionary to this passing case when |
+ // complete. |
+ base::DictionaryValue dict; |
+ RestoreDictionaryForImportBadJwkTest(&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", "A127CBC"); |
+ json_vec = MakeJsonVector(dict); |
+ EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); |
+ RestoreDictionaryForImportBadJwkTest(&dict); |
+ |
+ // Fail on both JWK and input algorithm missing. |
+ dict.Remove("alg", NULL); |
+ json_vec = MakeJsonVector(dict); |
+ EXPECT_FALSE(ImportKeyJwk(json_vec, |
+ blink::WebCryptoAlgorithm::createNull(), |
+ false, |
+ usage_mask, |
+ &key)); |
+ RestoreDictionaryForImportBadJwkTest(&dict); |
+ |
+ // Fail on invalid kty. |
+ dict.SetString("kty", "foo"); |
+ json_vec = MakeJsonVector(dict); |
+ EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); |
+ RestoreDictionaryForImportBadJwkTest(&dict); |
+ |
+ // Fail on missing kty. |
+ dict.Remove("kty", NULL); |
+ json_vec = MakeJsonVector(dict); |
+ EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); |
+ RestoreDictionaryForImportBadJwkTest(&dict); |
+ |
+ // Fail on invalid use. |
+ dict.SetString("use", "foo"); |
+ json_vec = MakeJsonVector(dict); |
+ EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); |
+ RestoreDictionaryForImportBadJwkTest(&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)); |
+ RestoreDictionaryForImportBadJwkTest(&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)); |
+ RestoreDictionaryForImportBadJwkTest(&dict); |
+ |
+ // Fail on empty k. |
+ dict.SetString("k", ""); |
+ json_vec = MakeJsonVector(dict); |
+ EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); |
+ RestoreDictionaryForImportBadJwkTest(&dict); |
+ |
+ // Fail on k actual length (120 bits) inconsistent with the embedded JWK alg |
+ // value (128) for an AES key. |
+ dict.SetString("k", "AVj42h0Y5aqGtE3yluKL"); |
+ json_vec = MakeJsonVector(dict); |
+ EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); |
+ RestoreDictionaryForImportBadJwkTest(&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, ImportJwkInputConsistency) { |
+ // 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. |
+ blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
+ bool extractable = false; |
+ blink::WebCryptoAlgorithm algorithm = |
+ webcrypto::CreateHmacAlgorithmByHashId(blink::WebCryptoAlgorithmIdSha256); |
+ blink::WebCryptoKeyUsageMask usage_mask = blink::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(blink::WebCryptoKeyTypeSecret, key.type()); |
+ EXPECT_EQ(extractable, key.extractable()); |
+ EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, key.algorithm().id()); |
+ EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256, |
+ key.algorithm().hmacParams()->hash().id()); |
+ EXPECT_EQ(blink::WebCryptoKeyUsageVerify, key.usages()); |
+ key = blink::WebCryptoKey::createNull(); |
+ |
+ // Consistency rules when JWK value exists: Fail if inconsistency is found. |
+ |
+ // Pass: 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", false); |
+ dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg"); |
+ json_vec = MakeJsonVector(dict); |
+ EXPECT_TRUE(ImportKeyJwk(json_vec, algorithm, extractable, usage_mask, &key)); |
+ |
+ // Extractable cases: |
+ // 1. input=T, JWK=F ==> fail (inconsistent) |
+ // 4. input=F, JWK=F ==> pass, result extractable is F |
+ // 2. input=T, JWK=T ==> pass, result extractable is T |
+ // 3. input=F, JWK=T ==> pass, result extractable is F |
+ EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, true, usage_mask, &key)); |
+ EXPECT_TRUE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); |
+ EXPECT_FALSE(key.extractable()); |
+ dict.SetBoolean("extractable", true); |
+ EXPECT_TRUE( |
+ ImportKeyJwk(MakeJsonVector(dict), algorithm, true, usage_mask, &key)); |
+ EXPECT_TRUE(key.extractable()); |
+ EXPECT_TRUE( |
+ ImportKeyJwk(MakeJsonVector(dict), algorithm, false, usage_mask, &key)); |
+ EXPECT_FALSE(key.extractable()); |
+ dict.SetBoolean("extractable", true); // restore previous value |
+ |
+ // Fail: Input algorithm (AES-CBC) is inconsistent with JWK value |
+ // (HMAC SHA256). |
+ EXPECT_FALSE(ImportKeyJwk( |
+ json_vec, |
+ webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), |
+ extractable, |
+ usage_mask, |
+ &key)); |
+ |
+ // Fail: Input algorithm (HMAC SHA1) is inconsistent with JWK value |
+ // (HMAC SHA256). |
+ EXPECT_FALSE(ImportKeyJwk( |
+ json_vec, |
+ webcrypto::CreateHmacAlgorithmByHashId(blink::WebCryptoAlgorithmIdSha1), |
+ extractable, |
+ usage_mask, |
+ &key)); |
+ |
+ // Pass: JWK alg valid but input algorithm isNull: use JWK algorithm value. |
+ EXPECT_TRUE(ImportKeyJwk(json_vec, |
+ blink::WebCryptoAlgorithm::createNull(), |
+ extractable, |
+ usage_mask, |
+ &key)); |
+ EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, algorithm.id()); |
+ |
+ // Pass: JWK alg missing but input algorithm specified: use input value |
+ dict.Remove("alg", NULL); |
+ EXPECT_TRUE(ImportKeyJwk( |
+ MakeJsonVector(dict), |
+ webcrypto::CreateHmacAlgorithmByHashId(blink::WebCryptoAlgorithmIdSha256), |
+ extractable, |
+ usage_mask, |
+ &key)); |
+ EXPECT_EQ(blink::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, blink::WebCryptoKeyUsageEncrypt, &key)); |
+ |
+ // Fail: Input usage_mask (encrypt|sign|verify) is not a subset of the JWK |
+ // value (sign|verify) |
+ usage_mask = blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageSign | |
+ blink::WebCryptoKeyUsageVerify; |
+ EXPECT_FALSE( |
+ ImportKeyJwk(json_vec, algorithm, extractable, usage_mask, &key)); |
+ usage_mask = blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify; |
+} |
+ |
+TEST_F(WebCryptoImplTest, ImportJwkHappy) { |
+ |
+ // This test verifies the happy path of JWK import, including the application |
+ // of the imported key material. |
+ |
+ blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
+ bool extractable = false; |
+ blink::WebCryptoAlgorithm algorithm = |
+ webcrypto::CreateHmacAlgorithmByHashId(blink::WebCryptoAlgorithmIdSha256); |
+ blink::WebCryptoKeyUsageMask usage_mask = blink::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"); |
+ |
+ blink::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 |
+} |
+ |
#if !defined(USE_OPENSSL) |
TEST_F(WebCryptoImplTest, ImportExportSpki) { |
@@ -727,7 +972,7 @@ TEST_F(WebCryptoImplTest, ImportExportSpki) { |
ASSERT_TRUE(ImportKeyInternal( |
blink::WebCryptoKeyFormatSpki, |
HexStringToBytes(hex_rsa_spki_der), |
- CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5), |
+ webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5), |
true, |
blink::WebCryptoKeyUsageEncrypt, |
&key)); |
@@ -760,7 +1005,7 @@ TEST_F(WebCryptoImplTest, ImportExportSpki) { |
EXPECT_FALSE(ImportKeyInternal( |
blink::WebCryptoKeyFormatSpki, |
HexStringToBytes("618333c4cb"), |
- CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5), |
+ webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5), |
true, |
blink::WebCryptoKeyUsageEncrypt, |
&key)); |
@@ -769,7 +1014,7 @@ TEST_F(WebCryptoImplTest, ImportExportSpki) { |
EXPECT_FALSE(ImportKeyInternal( |
blink::WebCryptoKeyFormatSpki, |
HexStringToBytes(hex_rsa_spki_der), |
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), |
+ webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), |
true, |
blink::WebCryptoKeyUsageEncrypt, |
&key)); |
@@ -784,15 +1029,13 @@ TEST_F(WebCryptoImplTest, ImportExportSpki) { |
ASSERT_TRUE(ImportKeyInternal( |
blink::WebCryptoKeyFormatSpki, |
HexStringToBytes(hex_rsa_spki_der), |
- CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5), |
+ webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5), |
false, |
blink::WebCryptoKeyUsageEncrypt, |
&key)); |
EXPECT_TRUE(key.handle()); |
EXPECT_FALSE(key.extractable()); |
EXPECT_FALSE(ExportKeyInternal(blink::WebCryptoKeyFormatSpki, key, &output)); |
- |
- // TODO(padolph): Use the imported key for a Known Answer Test (KAT). |
} |
TEST_F(WebCryptoImplTest, ImportPkcs8) { |
@@ -825,7 +1068,7 @@ TEST_F(WebCryptoImplTest, ImportPkcs8) { |
ASSERT_TRUE(ImportKeyInternal( |
blink::WebCryptoKeyFormatPkcs8, |
HexStringToBytes(hex_rsa_pkcs8_der), |
- CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5), |
+ webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5), |
true, |
blink::WebCryptoKeyUsageSign, |
&key)); |
@@ -858,7 +1101,7 @@ TEST_F(WebCryptoImplTest, ImportPkcs8) { |
EXPECT_FALSE(ImportKeyInternal( |
blink::WebCryptoKeyFormatPkcs8, |
HexStringToBytes("618333c4cb"), |
- CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5), |
+ webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5), |
true, |
blink::WebCryptoKeyUsageSign, |
&key)); |
@@ -867,12 +1110,10 @@ TEST_F(WebCryptoImplTest, ImportPkcs8) { |
EXPECT_FALSE(ImportKeyInternal( |
blink::WebCryptoKeyFormatPkcs8, |
HexStringToBytes(hex_rsa_pkcs8_der), |
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), |
+ webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), |
true, |
blink::WebCryptoKeyUsageSign, |
&key)); |
- |
- // TODO(padolph): Use the imported key for a Known Answer Test (KAT). |
} |
TEST_F(WebCryptoImplTest, GenerateKeyPairRsa) { |
@@ -881,11 +1122,11 @@ TEST_F(WebCryptoImplTest, GenerateKeyPairRsa) { |
// Successful WebCryptoAlgorithmIdRsaEsPkcs1v1_5 key generation. |
const unsigned modulus_length = 256; |
const std::vector<uint8> public_exponent = HexStringToBytes("010001"); |
- blink::WebCryptoAlgorithm algorithm = |
- CreateRsaKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, |
- modulus_length, |
- public_exponent); |
- bool extractable = true; |
+ blink::WebCryptoAlgorithm algorithm = webcrypto::CreateRsaKeyGenAlgorithm( |
+ blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, |
+ modulus_length, |
+ public_exponent); |
+ bool extractable = false; |
const blink::WebCryptoKeyUsageMask usage_mask = 0; |
blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); |
blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull(); |
@@ -901,34 +1142,34 @@ TEST_F(WebCryptoImplTest, GenerateKeyPairRsa) { |
EXPECT_EQ(usage_mask, private_key.usages()); |
// Fail with bad modulus. |
- algorithm = CreateRsaKeyGenAlgorithm( |
+ algorithm = webcrypto::CreateRsaKeyGenAlgorithm( |
blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, 0, public_exponent); |
EXPECT_FALSE(GenerateKeyPairInternal( |
algorithm, extractable, usage_mask, &public_key, &private_key)); |
// Fail with bad exponent: larger than unsigned long. |
- unsigned exponent_length = sizeof(unsigned long) + 1; // NOLINT |
+ unsigned exponent_length = sizeof(unsigned long) + 1; // NOLINT |
const std::vector<uint8> long_exponent(exponent_length, 0x01); |
- algorithm = CreateRsaKeyGenAlgorithm( |
+ algorithm = webcrypto::CreateRsaKeyGenAlgorithm( |
blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, modulus_length, long_exponent); |
EXPECT_FALSE(GenerateKeyPairInternal( |
algorithm, extractable, usage_mask, &public_key, &private_key)); |
// Fail with bad exponent: empty. |
const std::vector<uint8> empty_exponent; |
- algorithm = |
- CreateRsaKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, |
- modulus_length, |
- empty_exponent); |
+ algorithm = webcrypto::CreateRsaKeyGenAlgorithm( |
+ blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, |
+ modulus_length, |
+ empty_exponent); |
EXPECT_FALSE(GenerateKeyPairInternal( |
algorithm, extractable, usage_mask, &public_key, &private_key)); |
// Fail with bad exponent: all zeros. |
std::vector<uint8> exponent_with_leading_zeros(15, 0x00); |
- algorithm = |
- CreateRsaKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, |
- modulus_length, |
- exponent_with_leading_zeros); |
+ algorithm = webcrypto::CreateRsaKeyGenAlgorithm( |
+ blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, |
+ modulus_length, |
+ exponent_with_leading_zeros); |
EXPECT_FALSE(GenerateKeyPairInternal( |
algorithm, extractable, usage_mask, &public_key, &private_key)); |
@@ -936,10 +1177,10 @@ TEST_F(WebCryptoImplTest, GenerateKeyPairRsa) { |
exponent_with_leading_zeros.insert(exponent_with_leading_zeros.end(), |
public_exponent.begin(), |
public_exponent.end()); |
- algorithm = |
- CreateRsaKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, |
- modulus_length, |
- exponent_with_leading_zeros); |
+ algorithm = webcrypto::CreateRsaKeyGenAlgorithm( |
+ blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, |
+ modulus_length, |
+ exponent_with_leading_zeros); |
EXPECT_TRUE(GenerateKeyPairInternal( |
algorithm, extractable, usage_mask, &public_key, &private_key)); |
EXPECT_FALSE(public_key.isNull()); |
@@ -952,7 +1193,7 @@ TEST_F(WebCryptoImplTest, GenerateKeyPairRsa) { |
EXPECT_EQ(usage_mask, private_key.usages()); |
// Successful WebCryptoAlgorithmIdRsaOaep key generation. |
- algorithm = CreateRsaKeyGenAlgorithm( |
+ algorithm = webcrypto::CreateRsaKeyGenAlgorithm( |
blink::WebCryptoAlgorithmIdRsaOaep, modulus_length, public_exponent); |
EXPECT_TRUE(GenerateKeyPairInternal( |
algorithm, extractable, usage_mask, &public_key, &private_key)); |
@@ -966,10 +1207,10 @@ TEST_F(WebCryptoImplTest, GenerateKeyPairRsa) { |
EXPECT_EQ(usage_mask, private_key.usages()); |
// Successful WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 key generation. |
- algorithm = |
- CreateRsaKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, |
- modulus_length, |
- public_exponent); |
+ algorithm = webcrypto::CreateRsaKeyGenAlgorithm( |
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, |
+ modulus_length, |
+ public_exponent); |
EXPECT_TRUE(GenerateKeyPairInternal( |
algorithm, extractable, usage_mask, &public_key, &private_key)); |
EXPECT_FALSE(public_key.isNull()); |
@@ -1018,7 +1259,8 @@ TEST_F(WebCryptoImplTest, RsaEsRoundTrip) { |
// Verify encrypt / decrypt round trip on a few messages. Note that RSA |
// encryption does not support empty input. |
- algorithm = CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5); |
+ algorithm = |
+ webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5); |
const char* const kTestDataHex[] = { |
"ff", |
"0102030405060708090a0b0c0d0e0f", |
@@ -1112,7 +1354,7 @@ TEST_F(WebCryptoImplTest, RsaEsKnownAnswer) { |
// Import the public key. |
const blink::WebCryptoAlgorithm algorithm = |
- CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5); |
+ webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5); |
blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); |
ASSERT_TRUE(ImportKeyInternal( |
blink::WebCryptoKeyFormatSpki, |
@@ -1189,7 +1431,8 @@ TEST_F(WebCryptoImplTest, RsaEsFailures) { |
EXPECT_FALSE(private_key.isNull()); |
// Fail encrypt with a private key. |
- algorithm = CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5); |
+ algorithm = |
+ webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5); |
blink::WebArrayBuffer encrypted_data; |
const std::string message_hex_str("0102030405060708090a0b0c0d0e0f"); |
const std::vector<uint8> message_hex(HexStringToBytes(message_hex_str)); |