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,
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.
void WriteSecretKey(const std::vector<uint8>& raw_key,
base::DictionaryValue* jwk_dict) {
......@@ -714,9 +708,7 @@ Status WriteAlg(const blink::WebCryptoKeyAlgorithm& algorithm,
}
bool IsRsaKey(const blink::WebCryptoKey& key) {
const blink::WebCryptoAlgorithmId algorithm_id = key.algorithm().id();
return algorithm_id == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 ||
algorithm_id == blink::WebCryptoAlgorithmIdRsaOaep;
return IsAlgorithmRsa(key.algorithm().id());
}
Status ImportRsaKey(base::DictionaryValue* dict,
......@@ -738,7 +730,19 @@ Status ImportRsaKey(base::DictionaryValue* dict,
if (status.IsError())
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,
extractable,
usage_mask,
......
......@@ -158,6 +158,7 @@ Status VerifyRsaSsaPkcs1v1_5(PublicKey* key,
// * algorithm.id() is for a symmetric key algorithm.
// * keylen_bytes is non-zero (TODO(eroman): revisit this).
// * 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,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
......@@ -170,9 +171,11 @@ Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm,
// is in algorithm. They are split out for convenience.
// * modulus_length_bits is not 0
// * public_exponent is not empty.
// * {public|private}_key_usage_mask make sense for the algorithm.
Status GenerateRsaKeyPair(const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKeyUsageMask public_key_usage_mask,
blink::WebCryptoKeyUsageMask private_key_usage_mask,
unsigned int modulus_length_bits,
const CryptoData& public_exponent,
blink::WebCryptoKey* public_key,
......@@ -182,6 +185,7 @@ Status GenerateRsaKeyPair(const blink::WebCryptoAlgorithm& algorithm,
// * |key| is non-null.
// * |algorithm.id()| is for a symmetric key algorithm.
// * 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.
Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm,
const CryptoData& key_data,
......@@ -191,6 +195,7 @@ Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm,
// Preconditions:
// * algorithm.id() is for an RSA algorithm.
// * usage_mask makes sense for the algorithm.
Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
......@@ -203,6 +208,7 @@ Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm,
// * modulus, public_exponent, and private_exponent will be non-empty. The
// others will either all be specified (non-empty), or all be unspecified
// (empty).
// * usage_mask makes sense for the algorithm.
Status ImportRsaPrivateKey(const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
......@@ -217,6 +223,8 @@ Status ImportRsaPrivateKey(const blink::WebCryptoAlgorithm& algorithm,
blink::WebCryptoKey* key);
// Note that this may be called from target Blink thread.
// Preconditions:
// * usage_mask makes sense for the algorithm.
Status ImportKeySpki(const blink::WebCryptoAlgorithm& algorithm,
const CryptoData& key_data,
bool extractable,
......@@ -224,6 +232,8 @@ Status ImportKeySpki(const blink::WebCryptoAlgorithm& algorithm,
blink::WebCryptoKey* key);
// Note that this may be called from target Blink thread.
// Preconditions:
// * usage_mask makes sense for the algorithm.
Status ImportKeyPkcs8(const blink::WebCryptoAlgorithm& algorithm,
const CryptoData& key_data,
bool extractable,
......@@ -278,6 +288,7 @@ Status WrapSymKeyAesKw(SymKey* key,
// * |key| is non-null
// * |wrapped_key_data| is at least 24 bytes and a multiple of 8 bytes
// * |algorithm.id()| is for a symmetric key algorithm.
// * usage_mask makes sense for the algorithm.
Status UnwrapSymKeyAesKw(const CryptoData& wrapped_key_data,
SymKey* wrapping_key,
const blink::WebCryptoAlgorithm& algorithm,
......
......@@ -1440,7 +1440,8 @@ Status EncryptDecryptAesGcm(EncryptOrDecrypt mode,
Status GenerateRsaKeyPair(const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKeyUsageMask public_key_usage_mask,
blink::WebCryptoKeyUsageMask private_key_usage_mask,
unsigned int modulus_length_bits,
const CryptoData& public_exponent,
blink::WebCryptoKey* public_key,
......@@ -1523,12 +1524,12 @@ Status GenerateRsaKeyPair(const blink::WebCryptoAlgorithm& algorithm,
blink::WebCryptoKeyTypePublic,
true,
key_algorithm,
usage_mask);
public_key_usage_mask);
*private_key = blink::WebCryptoKey::create(private_key_handle.release(),
blink::WebCryptoKeyTypePrivate,
extractable,
key_algorithm,
usage_mask);
private_key_usage_mask);
return Status::Success();
}
......
......@@ -300,7 +300,8 @@ Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm,
Status GenerateRsaKeyPair(const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKeyUsageMask public_key_usage_mask,
blink::WebCryptoKeyUsageMask private_key_usage_mask,
unsigned int modulus_length_bits,
const CryptoData& public_exponent,
blink::WebCryptoKey* public_key,
......
This diff is collapsed.
......@@ -174,6 +174,12 @@ Status ToPlatformPublicKey(const blink::WebCryptoKey& key,
Status ToPlatformPrivateKey(const blink::WebCryptoKey& key,
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 content
......
......@@ -198,6 +198,11 @@ Status Status::ErrorGenerateKeyLength() {
"bits");
}
Status Status::ErrorCreateKeyBadUsages() {
return Status(blink::WebCryptoErrorTypeData,
"Cannot create a key using the specified key usages.");
}
Status::Status(blink::WebCryptoErrorType error_type,
const std::string& error_details_utf8)
: type_(TYPE_ERROR),
......
......@@ -19,11 +19,6 @@ namespace webcrypto {
//
// As such, it is important that errors DO NOT reveal any sensitive material
// (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 {
public:
Status() : type_(TYPE_ERROR) {}
......@@ -187,6 +182,11 @@ class CONTENT_EXPORT Status {
// zero, or it was not a multiple of 8 bits.
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:
enum Type { TYPE_ERROR, TYPE_SUCCESS };
......
......@@ -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:
//
// * The main Blink thread
......@@ -405,7 +399,8 @@ void DoGenerateKeyReply(scoped_ptr<GenerateKeyState> state) {
void DoGenerateKey(scoped_ptr<GenerateKeyState> passed_state) {
GenerateKeyState* state = passed_state.get();
state->is_asymmetric = IsAlgorithmAsymmetric(state->algorithm);
state->is_asymmetric =
webcrypto::IsAlgorithmAsymmetric(state->algorithm.id());
if (state->is_asymmetric) {
state->status = webcrypto::GenerateKeyPair(state->algorithm,
state->extractable,
......@@ -420,8 +415,6 @@ void DoGenerateKey(scoped_ptr<GenerateKeyState> passed_state) {
DCHECK_EQ(state->algorithm.id(), state->private_key.algorithm().id());
DCHECK_EQ(true, state->public_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 {
blink::WebCryptoKey* key = &state->public_key;
......
......@@ -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) {
return alg_id == blink::WebCryptoAlgorithmIdRsaOaep ||
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 content
......@@ -71,7 +71,12 @@ bool CreateSecretKeyAlgorithm(const blink::WebCryptoAlgorithm& algorithm,
unsigned int keylen_bytes,
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 IsAlgorithmAsymmetric(blink::WebCryptoAlgorithmId alg_id);
} // 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