Commit 9c2e9cf7 authored by eroman@chromium.org's avatar eroman@chromium.org

[webcryto] Validate key usages during key creation.

 (1) Key creation (whether by importKey(), unwrapKey(), generateKey() now fails if the requested key usages are not applicable (for instance asking for 'sign' on an AES-CBC key).
 (2) When generating a key pair, the public/private key get the intersection of supported usages and requested ones.
 (3) The exceptions thrown during the import phase of unwrapKey() are now surfaced to the caller (bug 372944)

BUG=372040,372944,245025
R=rsleevi@chromium.org

Review URL: https://codereview.chromium.org/282133002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@272630 0039d316-1c4b-4281-b951-d872f2087c98
parent a95539cf
...@@ -509,12 +509,6 @@ Status GetOptionalJwkBool(base::DictionaryValue* dict, ...@@ -509,12 +509,6 @@ Status GetOptionalJwkBool(base::DictionaryValue* dict,
return Status::Success(); return Status::Success();
} }
// Returns true if the set bits in b make up a subset of the set bits in a.
bool ContainsKeyUsages(blink::WebCryptoKeyUsageMask a,
blink::WebCryptoKeyUsageMask b) {
return (a & b) == b;
}
// Writes a secret/symmetric key to a JWK dictionary. // Writes a secret/symmetric key to a JWK dictionary.
void WriteSecretKey(const std::vector<uint8>& raw_key, void WriteSecretKey(const std::vector<uint8>& raw_key,
base::DictionaryValue* jwk_dict) { base::DictionaryValue* jwk_dict) {
...@@ -714,9 +708,7 @@ Status WriteAlg(const blink::WebCryptoKeyAlgorithm& algorithm, ...@@ -714,9 +708,7 @@ Status WriteAlg(const blink::WebCryptoKeyAlgorithm& algorithm,
} }
bool IsRsaKey(const blink::WebCryptoKey& key) { bool IsRsaKey(const blink::WebCryptoKey& key) {
const blink::WebCryptoAlgorithmId algorithm_id = key.algorithm().id(); return IsAlgorithmRsa(key.algorithm().id());
return algorithm_id == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 ||
algorithm_id == blink::WebCryptoAlgorithmIdRsaOaep;
} }
Status ImportRsaKey(base::DictionaryValue* dict, Status ImportRsaKey(base::DictionaryValue* dict,
...@@ -738,7 +730,19 @@ Status ImportRsaKey(base::DictionaryValue* dict, ...@@ -738,7 +730,19 @@ Status ImportRsaKey(base::DictionaryValue* dict,
if (status.IsError()) if (status.IsError())
return status; return status;
if (!dict->HasKey("d")) { bool is_public_key = !dict->HasKey("d");
// Now that the key type is known, do an additional check on the usages to
// make sure they are all applicable for this algorithm + key type.
status = CheckKeyUsages(algorithm.id(),
is_public_key ? blink::WebCryptoKeyTypePublic
: blink::WebCryptoKeyTypePrivate,
usage_mask);
if (status.IsError())
return status;
if (is_public_key) {
return platform::ImportRsaPublicKey(algorithm, return platform::ImportRsaPublicKey(algorithm,
extractable, extractable,
usage_mask, usage_mask,
......
...@@ -158,6 +158,7 @@ Status VerifyRsaSsaPkcs1v1_5(PublicKey* key, ...@@ -158,6 +158,7 @@ Status VerifyRsaSsaPkcs1v1_5(PublicKey* key,
// * algorithm.id() is for a symmetric key algorithm. // * algorithm.id() is for a symmetric key algorithm.
// * keylen_bytes is non-zero (TODO(eroman): revisit this). // * keylen_bytes is non-zero (TODO(eroman): revisit this).
// * For AES algorithms |keylen_bytes| is either 16, 24, or 32 bytes long. // * For AES algorithms |keylen_bytes| is either 16, 24, or 32 bytes long.
// * usage_mask makes sense for the algorithm.
Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm, Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm,
bool extractable, bool extractable,
blink::WebCryptoKeyUsageMask usage_mask, blink::WebCryptoKeyUsageMask usage_mask,
...@@ -170,9 +171,11 @@ Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm, ...@@ -170,9 +171,11 @@ Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm,
// is in algorithm. They are split out for convenience. // is in algorithm. They are split out for convenience.
// * modulus_length_bits is not 0 // * modulus_length_bits is not 0
// * public_exponent is not empty. // * public_exponent is not empty.
// * {public|private}_key_usage_mask make sense for the algorithm.
Status GenerateRsaKeyPair(const blink::WebCryptoAlgorithm& algorithm, Status GenerateRsaKeyPair(const blink::WebCryptoAlgorithm& algorithm,
bool extractable, bool extractable,
blink::WebCryptoKeyUsageMask usage_mask, blink::WebCryptoKeyUsageMask public_key_usage_mask,
blink::WebCryptoKeyUsageMask private_key_usage_mask,
unsigned int modulus_length_bits, unsigned int modulus_length_bits,
const CryptoData& public_exponent, const CryptoData& public_exponent,
blink::WebCryptoKey* public_key, blink::WebCryptoKey* public_key,
...@@ -182,6 +185,7 @@ Status GenerateRsaKeyPair(const blink::WebCryptoAlgorithm& algorithm, ...@@ -182,6 +185,7 @@ Status GenerateRsaKeyPair(const blink::WebCryptoAlgorithm& algorithm,
// * |key| is non-null. // * |key| is non-null.
// * |algorithm.id()| is for a symmetric key algorithm. // * |algorithm.id()| is for a symmetric key algorithm.
// * For AES algorithms |key_data| is either 16, 24, or 32 bytes long. // * For AES algorithms |key_data| is either 16, 24, or 32 bytes long.
// * usage_mask makes sense for the algorithm.
// Note that this may be called from target Blink thread. // Note that this may be called from target Blink thread.
Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm, Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm,
const CryptoData& key_data, const CryptoData& key_data,
...@@ -191,6 +195,7 @@ Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm, ...@@ -191,6 +195,7 @@ Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm,
// Preconditions: // Preconditions:
// * algorithm.id() is for an RSA algorithm. // * algorithm.id() is for an RSA algorithm.
// * usage_mask makes sense for the algorithm.
Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm, Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm,
bool extractable, bool extractable,
blink::WebCryptoKeyUsageMask usage_mask, blink::WebCryptoKeyUsageMask usage_mask,
...@@ -203,6 +208,7 @@ Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm, ...@@ -203,6 +208,7 @@ Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm,
// * modulus, public_exponent, and private_exponent will be non-empty. The // * modulus, public_exponent, and private_exponent will be non-empty. The
// others will either all be specified (non-empty), or all be unspecified // others will either all be specified (non-empty), or all be unspecified
// (empty). // (empty).
// * usage_mask makes sense for the algorithm.
Status ImportRsaPrivateKey(const blink::WebCryptoAlgorithm& algorithm, Status ImportRsaPrivateKey(const blink::WebCryptoAlgorithm& algorithm,
bool extractable, bool extractable,
blink::WebCryptoKeyUsageMask usage_mask, blink::WebCryptoKeyUsageMask usage_mask,
...@@ -217,6 +223,8 @@ Status ImportRsaPrivateKey(const blink::WebCryptoAlgorithm& algorithm, ...@@ -217,6 +223,8 @@ Status ImportRsaPrivateKey(const blink::WebCryptoAlgorithm& algorithm,
blink::WebCryptoKey* key); blink::WebCryptoKey* key);
// Note that this may be called from target Blink thread. // Note that this may be called from target Blink thread.
// Preconditions:
// * usage_mask makes sense for the algorithm.
Status ImportKeySpki(const blink::WebCryptoAlgorithm& algorithm, Status ImportKeySpki(const blink::WebCryptoAlgorithm& algorithm,
const CryptoData& key_data, const CryptoData& key_data,
bool extractable, bool extractable,
...@@ -224,6 +232,8 @@ Status ImportKeySpki(const blink::WebCryptoAlgorithm& algorithm, ...@@ -224,6 +232,8 @@ Status ImportKeySpki(const blink::WebCryptoAlgorithm& algorithm,
blink::WebCryptoKey* key); blink::WebCryptoKey* key);
// Note that this may be called from target Blink thread. // Note that this may be called from target Blink thread.
// Preconditions:
// * usage_mask makes sense for the algorithm.
Status ImportKeyPkcs8(const blink::WebCryptoAlgorithm& algorithm, Status ImportKeyPkcs8(const blink::WebCryptoAlgorithm& algorithm,
const CryptoData& key_data, const CryptoData& key_data,
bool extractable, bool extractable,
...@@ -278,6 +288,7 @@ Status WrapSymKeyAesKw(SymKey* key, ...@@ -278,6 +288,7 @@ Status WrapSymKeyAesKw(SymKey* key,
// * |key| is non-null // * |key| is non-null
// * |wrapped_key_data| is at least 24 bytes and a multiple of 8 bytes // * |wrapped_key_data| is at least 24 bytes and a multiple of 8 bytes
// * |algorithm.id()| is for a symmetric key algorithm. // * |algorithm.id()| is for a symmetric key algorithm.
// * usage_mask makes sense for the algorithm.
Status UnwrapSymKeyAesKw(const CryptoData& wrapped_key_data, Status UnwrapSymKeyAesKw(const CryptoData& wrapped_key_data,
SymKey* wrapping_key, SymKey* wrapping_key,
const blink::WebCryptoAlgorithm& algorithm, const blink::WebCryptoAlgorithm& algorithm,
......
...@@ -1440,7 +1440,8 @@ Status EncryptDecryptAesGcm(EncryptOrDecrypt mode, ...@@ -1440,7 +1440,8 @@ Status EncryptDecryptAesGcm(EncryptOrDecrypt mode,
Status GenerateRsaKeyPair(const blink::WebCryptoAlgorithm& algorithm, Status GenerateRsaKeyPair(const blink::WebCryptoAlgorithm& algorithm,
bool extractable, bool extractable,
blink::WebCryptoKeyUsageMask usage_mask, blink::WebCryptoKeyUsageMask public_key_usage_mask,
blink::WebCryptoKeyUsageMask private_key_usage_mask,
unsigned int modulus_length_bits, unsigned int modulus_length_bits,
const CryptoData& public_exponent, const CryptoData& public_exponent,
blink::WebCryptoKey* public_key, blink::WebCryptoKey* public_key,
...@@ -1523,12 +1524,12 @@ Status GenerateRsaKeyPair(const blink::WebCryptoAlgorithm& algorithm, ...@@ -1523,12 +1524,12 @@ Status GenerateRsaKeyPair(const blink::WebCryptoAlgorithm& algorithm,
blink::WebCryptoKeyTypePublic, blink::WebCryptoKeyTypePublic,
true, true,
key_algorithm, key_algorithm,
usage_mask); public_key_usage_mask);
*private_key = blink::WebCryptoKey::create(private_key_handle.release(), *private_key = blink::WebCryptoKey::create(private_key_handle.release(),
blink::WebCryptoKeyTypePrivate, blink::WebCryptoKeyTypePrivate,
extractable, extractable,
key_algorithm, key_algorithm,
usage_mask); private_key_usage_mask);
return Status::Success(); return Status::Success();
} }
......
...@@ -300,7 +300,8 @@ Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm, ...@@ -300,7 +300,8 @@ Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm,
Status GenerateRsaKeyPair(const blink::WebCryptoAlgorithm& algorithm, Status GenerateRsaKeyPair(const blink::WebCryptoAlgorithm& algorithm,
bool extractable, bool extractable,
blink::WebCryptoKeyUsageMask usage_mask, blink::WebCryptoKeyUsageMask public_key_usage_mask,
blink::WebCryptoKeyUsageMask private_key_usage_mask,
unsigned int modulus_length_bits, unsigned int modulus_length_bits,
const CryptoData& public_exponent, const CryptoData& public_exponent,
blink::WebCryptoKey* public_key, blink::WebCryptoKey* public_key,
......
This diff is collapsed.
...@@ -174,6 +174,12 @@ Status ToPlatformPublicKey(const blink::WebCryptoKey& key, ...@@ -174,6 +174,12 @@ Status ToPlatformPublicKey(const blink::WebCryptoKey& key,
Status ToPlatformPrivateKey(const blink::WebCryptoKey& key, Status ToPlatformPrivateKey(const blink::WebCryptoKey& key,
platform::PrivateKey** out); platform::PrivateKey** out);
// Returns Staus::Success() if |usages| is valid for |key_type| and |algorithm|.
// Otherwise returns a failure
Status CheckKeyUsages(blink::WebCryptoAlgorithmId algorithm,
blink::WebCryptoKeyType key_type,
blink::WebCryptoKeyUsageMask usages);
} // namespace webcrypto } // namespace webcrypto
} // namespace content } // namespace content
......
...@@ -198,6 +198,11 @@ Status Status::ErrorGenerateKeyLength() { ...@@ -198,6 +198,11 @@ Status Status::ErrorGenerateKeyLength() {
"bits"); "bits");
} }
Status Status::ErrorCreateKeyBadUsages() {
return Status(blink::WebCryptoErrorTypeData,
"Cannot create a key using the specified key usages.");
}
Status::Status(blink::WebCryptoErrorType error_type, Status::Status(blink::WebCryptoErrorType error_type,
const std::string& error_details_utf8) const std::string& error_details_utf8)
: type_(TYPE_ERROR), : type_(TYPE_ERROR),
......
...@@ -19,11 +19,6 @@ namespace webcrypto { ...@@ -19,11 +19,6 @@ namespace webcrypto {
// //
// As such, it is important that errors DO NOT reveal any sensitive material // As such, it is important that errors DO NOT reveal any sensitive material
// (like key bytes). // (like key bytes).
//
// Care must be taken with what errors are reported back to Blink when doing
// compound operations like unwrapping a JWK key. In this case, errors
// generated by the JWK import are not appropriate to report since the wrapped
// JWK is not visible to the caller.
class CONTENT_EXPORT Status { class CONTENT_EXPORT Status {
public: public:
Status() : type_(TYPE_ERROR) {} Status() : type_(TYPE_ERROR) {}
...@@ -187,6 +182,11 @@ class CONTENT_EXPORT Status { ...@@ -187,6 +182,11 @@ class CONTENT_EXPORT Status {
// zero, or it was not a multiple of 8 bits. // zero, or it was not a multiple of 8 bits.
static Status ErrorGenerateKeyLength(); static Status ErrorGenerateKeyLength();
// Attempted to create a key (either by importKey(), generateKey(), or
// unwrapKey()) however the key usages were not applicable for the key type
// and algorithm.
static Status ErrorCreateKeyBadUsages();
private: private:
enum Type { TYPE_ERROR, TYPE_SUCCESS }; enum Type { TYPE_ERROR, TYPE_SUCCESS };
......
...@@ -134,12 +134,6 @@ void CompleteWithKeyOrError(const Status& status, ...@@ -134,12 +134,6 @@ void CompleteWithKeyOrError(const Status& status,
} }
} }
bool IsAlgorithmAsymmetric(const blink::WebCryptoAlgorithm& algorithm) {
// TODO(padolph): include all other asymmetric algorithms once they are
// defined, e.g. EC and DH.
return webcrypto::IsAlgorithmRsa(algorithm.id());
}
// Gets a task runner for the current thread. The current thread is either: // Gets a task runner for the current thread. The current thread is either:
// //
// * The main Blink thread // * The main Blink thread
...@@ -405,7 +399,8 @@ void DoGenerateKeyReply(scoped_ptr<GenerateKeyState> state) { ...@@ -405,7 +399,8 @@ void DoGenerateKeyReply(scoped_ptr<GenerateKeyState> state) {
void DoGenerateKey(scoped_ptr<GenerateKeyState> passed_state) { void DoGenerateKey(scoped_ptr<GenerateKeyState> passed_state) {
GenerateKeyState* state = passed_state.get(); GenerateKeyState* state = passed_state.get();
state->is_asymmetric = IsAlgorithmAsymmetric(state->algorithm); state->is_asymmetric =
webcrypto::IsAlgorithmAsymmetric(state->algorithm.id());
if (state->is_asymmetric) { if (state->is_asymmetric) {
state->status = webcrypto::GenerateKeyPair(state->algorithm, state->status = webcrypto::GenerateKeyPair(state->algorithm,
state->extractable, state->extractable,
...@@ -420,8 +415,6 @@ void DoGenerateKey(scoped_ptr<GenerateKeyState> passed_state) { ...@@ -420,8 +415,6 @@ void DoGenerateKey(scoped_ptr<GenerateKeyState> passed_state) {
DCHECK_EQ(state->algorithm.id(), state->private_key.algorithm().id()); DCHECK_EQ(state->algorithm.id(), state->private_key.algorithm().id());
DCHECK_EQ(true, state->public_key.extractable()); DCHECK_EQ(true, state->public_key.extractable());
DCHECK_EQ(state->extractable, state->private_key.extractable()); DCHECK_EQ(state->extractable, state->private_key.extractable());
DCHECK_EQ(state->usage_mask, state->public_key.usages());
DCHECK_EQ(state->usage_mask, state->private_key.usages());
} }
} else { } else {
blink::WebCryptoKey* key = &state->public_key; blink::WebCryptoKey* key = &state->public_key;
......
...@@ -179,11 +179,22 @@ bool CreateSecretKeyAlgorithm(const blink::WebCryptoAlgorithm& algorithm, ...@@ -179,11 +179,22 @@ bool CreateSecretKeyAlgorithm(const blink::WebCryptoAlgorithm& algorithm,
} }
} }
bool ContainsKeyUsages(blink::WebCryptoKeyUsageMask a,
blink::WebCryptoKeyUsageMask b) {
return (a & b) == b;
}
bool IsAlgorithmRsa(blink::WebCryptoAlgorithmId alg_id) { bool IsAlgorithmRsa(blink::WebCryptoAlgorithmId alg_id) {
return alg_id == blink::WebCryptoAlgorithmIdRsaOaep || return alg_id == blink::WebCryptoAlgorithmIdRsaOaep ||
alg_id == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5; alg_id == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5;
} }
bool IsAlgorithmAsymmetric(blink::WebCryptoAlgorithmId alg_id) {
// TODO(padolph): include all other asymmetric algorithms once they are
// defined, e.g. EC and DH.
return IsAlgorithmRsa(alg_id);
}
} // namespace webcrypto } // namespace webcrypto
} // namespace content } // namespace content
...@@ -71,7 +71,12 @@ bool CreateSecretKeyAlgorithm(const blink::WebCryptoAlgorithm& algorithm, ...@@ -71,7 +71,12 @@ bool CreateSecretKeyAlgorithm(const blink::WebCryptoAlgorithm& algorithm,
unsigned int keylen_bytes, unsigned int keylen_bytes,
blink::WebCryptoKeyAlgorithm* key_algorithm); blink::WebCryptoKeyAlgorithm* key_algorithm);
// Returns true if the set bits in b make up a subset of the set bits in a.
bool ContainsKeyUsages(blink::WebCryptoKeyUsageMask a,
blink::WebCryptoKeyUsageMask b);
bool IsAlgorithmRsa(blink::WebCryptoAlgorithmId alg_id); bool IsAlgorithmRsa(blink::WebCryptoAlgorithmId alg_id);
bool IsAlgorithmAsymmetric(blink::WebCryptoAlgorithmId alg_id);
} // namespace webcrypto } // namespace webcrypto
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment