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

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

Issue 141853006: [webcrypto] Validate JWK import of AES keys: key length must match algorithm. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 10 months 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
« no previous file with comments | « no previous file | content/renderer/webcrypto/webcrypto_impl_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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()),
« no previous file with comments | « no previous file | content/renderer/webcrypto/webcrypto_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698