Index: content/renderer/webcrypto/webcrypto_impl.cc |
diff --git a/content/renderer/webcrypto/webcrypto_impl.cc b/content/renderer/webcrypto/webcrypto_impl.cc |
index 78df5ba9f81e6358cad1a13a48be42b4b63d5c50..967408f6094ec45c69af7add31e440ff304a861a 100644 |
--- a/content/renderer/webcrypto/webcrypto_impl.cc |
+++ b/content/renderer/webcrypto/webcrypto_impl.cc |
@@ -38,89 +38,127 @@ bool IsAlgorithmAsymmetric(const blink::WebCryptoAlgorithm& algorithm) { |
algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep); |
} |
-// Binds a specific key length value to a compatible factory function. |
-typedef blink::WebCryptoAlgorithm (*AlgFactoryFuncWithOneShortArg)( |
- unsigned short); |
-template <AlgFactoryFuncWithOneShortArg func, unsigned short key_length> |
-blink::WebCryptoAlgorithm BindAlgFactoryWithKeyLen() { |
- return func(key_length); |
-} |
+typedef blink::WebCryptoAlgorithm (*AlgorithmCreationFunc)(); |
-// Binds a WebCryptoAlgorithmId value to a compatible factory function. |
-typedef blink::WebCryptoAlgorithm (*AlgFactoryFuncWithWebCryptoAlgIdArg)( |
- blink::WebCryptoAlgorithmId); |
-template <AlgFactoryFuncWithWebCryptoAlgIdArg func, |
- blink::WebCryptoAlgorithmId algorithm_id> |
-blink::WebCryptoAlgorithm BindAlgFactoryAlgorithmId() { |
- return func(algorithm_id); |
-} |
+class JwkAlgorithmInfo { |
+ public: |
+ JwkAlgorithmInfo() |
+ : creation_func_(NULL), |
+ required_key_length_bytes_(NO_KEY_SIZE_REQUIREMENT) { |
+ |
+ } |
+ |
+ explicit JwkAlgorithmInfo(AlgorithmCreationFunc algorithm_creation_func) |
+ : creation_func_(algorithm_creation_func), |
+ required_key_length_bytes_(NO_KEY_SIZE_REQUIREMENT) { |
+ } |
+ |
+ JwkAlgorithmInfo(AlgorithmCreationFunc algorithm_creation_func, |
+ unsigned int required_key_length_bits) |
+ : creation_func_(algorithm_creation_func), |
+ required_key_length_bytes_(required_key_length_bits / 8) { |
+ DCHECK((required_key_length_bits % 8) == 0); |
+ } |
+ |
+ bool CreateAlgorithm(blink::WebCryptoAlgorithm* algorithm) const { |
+ *algorithm = creation_func_(); |
+ return !algorithm->isNull(); |
+ } |
+ |
+ bool IsInvalidKeyByteLength(size_t byte_length) const { |
+ if (required_key_length_bytes_ == NO_KEY_SIZE_REQUIREMENT) |
+ return false; |
+ return required_key_length_bytes_ != byte_length; |
+ } |
-// Defines a map between a JWK 'alg' string ID and a corresponding Web Crypto |
-// factory function. |
-typedef blink::WebCryptoAlgorithm (*AlgFactoryFuncNoArgs)(); |
-typedef std::map<std::string, AlgFactoryFuncNoArgs> JwkAlgFactoryMap; |
+ private: |
+ enum { NO_KEY_SIZE_REQUIREMENT = UINT_MAX }; |
+ |
+ AlgorithmCreationFunc creation_func_; |
-class JwkAlgorithmFactoryMap { |
+ // The expected key size for the algorithm or NO_KEY_SIZE_REQUIREMENT. |
+ unsigned int required_key_length_bytes_; |
+ |
+}; |
+ |
+typedef std::map<std::string, JwkAlgorithmInfo> JwkAlgorithmInfoMap; |
+ |
+class JwkAlgorithmRegistry { |
public: |
- JwkAlgorithmFactoryMap() { |
- map_["HS256"] = |
- &BindAlgFactoryAlgorithmId<webcrypto::CreateHmacAlgorithmByHashId, |
- blink::WebCryptoAlgorithmIdSha256>; |
- map_["HS384"] = |
- &BindAlgFactoryAlgorithmId<webcrypto::CreateHmacAlgorithmByHashId, |
- blink::WebCryptoAlgorithmIdSha384>; |
- map_["HS512"] = |
- &BindAlgFactoryAlgorithmId<webcrypto::CreateHmacAlgorithmByHashId, |
- blink::WebCryptoAlgorithmIdSha512>; |
- map_["RS256"] = |
- &BindAlgFactoryAlgorithmId<webcrypto::CreateRsaSsaAlgorithm, |
- blink::WebCryptoAlgorithmIdSha256>; |
- map_["RS384"] = |
- &BindAlgFactoryAlgorithmId<webcrypto::CreateRsaSsaAlgorithm, |
- blink::WebCryptoAlgorithmIdSha384>; |
- map_["RS512"] = |
- &BindAlgFactoryAlgorithmId<webcrypto::CreateRsaSsaAlgorithm, |
- blink::WebCryptoAlgorithmIdSha512>; |
- map_["RSA1_5"] = |
- &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm, |
- blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5>; |
- map_["RSA-OAEP"] = |
- &BindAlgFactoryAlgorithmId<webcrypto::CreateRsaOaepAlgorithm, |
- blink::WebCryptoAlgorithmIdSha1>; |
+ JwkAlgorithmRegistry() { |
+ // TODO(eroman): |
+ // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-20 |
+ // says HMAC with SHA-2 should have a key size at least as large as the |
+ // hash output. |
+ alg_to_info_["HS256"] = JwkAlgorithmInfo( |
+ &BindAlgorithmId<webcrypto::CreateHmacAlgorithmByHashId, |
+ blink::WebCryptoAlgorithmIdSha256>); |
+ alg_to_info_["HS384"] = JwkAlgorithmInfo( |
+ &BindAlgorithmId<webcrypto::CreateHmacAlgorithmByHashId, |
+ blink::WebCryptoAlgorithmIdSha384>); |
+ alg_to_info_["HS512"] = JwkAlgorithmInfo( |
+ &BindAlgorithmId<webcrypto::CreateHmacAlgorithmByHashId, |
+ blink::WebCryptoAlgorithmIdSha512>); |
+ alg_to_info_["RS256"] = JwkAlgorithmInfo( |
+ &BindAlgorithmId<webcrypto::CreateRsaSsaAlgorithm, |
+ blink::WebCryptoAlgorithmIdSha256>); |
+ alg_to_info_["RS384"] = JwkAlgorithmInfo( |
+ &BindAlgorithmId<webcrypto::CreateRsaSsaAlgorithm, |
+ blink::WebCryptoAlgorithmIdSha384>); |
+ alg_to_info_["RS512"] = JwkAlgorithmInfo( |
+ &BindAlgorithmId<webcrypto::CreateRsaSsaAlgorithm, |
+ blink::WebCryptoAlgorithmIdSha512>); |
+ alg_to_info_["RSA1_5"] = JwkAlgorithmInfo( |
+ &BindAlgorithmId<webcrypto::CreateAlgorithm, |
+ blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5>); |
+ alg_to_info_["RSA-OAEP"] = JwkAlgorithmInfo( |
+ &BindAlgorithmId<webcrypto::CreateRsaOaepAlgorithm, |
+ blink::WebCryptoAlgorithmIdSha1>); |
// TODO(padolph): The Web Crypto spec does not enumerate AES-KW 128 yet |
- map_["A128KW"] = &blink::WebCryptoAlgorithm::createNull; |
+ alg_to_info_["A128KW"] = |
+ JwkAlgorithmInfo(&blink::WebCryptoAlgorithm::createNull, 128); |
// TODO(padolph): The Web Crypto spec does not enumerate AES-KW 256 yet |
- map_["A256KW"] = &blink::WebCryptoAlgorithm::createNull; |
- map_["A128GCM"] = |
- &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm, |
- blink::WebCryptoAlgorithmIdAesGcm>; |
- map_["A256GCM"] = |
- &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm, |
- blink::WebCryptoAlgorithmIdAesGcm>; |
- map_["A128CBC"] = |
- &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm, |
- blink::WebCryptoAlgorithmIdAesCbc>; |
- map_["A192CBC"] = |
- &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm, |
- blink::WebCryptoAlgorithmIdAesCbc>; |
- map_["A256CBC"] = |
- &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm, |
- blink::WebCryptoAlgorithmIdAesCbc>; |
+ alg_to_info_["A256KW"] = |
+ JwkAlgorithmInfo(&blink::WebCryptoAlgorithm::createNull, 256); |
+ alg_to_info_["A128GCM"] = JwkAlgorithmInfo( |
+ &BindAlgorithmId<webcrypto::CreateAlgorithm, |
+ blink::WebCryptoAlgorithmIdAesGcm>, 128); |
+ alg_to_info_["A256GCM"] = JwkAlgorithmInfo( |
+ &BindAlgorithmId<webcrypto::CreateAlgorithm, |
+ blink::WebCryptoAlgorithmIdAesGcm>, 256); |
+ alg_to_info_["A128CBC"] = JwkAlgorithmInfo( |
+ &BindAlgorithmId<webcrypto::CreateAlgorithm, |
+ blink::WebCryptoAlgorithmIdAesCbc>, 128); |
+ alg_to_info_["A192CBC"] = JwkAlgorithmInfo( |
+ &BindAlgorithmId<webcrypto::CreateAlgorithm, |
+ blink::WebCryptoAlgorithmIdAesCbc>, 192); |
+ alg_to_info_["A256CBC"] = JwkAlgorithmInfo( |
+ &BindAlgorithmId<webcrypto::CreateAlgorithm, |
+ blink::WebCryptoAlgorithmIdAesCbc>, 256); |
} |
- blink::WebCryptoAlgorithm CreateAlgorithmFromName(const std::string& alg_id) |
- const { |
- const JwkAlgFactoryMap::const_iterator pos = map_.find(alg_id); |
- if (pos == map_.end()) |
- return blink::WebCryptoAlgorithm::createNull(); |
- return pos->second(); |
+ // Returns NULL if the algorithm name was not registered. |
+ const JwkAlgorithmInfo* GetAlgorithmInfo(const std::string& jwk_alg) const { |
+ const JwkAlgorithmInfoMap::const_iterator pos = alg_to_info_.find(jwk_alg); |
+ if (pos == alg_to_info_.end()) |
+ return NULL; |
+ return &pos->second; |
} |
private: |
- JwkAlgFactoryMap map_; |
+ // Binds a WebCryptoAlgorithmId value to a compatible factory function. |
+ typedef blink::WebCryptoAlgorithm (*FuncWithWebCryptoAlgIdArg)( |
+ blink::WebCryptoAlgorithmId); |
+ template <FuncWithWebCryptoAlgIdArg func, |
+ blink::WebCryptoAlgorithmId algorithm_id> |
+ static blink::WebCryptoAlgorithm BindAlgorithmId() { |
+ return func(algorithm_id); |
+ } |
+ |
+ JwkAlgorithmInfoMap alg_to_info_; |
}; |
-base::LazyInstance<JwkAlgorithmFactoryMap> jwk_alg_factory = |
+base::LazyInstance<JwkAlgorithmRegistry> jwk_alg_registry = |
LAZY_INSTANCE_INITIALIZER; |
bool WebCryptoAlgorithmsConsistent(const blink::WebCryptoAlgorithm& alg1, |
@@ -161,12 +199,8 @@ bool GetDecodedUrl64ValueByKey( |
const std::string& key, |
std::string* decoded) { |
std::string value_url64; |
- if (!dict.GetString(key, &value_url64) || |
- !webcrypto::Base64DecodeUrlSafe(value_url64, decoded) || |
- !decoded->size()) { |
- return false; |
- } |
- return true; |
+ return dict.GetString(key, &value_url64) && |
+ webcrypto::Base64DecodeUrlSafe(value_url64, decoded); |
} |
} // namespace |
@@ -530,6 +564,7 @@ Status WebCryptoImpl::ImportKeyJwk( |
// 6. JWK alg missing AND input algorithm specified: use input value |
// TODO(eroman): Should error if "alg" was specified but not a string. |
blink::WebCryptoAlgorithm algorithm = blink::WebCryptoAlgorithm::createNull(); |
+ const JwkAlgorithmInfo* algorithm_info = NULL; |
std::string jwk_alg_value; |
if (dict_value->GetString("alg", &jwk_alg_value)) { |
// JWK alg present |
@@ -537,12 +572,12 @@ Status WebCryptoImpl::ImportKeyJwk( |
// TODO(padolph): Validate alg vs kty. For example kty="RSA" implies alg can |
// only be from the RSA family. |
- const blink::WebCryptoAlgorithm jwk_algorithm = |
- jwk_alg_factory.Get().CreateAlgorithmFromName(jwk_alg_value); |
- if (jwk_algorithm.isNull()) { |
- // JWK alg unrecognized |
+ blink::WebCryptoAlgorithm jwk_algorithm = |
+ blink::WebCryptoAlgorithm::createNull(); |
+ algorithm_info = jwk_alg_registry.Get().GetAlgorithmInfo(jwk_alg_value); |
+ if (!algorithm_info || !algorithm_info->CreateAlgorithm(&jwk_algorithm)) |
return Status::ErrorJwkUnrecognizedAlgorithm(); // case 1 |
- } |
+ |
// JWK alg valid |
if (algorithm_or_null.isNull()) { |
// input algorithm not specified |
@@ -591,11 +626,16 @@ Status WebCryptoImpl::ImportKeyJwk( |
if (!GetDecodedUrl64ValueByKey(*dict_value, "k", &jwk_k_value)) |
return Status::ErrorJwkDecodeK(); |
- // TODO(padolph): Some JWK alg ID's embed information about the key length |
- // in the alg ID string. For example "A128" implies the JWK carries 128 bits |
- // of key material, and "HS512" implies the JWK carries _at least_ 512 bits |
- // of key material. For such keys validate the actual key length against the |
- // value in the ID. |
+ // Some JWK alg ID's embed information about the key length in the alg ID |
+ // string. For example "A128CBC" implies the JWK carries 128 bits |
+ // of key material. For such keys validate that enough bytes were provided. |
+ // If this validation is not done, then it would be possible to select a |
+ // different algorithm by passing a different lengthed key, since that is |
+ // how WebCrypto interprets things. |
+ if (algorithm_info && |
+ algorithm_info->IsInvalidKeyByteLength(jwk_k_value.size())) { |
+ return Status::ErrorJwkIncorrectKeyLength(); |
+ } |
return ImportKeyInternal(blink::WebCryptoKeyFormatRaw, |
reinterpret_cast<const uint8*>(jwk_k_value.data()), |