blob: 11c6b295b2d1d923ea8958abd8b098449821107b [file] [log] [blame]
/*
* Copyright (C) 2013 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "third_party/blink/renderer/modules/crypto/subtle_crypto.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/public/platform/web_crypto.h"
#include "third_party/blink/public/platform/web_crypto_algorithm.h"
#include "third_party/blink/public/platform/web_crypto_algorithm_params.h"
#include "third_party/blink/renderer/bindings/core/v8/dictionary.h"
#include "third_party/blink/renderer/bindings/modules/v8/array_buffer_or_array_buffer_view_or_json_web_key.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/deprecation.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_piece.h"
#include "third_party/blink/renderer/modules/crypto/crypto_histograms.h"
#include "third_party/blink/renderer/modules/crypto/crypto_key.h"
#include "third_party/blink/renderer/modules/crypto/crypto_result_impl.h"
#include "third_party/blink/renderer/modules/crypto/crypto_utilities.h"
#include "third_party/blink/renderer/modules/crypto/normalize_algorithm.h"
#include "third_party/blink/renderer/platform/json/json_values.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
namespace blink {
// Parses a JsonWebKey dictionary. On success writes the result to
// |jsonUtf8| as a UTF8-encoded JSON octet string and returns true.
// On failure sets an error on |result| and returns false.
//
// Note: The choice of output as an octet string is to facilitate interop
// with the non-JWK formats, but does mean there is a second parsing step.
// This design choice should be revisited after crbug.com/614385).
static bool ParseJsonWebKey(const JsonWebKey& key,
WebVector<uint8_t>& json_utf8,
CryptoResult* result) {
auto json_object = std::make_unique<JSONObject>();
if (key.hasKty())
json_object->SetString("kty", key.kty());
if (key.hasUse())
json_object->SetString("use", key.use());
if (key.hasKeyOps()) {
auto json_array = std::make_unique<JSONArray>();
for (auto&& value : key.keyOps())
json_array->PushString(value);
json_object->SetArray("key_ops", std::move(json_array));
}
if (key.hasAlg())
json_object->SetString("alg", key.alg());
if (key.hasExt())
json_object->SetBoolean("ext", key.ext());
if (key.hasCrv())
json_object->SetString("crv", key.crv());
if (key.hasX())
json_object->SetString("x", key.x());
if (key.hasY())
json_object->SetString("y", key.y());
if (key.hasD())
json_object->SetString("d", key.d());
if (key.hasN())
json_object->SetString("n", key.n());
if (key.hasE())
json_object->SetString("e", key.e());
if (key.hasP())
json_object->SetString("p", key.p());
if (key.hasQ())
json_object->SetString("q", key.q());
if (key.hasDp())
json_object->SetString("dp", key.dp());
if (key.hasDq())
json_object->SetString("dq", key.dq());
if (key.hasQi())
json_object->SetString("qi", key.qi());
// TODO(eroman): Parse "oth" (crbug.com/441396)
if (key.hasK())
json_object->SetString("k", key.k());
String json = json_object->ToJSONString();
json_utf8 = WebVector<uint8_t>(json.Utf8().c_str(), json.Utf8().length());
return true;
}
SubtleCrypto::SubtleCrypto() = default;
ScriptPromise SubtleCrypto::encrypt(ScriptState* script_state,
const AlgorithmIdentifier& raw_algorithm,
CryptoKey* key,
const BufferSource& raw_data,
ExceptionState& exception_state) {
// Method described by:
// https://w3c.github.io/webcrypto/Overview.html#dfn-SubtleCrypto-method-encrypt
// 14.3.1.2: Let data be the result of getting a copy of the bytes held by
// the data parameter passed to the encrypt method.
WebVector<uint8_t> data = CopyBytes(raw_data);
// 14.3.1.3: Let normalizedAlgorithm be the result of normalizing an
// algorithm, with alg set to algorithm and op set to "encrypt".
WebCryptoAlgorithm normalized_algorithm;
if (!NormalizeAlgorithm(script_state->GetIsolate(), raw_algorithm,
kWebCryptoOperationEncrypt, normalized_algorithm,
exception_state))
return ScriptPromise();
auto* result = MakeGarbageCollected<CryptoResultImpl>(script_state);
ScriptPromise promise = result->Promise();
// 14.3.1.8: If the name member of normalizedAlgorithm is not equal to the
// name attribute of the [[algorithm]] internal slot of key then
// throw an InvalidAccessError.
//
// 14.3.1.9: If the [[usages]] internal slot of key does not contain an
// entry that is "encrypt", then throw an InvalidAccessError.
if (!key->CanBeUsedForAlgorithm(normalized_algorithm,
kWebCryptoKeyUsageEncrypt, result))
return promise;
HistogramAlgorithmAndKey(ExecutionContext::From(script_state),
normalized_algorithm, key->Key());
scoped_refptr<base::SingleThreadTaskRunner> task_runner =
ExecutionContext::From(script_state)
->GetTaskRunner(blink::TaskType::kInternalWebCrypto);
Platform::Current()->Crypto()->Encrypt(normalized_algorithm, key->Key(),
std::move(data), result->Result(),
std::move(task_runner));
return promise;
}
ScriptPromise SubtleCrypto::decrypt(ScriptState* script_state,
const AlgorithmIdentifier& raw_algorithm,
CryptoKey* key,
const BufferSource& raw_data,
ExceptionState& exception_state) {
// Method described by:
// https://w3c.github.io/webcrypto/Overview.html#dfn-SubtleCrypto-method-decrypt
// 14.3.2.2: Let data be the result of getting a copy of the bytes held by
// the data parameter passed to the decrypt method.
WebVector<uint8_t> data = CopyBytes(raw_data);
// 14.3.2.3: Let normalizedAlgorithm be the result of normalizing an
// algorithm, with alg set to algorithm and op set to "decrypt".
WebCryptoAlgorithm normalized_algorithm;
if (!NormalizeAlgorithm(script_state->GetIsolate(), raw_algorithm,
kWebCryptoOperationDecrypt, normalized_algorithm,
exception_state))
return ScriptPromise();
auto* result = MakeGarbageCollected<CryptoResultImpl>(script_state);
ScriptPromise promise = result->Promise();
// 14.3.2.8: If the name member of normalizedAlgorithm is not equal to the
// name attribute of the [[algorithm]] internal slot of key then
// throw an InvalidAccessError.
//
// 14.3.2.9: If the [[usages]] internal slot of key does not contain an
// entry that is "decrypt", then throw an InvalidAccessError.
if (!key->CanBeUsedForAlgorithm(normalized_algorithm,
kWebCryptoKeyUsageDecrypt, result))
return promise;
HistogramAlgorithmAndKey(ExecutionContext::From(script_state),
normalized_algorithm, key->Key());
scoped_refptr<base::SingleThreadTaskRunner> task_runner =
ExecutionContext::From(script_state)
->GetTaskRunner(blink::TaskType::kInternalWebCrypto);
Platform::Current()->Crypto()->Decrypt(normalized_algorithm, key->Key(),
std::move(data), result->Result(),
std::move(task_runner));
return promise;
}
ScriptPromise SubtleCrypto::sign(ScriptState* script_state,
const AlgorithmIdentifier& raw_algorithm,
CryptoKey* key,
const BufferSource& raw_data,
ExceptionState& exception_state) {
// Method described by:
// https://w3c.github.io/webcrypto/Overview.html#dfn-SubtleCrypto-method-sign
// 14.3.3.2: Let data be the result of getting a copy of the bytes held by
// the data parameter passed to the sign method.
WebVector<uint8_t> data = CopyBytes(raw_data);
// 14.3.3.3: Let normalizedAlgorithm be the result of normalizing an
// algorithm, with alg set to algorithm and op set to "sign".
WebCryptoAlgorithm normalized_algorithm;
if (!NormalizeAlgorithm(script_state->GetIsolate(), raw_algorithm,
kWebCryptoOperationSign, normalized_algorithm,
exception_state))
return ScriptPromise();
auto* result = MakeGarbageCollected<CryptoResultImpl>(script_state);
ScriptPromise promise = result->Promise();
// 14.3.3.8: If the name member of normalizedAlgorithm is not equal to the
// name attribute of the [[algorithm]] internal slot of key then
// throw an InvalidAccessError.
//
// 14.3.3.9: If the [[usages]] internal slot of key does not contain an
// entry that is "sign", then throw an InvalidAccessError.
if (!key->CanBeUsedForAlgorithm(normalized_algorithm, kWebCryptoKeyUsageSign,
result))
return promise;
HistogramAlgorithmAndKey(ExecutionContext::From(script_state),
normalized_algorithm, key->Key());
scoped_refptr<base::SingleThreadTaskRunner> task_runner =
ExecutionContext::From(script_state)
->GetTaskRunner(blink::TaskType::kInternalWebCrypto);
Platform::Current()->Crypto()->Sign(normalized_algorithm, key->Key(),
std::move(data), result->Result(),
std::move(task_runner));
return promise;
}
ScriptPromise SubtleCrypto::verifySignature(
ScriptState* script_state,
const AlgorithmIdentifier& raw_algorithm,
CryptoKey* key,
const BufferSource& raw_signature,
const BufferSource& raw_data,
ExceptionState& exception_state) {
// Method described by:
// https://w3c.github.io/webcrypto/Overview.html#SubtleCrypto-method-verify
// 14.3.4.2: Let signature be the result of getting a copy of the bytes
// held by the signature parameter passed to the verify method.
WebVector<uint8_t> signature = CopyBytes(raw_signature);
// 14.3.4.3: Let data be the result of getting a copy of the bytes held by
// the data parameter passed to the verify method.
WebVector<uint8_t> data = CopyBytes(raw_data);
// 14.3.4.4: Let normalizedAlgorithm be the result of normalizing an
// algorithm, with alg set to algorithm and op set to "verify".
WebCryptoAlgorithm normalized_algorithm;
if (!NormalizeAlgorithm(script_state->GetIsolate(), raw_algorithm,
kWebCryptoOperationVerify, normalized_algorithm,
exception_state))
return ScriptPromise();
auto* result = MakeGarbageCollected<CryptoResultImpl>(script_state);
ScriptPromise promise = result->Promise();
// 14.3.4.9: If the name member of normalizedAlgorithm is not equal to the
// name attribute of the [[algorithm]] internal slot of key then
// throw an InvalidAccessError.
//
// 14.3.4.10: If the [[usages]] internal slot of key does not contain an
// entry that is "verify", then throw an InvalidAccessError.
if (!key->CanBeUsedForAlgorithm(normalized_algorithm,
kWebCryptoKeyUsageVerify, result))
return promise;
HistogramAlgorithmAndKey(ExecutionContext::From(script_state),
normalized_algorithm, key->Key());
scoped_refptr<base::SingleThreadTaskRunner> task_runner =
ExecutionContext::From(script_state)
->GetTaskRunner(blink::TaskType::kInternalWebCrypto);
Platform::Current()->Crypto()->VerifySignature(
normalized_algorithm, key->Key(), std::move(signature), std::move(data),
result->Result(), std::move(task_runner));
return promise;
}
ScriptPromise SubtleCrypto::digest(ScriptState* script_state,
const AlgorithmIdentifier& raw_algorithm,
const BufferSource& raw_data,
ExceptionState& exception_state) {
// Method described by:
// https://w3c.github.io/webcrypto/Overview.html#SubtleCrypto-method-digest
// 14.3.5.2: Let data be the result of getting a copy of the bytes held
// by the data parameter passed to the digest method.
WebVector<uint8_t> data = CopyBytes(raw_data);
// 14.3.5.3: Let normalizedAlgorithm be the result of normalizing an
// algorithm, with alg set to algorithm and op set to "digest".
WebCryptoAlgorithm normalized_algorithm;
if (!NormalizeAlgorithm(script_state->GetIsolate(), raw_algorithm,
kWebCryptoOperationDigest, normalized_algorithm,
exception_state))
return ScriptPromise();
auto* result = MakeGarbageCollected<CryptoResultImpl>(script_state);
HistogramAlgorithm(ExecutionContext::From(script_state),
normalized_algorithm);
scoped_refptr<base::SingleThreadTaskRunner> task_runner =
ExecutionContext::From(script_state)
->GetTaskRunner(blink::TaskType::kInternalWebCrypto);
Platform::Current()->Crypto()->Digest(normalized_algorithm, std::move(data),
result->Result(),
std::move(task_runner));
return result->Promise();
}
ScriptPromise SubtleCrypto::generateKey(
ScriptState* script_state,
const AlgorithmIdentifier& raw_algorithm,
bool extractable,
const Vector<String>& raw_key_usages,
ExceptionState& exception_state) {
// Method described by:
// https://w3c.github.io/webcrypto/Overview.html#SubtleCrypto-method-generateKey
auto* result = MakeGarbageCollected<CryptoResultImpl>(script_state);
ScriptPromise promise = result->Promise();
WebCryptoKeyUsageMask key_usages;
if (!CryptoKey::ParseUsageMask(raw_key_usages, key_usages, result))
return promise;
// 14.3.6.2: Let normalizedAlgorithm be the result of normalizing an
// algorithm, with alg set to algorithm and op set to
// "generateKey".
WebCryptoAlgorithm normalized_algorithm;
if (!NormalizeAlgorithm(script_state->GetIsolate(), raw_algorithm,
kWebCryptoOperationGenerateKey, normalized_algorithm,
exception_state))
return ScriptPromise();
// NOTE: Steps (8) and (9) disallow empty usages on secret and private
// keys. This normative requirement is enforced by the platform
// implementation in the call below.
HistogramAlgorithm(ExecutionContext::From(script_state),
normalized_algorithm);
scoped_refptr<base::SingleThreadTaskRunner> task_runner =
ExecutionContext::From(script_state)
->GetTaskRunner(blink::TaskType::kInternalWebCrypto);
Platform::Current()->Crypto()->GenerateKey(normalized_algorithm, extractable,
key_usages, result->Result(),
std::move(task_runner));
return promise;
}
ScriptPromise SubtleCrypto::importKey(
ScriptState* script_state,
const String& raw_format,
const ArrayBufferOrArrayBufferViewOrJsonWebKey& raw_key_data,
const AlgorithmIdentifier& raw_algorithm,
bool extractable,
const Vector<String>& raw_key_usages,
ExceptionState& exception_state) {
// Method described by:
// https://w3c.github.io/webcrypto/Overview.html#SubtleCrypto-method-importKey
auto* result = MakeGarbageCollected<CryptoResultImpl>(script_state);
ScriptPromise promise = result->Promise();
WebCryptoKeyFormat format;
if (!CryptoKey::ParseFormat(raw_format, format, result))
return promise;
WebCryptoKeyUsageMask key_usages;
if (!CryptoKey::ParseUsageMask(raw_key_usages, key_usages, result))
return promise;
// In the case of JWK keyData will hold the UTF8-encoded JSON for the
// JsonWebKey, otherwise it holds a copy of the BufferSource.
WebVector<uint8_t> key_data;
switch (format) {
// 14.3.9.2: If format is equal to the string "raw", "pkcs8", or "spki":
//
// (1) If the keyData parameter passed to the importKey method is a
// JsonWebKey dictionary, throw a TypeError.
//
// (2) Let keyData be the result of getting a copy of the bytes held by
// the keyData parameter passed to the importKey method.
case kWebCryptoKeyFormatRaw:
case kWebCryptoKeyFormatPkcs8:
case kWebCryptoKeyFormatSpki:
if (raw_key_data.IsArrayBuffer()) {
key_data = CopyBytes(raw_key_data.GetAsArrayBuffer());
} else if (raw_key_data.IsArrayBufferView()) {
key_data = CopyBytes(raw_key_data.GetAsArrayBufferView().Get());
} else {
result->CompleteWithError(
kWebCryptoErrorTypeType,
"Key data must be a BufferSource for non-JWK formats");
return promise;
}
break;
// 14.3.9.2: If format is equal to the string "jwk":
//
// (1) If the keyData parameter passed to the importKey method is not a
// JsonWebKey dictionary, throw a TypeError.
//
// (2) Let keyData be the keyData parameter passed to the importKey
// method.
case kWebCryptoKeyFormatJwk:
if (raw_key_data.IsJsonWebKey()) {
if (!ParseJsonWebKey(*raw_key_data.GetAsJsonWebKey(), key_data, result))
return promise;
} else {
result->CompleteWithError(kWebCryptoErrorTypeType,
"Key data must be an object for JWK import");
return promise;
}
break;
}
// 14.3.9.3: Let normalizedAlgorithm be the result of normalizing an
// algorithm, with alg set to algorithm and op set to
// "importKey".
WebCryptoAlgorithm normalized_algorithm;
if (!NormalizeAlgorithm(script_state->GetIsolate(), raw_algorithm,
kWebCryptoOperationImportKey, normalized_algorithm,
exception_state))
return ScriptPromise();
HistogramAlgorithm(ExecutionContext::From(script_state),
normalized_algorithm);
scoped_refptr<base::SingleThreadTaskRunner> task_runner =
ExecutionContext::From(script_state)
->GetTaskRunner(blink::TaskType::kInternalWebCrypto);
Platform::Current()->Crypto()->ImportKey(
format, std::move(key_data), normalized_algorithm, extractable,
key_usages, result->Result(), std::move(task_runner));
return promise;
}
ScriptPromise SubtleCrypto::exportKey(ScriptState* script_state,
const String& raw_format,
CryptoKey* key) {
// Method described by:
// https://w3c.github.io/webcrypto/Overview.html#dfn-SubtleCrypto-method-exportKey
auto* result = MakeGarbageCollected<CryptoResultImpl>(script_state);
ScriptPromise promise = result->Promise();
WebCryptoKeyFormat format;
if (!CryptoKey::ParseFormat(raw_format, format, result))
return promise;
// 14.3.10.6: If the [[extractable]] internal slot of key is false, then
// throw an InvalidAccessError.
if (!key->extractable()) {
result->CompleteWithError(kWebCryptoErrorTypeInvalidAccess,
"key is not extractable");
return promise;
}
HistogramKey(ExecutionContext::From(script_state), key->Key());
scoped_refptr<base::SingleThreadTaskRunner> task_runner =
ExecutionContext::From(script_state)
->GetTaskRunner(blink::TaskType::kInternalWebCrypto);
Platform::Current()->Crypto()->ExportKey(format, key->Key(), result->Result(),
std::move(task_runner));
return promise;
}
ScriptPromise SubtleCrypto::wrapKey(
ScriptState* script_state,
const String& raw_format,
CryptoKey* key,
CryptoKey* wrapping_key,
const AlgorithmIdentifier& raw_wrap_algorithm,
ExceptionState& exception_state) {
// Method described by:
// https://w3c.github.io/webcrypto/Overview.html#SubtleCrypto-method-wrapKey
auto* result = MakeGarbageCollected<CryptoResultImpl>(script_state);
ScriptPromise promise = result->Promise();
WebCryptoKeyFormat format;
if (!CryptoKey::ParseFormat(raw_format, format, result))
return promise;
// 14.3.11.2: Let normalizedAlgorithm be the result of normalizing an
// algorithm, with alg set to algorithm and op set to "wrapKey".
//
// 14.3.11.3: If an error occurred, let normalizedAlgorithm be the result
// of normalizing an algorithm, with alg set to algorithm and op
// set to "encrypt".
WebCryptoAlgorithm normalized_algorithm;
if (!NormalizeAlgorithm(script_state->GetIsolate(), raw_wrap_algorithm,
kWebCryptoOperationWrapKey, normalized_algorithm,
exception_state))
return ScriptPromise();
// 14.3.11.9: If the name member of normalizedAlgorithm is not equal to the
// name attribute of the [[algorithm]] internal slot of
// wrappingKey then throw an InvalidAccessError.
//
// 14.3.11.10: If the [[usages]] internal slot of wrappingKey does not
// contain an entry that is "wrapKey", then throw an
// InvalidAccessError.
if (!wrapping_key->CanBeUsedForAlgorithm(normalized_algorithm,
kWebCryptoKeyUsageWrapKey, result))
return promise;
// TODO(crbug.com/628416): The error from step 11
// (NotSupportedError) is thrown after step 12 which does not match
// the spec order.
// 14.3.11.12: If the [[extractable]] internal slot of key is false, then
// throw an InvalidAccessError.
if (!key->extractable()) {
result->CompleteWithError(kWebCryptoErrorTypeInvalidAccess,
"key is not extractable");
return promise;
}
HistogramAlgorithmAndKey(ExecutionContext::From(script_state),
normalized_algorithm, wrapping_key->Key());
HistogramKey(ExecutionContext::From(script_state), key->Key());
scoped_refptr<base::SingleThreadTaskRunner> task_runner =
ExecutionContext::From(script_state)
->GetTaskRunner(blink::TaskType::kInternalWebCrypto);
Platform::Current()->Crypto()->WrapKey(
format, key->Key(), wrapping_key->Key(), normalized_algorithm,
result->Result(), std::move(task_runner));
return promise;
}
ScriptPromise SubtleCrypto::unwrapKey(
ScriptState* script_state,
const String& raw_format,
const BufferSource& raw_wrapped_key,
CryptoKey* unwrapping_key,
const AlgorithmIdentifier& raw_unwrap_algorithm,
const AlgorithmIdentifier& raw_unwrapped_key_algorithm,
bool extractable,
const Vector<String>& raw_key_usages,
ExceptionState& exception_state) {
// Method described by:
// https://w3c.github.io/webcrypto/Overview.html#SubtleCrypto-method-unwrapKey
auto* result = MakeGarbageCollected<CryptoResultImpl>(script_state);
ScriptPromise promise = result->Promise();
WebCryptoKeyFormat format;
if (!CryptoKey::ParseFormat(raw_format, format, result))
return promise;
WebCryptoKeyUsageMask key_usages;
if (!CryptoKey::ParseUsageMask(raw_key_usages, key_usages, result))
return promise;
// 14.3.12.2: Let wrappedKey be the result of getting a copy of the bytes
// held by the wrappedKey parameter passed to the unwrapKey
// method.
WebVector<uint8_t> wrapped_key = CopyBytes(raw_wrapped_key);
// 14.3.12.3: Let normalizedAlgorithm be the result of normalizing an
// algorithm, with alg set to algorithm and op set to
// "unwrapKey".
//
// 14.3.12.4: If an error occurred, let normalizedAlgorithm be the result
// of normalizing an algorithm, with alg set to algorithm and op
// set to "decrypt".
WebCryptoAlgorithm normalized_algorithm;
if (!NormalizeAlgorithm(script_state->GetIsolate(), raw_unwrap_algorithm,
kWebCryptoOperationUnwrapKey, normalized_algorithm,
exception_state))
return ScriptPromise();
// 14.3.12.6: Let normalizedKeyAlgorithm be the result of normalizing an
// algorithm, with alg set to unwrappedKeyAlgorithm and op set
// to "importKey".
WebCryptoAlgorithm normalized_key_algorithm;
if (!NormalizeAlgorithm(script_state->GetIsolate(),
raw_unwrapped_key_algorithm,
kWebCryptoOperationImportKey,
normalized_key_algorithm, exception_state))
return ScriptPromise();
// 14.3.12.11: If the name member of normalizedAlgorithm is not equal to
// the name attribute of the [[algorithm]] internal slot of
// unwrappingKey then throw an InvalidAccessError.
//
// 14.3.12.12: If the [[usages]] internal slot of unwrappingKey does not
// contain an entry that is "unwrapKey", then throw an
// InvalidAccessError.
if (!unwrapping_key->CanBeUsedForAlgorithm(
normalized_algorithm, kWebCryptoKeyUsageUnwrapKey, result))
return promise;
// NOTE: Step (16) disallows empty usages on secret and private keys. This
// normative requirement is enforced by the platform implementation in the
// call below.
HistogramAlgorithmAndKey(ExecutionContext::From(script_state),
normalized_algorithm, unwrapping_key->Key());
HistogramAlgorithm(ExecutionContext::From(script_state),
normalized_key_algorithm);
scoped_refptr<base::SingleThreadTaskRunner> task_runner =
ExecutionContext::From(script_state)
->GetTaskRunner(blink::TaskType::kInternalWebCrypto);
Platform::Current()->Crypto()->UnwrapKey(
format, std::move(wrapped_key), unwrapping_key->Key(),
normalized_algorithm, normalized_key_algorithm, extractable, key_usages,
result->Result(), std::move(task_runner));
return promise;
}
ScriptPromise SubtleCrypto::deriveBits(ScriptState* script_state,
const AlgorithmIdentifier& raw_algorithm,
CryptoKey* base_key,
unsigned length_bits,
ExceptionState& exception_state) {
// Method described by:
// https://w3c.github.io/webcrypto/Overview.html#dfn-SubtleCrypto-method-deriveBits
// 14.3.8.2: Let normalizedAlgorithm be the result of normalizing an
// algorithm, with alg set to algorithm and op set to
// "deriveBits".
WebCryptoAlgorithm normalized_algorithm;
if (!NormalizeAlgorithm(script_state->GetIsolate(), raw_algorithm,
kWebCryptoOperationDeriveBits, normalized_algorithm,
exception_state))
return ScriptPromise();
// 14.3.8.7: If the name member of normalizedAlgorithm is not equal to the
// name attribute of the [[algorithm]] internal slot of baseKey
// then throw an InvalidAccessError.
//
// 14.3.8.8: If the [[usages]] internal slot of baseKey does not contain an
// entry that is "deriveBits", then throw an InvalidAccessError.
auto* result = MakeGarbageCollected<CryptoResultImpl>(script_state);
ScriptPromise promise = result->Promise();
if (!base_key->CanBeUsedForAlgorithm(normalized_algorithm,
kWebCryptoKeyUsageDeriveBits, result))
return promise;
HistogramAlgorithmAndKey(ExecutionContext::From(script_state),
normalized_algorithm, base_key->Key());
scoped_refptr<base::SingleThreadTaskRunner> task_runner =
ExecutionContext::From(script_state)
->GetTaskRunner(blink::TaskType::kInternalWebCrypto);
Platform::Current()->Crypto()->DeriveBits(
normalized_algorithm, base_key->Key(), length_bits, result->Result(),
std::move(task_runner));
return promise;
}
ScriptPromise SubtleCrypto::deriveKey(
ScriptState* script_state,
const AlgorithmIdentifier& raw_algorithm,
CryptoKey* base_key,
const AlgorithmIdentifier& raw_derived_key_type,
bool extractable,
const Vector<String>& raw_key_usages,
ExceptionState& exception_state) {
// Method described by:
// https://w3c.github.io/webcrypto/Overview.html#SubtleCrypto-method-deriveKey
auto* result = MakeGarbageCollected<CryptoResultImpl>(script_state);
ScriptPromise promise = result->Promise();
WebCryptoKeyUsageMask key_usages;
if (!CryptoKey::ParseUsageMask(raw_key_usages, key_usages, result))
return promise;
// 14.3.7.2: Let normalizedAlgorithm be the result of normalizing an
// algorithm, with alg set to algorithm and op set to
// "deriveBits".
WebCryptoAlgorithm normalized_algorithm;
if (!NormalizeAlgorithm(script_state->GetIsolate(), raw_algorithm,
kWebCryptoOperationDeriveBits, normalized_algorithm,
exception_state))
return ScriptPromise();
// 14.3.7.4: Let normalizedDerivedKeyAlgorithm be the result of normalizing
// an algorithm, with alg set to derivedKeyType and op set to
// "importKey".
WebCryptoAlgorithm normalized_derived_key_algorithm;
if (!NormalizeAlgorithm(script_state->GetIsolate(), raw_derived_key_type,
kWebCryptoOperationImportKey,
normalized_derived_key_algorithm, exception_state))
return ScriptPromise();
// TODO(eroman): The description in the spec needs to be updated as
// it doesn't describe algorithm normalization for the Get Key
// Length parameters (https://github.com/w3c/webcrypto/issues/127)
// For now reference step 10 which is the closest.
//
// 14.3.7.10: If the name member of normalizedDerivedKeyAlgorithm does not
// identify a registered algorithm that supports the get key length
// operation, then throw a NotSupportedError.
WebCryptoAlgorithm key_length_algorithm;
if (!NormalizeAlgorithm(script_state->GetIsolate(), raw_derived_key_type,
kWebCryptoOperationGetKeyLength, key_length_algorithm,
exception_state))
return ScriptPromise();
// 14.3.7.11: If the name member of normalizedAlgorithm is not equal to the
// name attribute of the [[algorithm]] internal slot of baseKey
// then throw an InvalidAccessError.
//
// 14.3.7.12: If the [[usages]] internal slot of baseKey does not contain
// an entry that is "deriveKey", then throw an InvalidAccessError.
if (!base_key->CanBeUsedForAlgorithm(normalized_algorithm,
kWebCryptoKeyUsageDeriveKey, result))
return promise;
// NOTE: Step (16) disallows empty usages on secret and private keys. This
// normative requirement is enforced by the platform implementation in the
// call below.
HistogramAlgorithmAndKey(ExecutionContext::From(script_state),
normalized_algorithm, base_key->Key());
HistogramAlgorithm(ExecutionContext::From(script_state),
normalized_derived_key_algorithm);
scoped_refptr<base::SingleThreadTaskRunner> task_runner =
ExecutionContext::From(script_state)
->GetTaskRunner(blink::TaskType::kInternalWebCrypto);
Platform::Current()->Crypto()->DeriveKey(
normalized_algorithm, base_key->Key(), normalized_derived_key_algorithm,
key_length_algorithm, extractable, key_usages, result->Result(),
std::move(task_runner));
return promise;
}
} // namespace blink