mirror of
https://github.com/servo/servo
synced 2026-05-11 09:26:59 +02:00
Testing: Ed25519 test passed. Fixes: Part of https://github.com/servo/servo/issues/43072 --------- Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com>
5110 lines
217 KiB
Rust
5110 lines
217 KiB
Rust
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
|
|
mod aes_cbc_operation;
|
|
mod aes_common;
|
|
mod aes_ctr_operation;
|
|
mod aes_gcm_operation;
|
|
mod aes_kw_operation;
|
|
mod aes_ocb_operation;
|
|
mod argon2_operation;
|
|
mod chacha20_poly1305_operation;
|
|
mod cshake_operation;
|
|
mod ec_common;
|
|
mod ecdh_operation;
|
|
mod ecdsa_operation;
|
|
mod ed25519_operation;
|
|
mod hkdf_operation;
|
|
mod hmac_operation;
|
|
mod ml_dsa_operation;
|
|
mod ml_kem_operation;
|
|
mod pbkdf2_operation;
|
|
mod rsa_common;
|
|
mod rsa_oaep_operation;
|
|
mod rsa_pss_operation;
|
|
mod rsassa_pkcs1_v1_5_operation;
|
|
mod sha3_operation;
|
|
mod sha_operation;
|
|
mod x25519_operation;
|
|
|
|
use std::fmt::Display;
|
|
use std::ptr;
|
|
use std::rc::Rc;
|
|
use std::str::FromStr;
|
|
|
|
use base64ct::{Base64UrlUnpadded, Encoding};
|
|
use dom_struct::dom_struct;
|
|
use js::conversions::ConversionResult;
|
|
use js::jsapi::{Heap, JSObject};
|
|
use js::jsval::{ObjectValue, UndefinedValue};
|
|
use js::realm::CurrentRealm;
|
|
use js::rust::wrappers2::JS_ParseJSON;
|
|
use js::rust::{HandleValue, MutableHandleValue};
|
|
use js::typedarray::ArrayBufferU8;
|
|
use strum::{EnumString, IntoStaticStr, VariantArray};
|
|
|
|
use crate::dom::bindings::buffer_source::create_buffer_source;
|
|
use crate::dom::bindings::codegen::Bindings::CryptoKeyBinding::{
|
|
CryptoKeyMethods, CryptoKeyPair, KeyType, KeyUsage,
|
|
};
|
|
use crate::dom::bindings::codegen::Bindings::SubtleCryptoBinding::{
|
|
AeadParams, AesCbcParams, AesCtrParams, AesDerivedKeyParams, AesGcmParams, AesKeyAlgorithm,
|
|
AesKeyGenParams, Algorithm, AlgorithmIdentifier, Argon2Params, CShakeParams, ContextParams,
|
|
EcKeyAlgorithm, EcKeyGenParams, EcKeyImportParams, EcdhKeyDeriveParams, EcdsaParams,
|
|
EncapsulatedBits, EncapsulatedKey, HkdfParams, HmacImportParams, HmacKeyAlgorithm,
|
|
HmacKeyGenParams, JsonWebKey, KeyAlgorithm, KeyFormat, Pbkdf2Params, RsaHashedImportParams,
|
|
RsaHashedKeyAlgorithm, RsaHashedKeyGenParams, RsaKeyAlgorithm, RsaOaepParams, RsaPssParams,
|
|
SubtleCryptoMethods,
|
|
};
|
|
use crate::dom::bindings::codegen::UnionTypes::{
|
|
ArrayBufferViewOrArrayBuffer, ArrayBufferViewOrArrayBufferOrJsonWebKey, ObjectOrString,
|
|
};
|
|
use crate::dom::bindings::conversions::{SafeFromJSValConvertible, SafeToJSValConvertible};
|
|
use crate::dom::bindings::error::{Error, Fallible};
|
|
use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
|
|
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object_with_cx};
|
|
use crate::dom::bindings::root::DomRoot;
|
|
use crate::dom::bindings::str::{DOMString, serialize_jsval_to_json_utf8};
|
|
use crate::dom::bindings::trace::RootedTraceableBox;
|
|
use crate::dom::bindings::utils::set_dictionary_property;
|
|
use crate::dom::cryptokey::{CryptoKey, CryptoKeyOrCryptoKeyPair};
|
|
use crate::dom::globalscope::GlobalScope;
|
|
use crate::dom::promise::Promise;
|
|
use crate::script_runtime::{CanGc, JSContext};
|
|
|
|
// Named elliptic curves
|
|
const NAMED_CURVE_P256: &str = "P-256";
|
|
const NAMED_CURVE_P384: &str = "P-384";
|
|
const NAMED_CURVE_P521: &str = "P-521";
|
|
|
|
static SUPPORTED_CURVES: &[&str] = &[NAMED_CURVE_P256, NAMED_CURVE_P384, NAMED_CURVE_P521];
|
|
|
|
#[derive(EnumString, VariantArray, IntoStaticStr, PartialEq, Clone, Copy, MallocSizeOf)]
|
|
enum CryptoAlgorithm {
|
|
#[strum(serialize = "RSASSA-PKCS1-v1_5")]
|
|
RsassaPkcs1V1_5,
|
|
#[strum(serialize = "RSA-PSS")]
|
|
RsaPss,
|
|
#[strum(serialize = "RSA-OAEP")]
|
|
RsaOaep,
|
|
#[strum(serialize = "ECDSA")]
|
|
Ecdsa,
|
|
#[strum(serialize = "ECDH")]
|
|
Ecdh,
|
|
#[strum(serialize = "Ed25519")]
|
|
Ed25519,
|
|
#[strum(serialize = "X25519")]
|
|
X25519,
|
|
#[strum(serialize = "AES-CTR")]
|
|
AesCtr,
|
|
#[strum(serialize = "AES-CBC")]
|
|
AesCbc,
|
|
#[strum(serialize = "AES-GCM")]
|
|
AesGcm,
|
|
#[strum(serialize = "AES-KW")]
|
|
AesKw,
|
|
#[strum(serialize = "HMAC")]
|
|
Hmac,
|
|
#[strum(serialize = "SHA-1")]
|
|
Sha1,
|
|
#[strum(serialize = "SHA-256")]
|
|
Sha256,
|
|
#[strum(serialize = "SHA-384")]
|
|
Sha384,
|
|
#[strum(serialize = "SHA-512")]
|
|
Sha512,
|
|
#[strum(serialize = "HKDF")]
|
|
Hkdf,
|
|
#[strum(serialize = "PBKDF2")]
|
|
Pbkdf2,
|
|
#[strum(serialize = "ML-KEM-512")]
|
|
MlKem512,
|
|
#[strum(serialize = "ML-KEM-768")]
|
|
MlKem768,
|
|
#[strum(serialize = "ML-KEM-1024")]
|
|
MlKem1024,
|
|
#[strum(serialize = "ML-DSA-44")]
|
|
MlDsa44,
|
|
#[strum(serialize = "ML-DSA-65")]
|
|
MlDsa65,
|
|
#[strum(serialize = "ML-DSA-87")]
|
|
MlDsa87,
|
|
#[strum(serialize = "AES-OCB")]
|
|
AesOcb,
|
|
#[strum(serialize = "ChaCha20-Poly1305")]
|
|
ChaCha20Poly1305,
|
|
#[strum(serialize = "SHA3-256")]
|
|
Sha3_256,
|
|
#[strum(serialize = "SHA3-384")]
|
|
Sha3_384,
|
|
#[strum(serialize = "SHA3-512")]
|
|
Sha3_512,
|
|
#[strum(serialize = "cSHAKE128")]
|
|
CShake128,
|
|
#[strum(serialize = "cSHAKE256")]
|
|
CShake256,
|
|
#[strum(serialize = "Argon2d")]
|
|
Argon2D,
|
|
#[strum(serialize = "Argon2i")]
|
|
Argon2I,
|
|
#[strum(serialize = "Argon2id")]
|
|
Argon2ID,
|
|
}
|
|
|
|
impl CryptoAlgorithm {
|
|
/// <https://w3c.github.io/webcrypto/#recognized-algorithm-name>
|
|
fn as_str(&self) -> &'static str {
|
|
(*self).into()
|
|
}
|
|
|
|
fn from_str_ignore_case(algorithm_name: &str) -> Fallible<CryptoAlgorithm> {
|
|
Self::VARIANTS
|
|
.iter()
|
|
.find(|algorithm| algorithm.as_str().eq_ignore_ascii_case(algorithm_name))
|
|
.cloned()
|
|
.ok_or(Error::NotSupported(Some(format!(
|
|
"Unsupported algorithm: {algorithm_name}"
|
|
))))
|
|
}
|
|
|
|
fn from_domstring(name: &DOMString) -> Fallible<Self> {
|
|
CryptoAlgorithm::try_from(&*name.str()).map_err(|_| Error::NotSupported(None))
|
|
}
|
|
}
|
|
|
|
#[dom_struct]
|
|
pub(crate) struct SubtleCrypto {
|
|
reflector_: Reflector,
|
|
}
|
|
|
|
impl SubtleCrypto {
|
|
fn new_inherited() -> SubtleCrypto {
|
|
SubtleCrypto {
|
|
reflector_: Reflector::new(),
|
|
}
|
|
}
|
|
|
|
pub(crate) fn new(
|
|
cx: &mut js::context::JSContext,
|
|
global: &GlobalScope,
|
|
) -> DomRoot<SubtleCrypto> {
|
|
reflect_dom_object_with_cx(Box::new(SubtleCrypto::new_inherited()), global, cx)
|
|
}
|
|
|
|
/// Queue a global task on the crypto task source, given realm's global object, to resolve
|
|
/// promise with the result of creating an ArrayBuffer in realm, containing data. If it fails
|
|
/// to create buffer source, reject promise with a JSFailedError.
|
|
fn resolve_promise_with_data(&self, promise: Rc<Promise>, data: Vec<u8>) {
|
|
let trusted_promise = TrustedPromise::new(promise);
|
|
self.global()
|
|
.task_manager()
|
|
.crypto_task_source()
|
|
.queue(task!(resolve_data: move |cx| {
|
|
let promise = trusted_promise.root();
|
|
|
|
rooted!(&in(cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
|
|
match create_buffer_source::<ArrayBufferU8>(
|
|
cx.into(),
|
|
&data,
|
|
array_buffer_ptr.handle_mut(),
|
|
CanGc::from_cx(cx),
|
|
) {
|
|
Ok(_) => promise.resolve_native(&*array_buffer_ptr, CanGc::from_cx(cx)),
|
|
Err(_) => promise.reject_error(Error::JSFailed, CanGc::from_cx(cx)),
|
|
}
|
|
}));
|
|
}
|
|
|
|
/// Queue a global task on the crypto task source, given realm's global object, to resolve
|
|
/// promise with the result of converting a JsonWebKey dictionary to an ECMAScript Object in
|
|
/// realm, as defined by [WebIDL].
|
|
fn resolve_promise_with_jwk(
|
|
&self,
|
|
cx: &mut js::context::JSContext,
|
|
promise: Rc<Promise>,
|
|
jwk: Box<JsonWebKey>,
|
|
) {
|
|
// NOTE: Serialize the JsonWebKey dictionary by stringifying it, in order to pass it to
|
|
// other threads.
|
|
let stringified_jwk = match jwk.stringify(cx) {
|
|
Ok(stringified_jwk) => stringified_jwk.to_string(),
|
|
Err(error) => {
|
|
self.reject_promise_with_error(promise, error);
|
|
return;
|
|
},
|
|
};
|
|
|
|
let trusted_subtle = Trusted::new(self);
|
|
let trusted_promise = TrustedPromise::new(promise);
|
|
self.global()
|
|
.task_manager()
|
|
.crypto_task_source()
|
|
.queue(task!(resolve_jwk: move |cx| {
|
|
let subtle = trusted_subtle.root();
|
|
let promise = trusted_promise.root();
|
|
|
|
match JsonWebKey::parse(cx, stringified_jwk.as_bytes()) {
|
|
Ok(jwk) => {
|
|
rooted!(&in(cx) let mut rval = UndefinedValue());
|
|
jwk.safe_to_jsval(cx.into(), rval.handle_mut(), CanGc::from_cx(cx));
|
|
rooted!(&in(cx) let mut object = rval.to_object());
|
|
promise.resolve_native(&*object, CanGc::from_cx(cx));
|
|
},
|
|
Err(error) => {
|
|
subtle.reject_promise_with_error(promise, error);
|
|
return;
|
|
},
|
|
}
|
|
}));
|
|
}
|
|
|
|
/// Queue a global task on the crypto task source, given realm's global object, to resolve
|
|
/// promise with a CryptoKey.
|
|
fn resolve_promise_with_key(&self, promise: Rc<Promise>, key: DomRoot<CryptoKey>) {
|
|
let trusted_key = Trusted::new(&*key);
|
|
let trusted_promise = TrustedPromise::new(promise);
|
|
self.global()
|
|
.task_manager()
|
|
.crypto_task_source()
|
|
.queue(task!(resolve_key: move |cx| {
|
|
let key = trusted_key.root();
|
|
let promise = trusted_promise.root();
|
|
promise.resolve_native(&key, CanGc::from_cx(cx));
|
|
}));
|
|
}
|
|
|
|
/// Queue a global task on the crypto task source, given realm's global object, to resolve
|
|
/// promise with a CryptoKeyPair.
|
|
fn resolve_promise_with_key_pair(&self, promise: Rc<Promise>, key_pair: CryptoKeyPair) {
|
|
let trusted_private_key = key_pair.privateKey.map(|key| Trusted::new(&*key));
|
|
let trusted_public_key = key_pair.publicKey.map(|key| Trusted::new(&*key));
|
|
let trusted_promise = TrustedPromise::new(promise);
|
|
self.global()
|
|
.task_manager()
|
|
.crypto_task_source()
|
|
.queue(task!(resolve_key: move |cx| {
|
|
let key_pair = CryptoKeyPair {
|
|
privateKey: trusted_private_key.map(|trusted_key| trusted_key.root()),
|
|
publicKey: trusted_public_key.map(|trusted_key| trusted_key.root()),
|
|
};
|
|
let promise = trusted_promise.root();
|
|
promise.resolve_native(&key_pair, CanGc::from_cx(cx));
|
|
}));
|
|
}
|
|
|
|
/// Queue a global task on the crypto task source, given realm's global object, to resolve
|
|
/// promise with a bool value.
|
|
fn resolve_promise_with_bool(&self, promise: Rc<Promise>, result: bool) {
|
|
let trusted_promise = TrustedPromise::new(promise);
|
|
self.global()
|
|
.task_manager()
|
|
.crypto_task_source()
|
|
.queue(task!(resolve_bool: move |cx| {
|
|
let promise = trusted_promise.root();
|
|
promise.resolve_native(&result, CanGc::from_cx(cx));
|
|
}));
|
|
}
|
|
|
|
/// Queue a global task on the crypto task source, given realm's global object, to reject
|
|
/// promise with an error.
|
|
fn reject_promise_with_error(&self, promise: Rc<Promise>, error: Error) {
|
|
let trusted_promise = TrustedPromise::new(promise);
|
|
self.global()
|
|
.task_manager()
|
|
.crypto_task_source()
|
|
.queue(task!(reject_error: move |cx| {
|
|
let promise = trusted_promise.root();
|
|
promise.reject_error(error, CanGc::from_cx(cx));
|
|
}));
|
|
}
|
|
|
|
/// Queue a global task on the crypto task source, given realm's global object, to resolve
|
|
/// promise with the result of converting EncapsulatedKey to an ECMAScript Object in realm, as
|
|
/// defined by [WebIDL].
|
|
fn resolve_promise_with_encapsulated_key(
|
|
&self,
|
|
promise: Rc<Promise>,
|
|
encapsulated_key: SubtleEncapsulatedKey,
|
|
) {
|
|
let trusted_promise = TrustedPromise::new(promise);
|
|
self.global().task_manager().crypto_task_source().queue(
|
|
task!(resolve_encapsulated_key: move |cx| {
|
|
let promise = trusted_promise.root();
|
|
promise.resolve_native(&encapsulated_key, CanGc::from_cx(cx));
|
|
}),
|
|
);
|
|
}
|
|
|
|
/// Queue a global task on the crypto task source, given realm's global object, to resolve
|
|
/// promise with the result of converting EncapsulateBits to an ECMAScript Object in realm, as
|
|
/// defined by [WebIDL].
|
|
fn resolve_promise_with_encapsulated_bits(
|
|
&self,
|
|
promise: Rc<Promise>,
|
|
encapsulated_bits: SubtleEncapsulatedBits,
|
|
) {
|
|
let trusted_promise = TrustedPromise::new(promise);
|
|
self.global().task_manager().crypto_task_source().queue(
|
|
task!(resolve_encapsulated_bits: move |cx| {
|
|
let promise = trusted_promise.root();
|
|
promise.resolve_native(&encapsulated_bits, CanGc::from_cx(cx));
|
|
}),
|
|
);
|
|
}
|
|
}
|
|
|
|
impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
|
|
/// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-encrypt>
|
|
fn Encrypt(
|
|
&self,
|
|
cx: &mut CurrentRealm,
|
|
algorithm: AlgorithmIdentifier,
|
|
key: &CryptoKey,
|
|
data: ArrayBufferViewOrArrayBuffer,
|
|
) -> Rc<Promise> {
|
|
// Step 1. Let algorithm and key be the algorithm and key parameters passed to the
|
|
// encrypt() method, respectively.
|
|
// NOTE: We did that in method parameter.
|
|
|
|
// Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
|
|
// to algorithm and op set to "encrypt".
|
|
// Step 3. If an error occurred, return a Promise rejected with normalizedAlgorithm.
|
|
let normalized_algorithm = match normalize_algorithm::<EncryptOperation>(cx, &algorithm) {
|
|
Ok(normalized_algorithm) => normalized_algorithm,
|
|
Err(error) => {
|
|
let promise = Promise::new_in_realm(cx);
|
|
promise.reject_error(error, CanGc::from_cx(cx));
|
|
return promise;
|
|
},
|
|
};
|
|
|
|
// Step 4. Let data be the result of getting a copy of the bytes held by the data parameter
|
|
// passed to the encrypt() method.
|
|
let data = match data {
|
|
ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
|
|
ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
|
|
};
|
|
|
|
// Step 5. Let realm be the relevant realm of this.
|
|
// Step 6. Let promise be a new Promise.
|
|
let promise = Promise::new_in_realm(cx);
|
|
|
|
// Step 7. Return promise and perform the remaining steps in parallel.
|
|
let this = Trusted::new(self);
|
|
let trusted_promise = TrustedPromise::new(promise.clone());
|
|
let trusted_key = Trusted::new(key);
|
|
self.global()
|
|
.task_manager()
|
|
.dom_manipulation_task_source()
|
|
.queue(task!(encrypt: move || {
|
|
let subtle = this.root();
|
|
let promise = trusted_promise.root();
|
|
let key = trusted_key.root();
|
|
|
|
// Step 8. If the following steps or referenced procedures say to throw an error,
|
|
// queue a global task on the crypto task source, given realm's global object, to
|
|
// reject promise with the returned error; and then terminate the algorithm.
|
|
|
|
// Step 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.
|
|
if normalized_algorithm.name() != key.algorithm().name() {
|
|
subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
|
|
return;
|
|
}
|
|
|
|
// Step 10. If the [[usages]] internal slot of key does not contain an entry that
|
|
// is "encrypt", then throw an InvalidAccessError.
|
|
if !key.usages().contains(&KeyUsage::Encrypt) {
|
|
subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
|
|
return;
|
|
}
|
|
|
|
// Step 11. Let ciphertext be the result of performing the encrypt operation
|
|
// specified by normalizedAlgorithm using algorithm and key and with data as
|
|
// plaintext.
|
|
let ciphertext = match normalized_algorithm.encrypt(&key, &data) {
|
|
Ok(ciphertext) => ciphertext,
|
|
Err(error) => {
|
|
subtle.reject_promise_with_error(promise, error);
|
|
return;
|
|
},
|
|
};
|
|
|
|
// Step 12. Queue a global task on the crypto task source, given realm's global
|
|
// object, to perform the remaining steps.
|
|
// Step 13. Let result be the result of creating an ArrayBuffer in realm,
|
|
// containing ciphertext.
|
|
// Step 14. Resolve promise with result.
|
|
subtle.resolve_promise_with_data(promise, ciphertext);
|
|
}));
|
|
promise
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-decrypt>
|
|
fn Decrypt(
|
|
&self,
|
|
cx: &mut CurrentRealm,
|
|
algorithm: AlgorithmIdentifier,
|
|
key: &CryptoKey,
|
|
data: ArrayBufferViewOrArrayBuffer,
|
|
) -> Rc<Promise> {
|
|
// Step 1. Let algorithm and key be the algorithm and key parameters passed to the
|
|
// decrypt() method, respectively.
|
|
// NOTE: We did that in method parameter.
|
|
|
|
// Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
|
|
// to algorithm and op set to "decrypt".
|
|
// Step 3. If an error occurred, return a Promise rejected with normalizedAlgorithm.
|
|
let normalized_algorithm = match normalize_algorithm::<DecryptOperation>(cx, &algorithm) {
|
|
Ok(normalized_algorithm) => normalized_algorithm,
|
|
Err(error) => {
|
|
let promise = Promise::new_in_realm(cx);
|
|
promise.reject_error(error, CanGc::from_cx(cx));
|
|
return promise;
|
|
},
|
|
};
|
|
|
|
// Step 4. Let data be the result of getting a copy of the bytes held by the data parameter
|
|
// passed to the decrypt() method.
|
|
let data = match data {
|
|
ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
|
|
ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
|
|
};
|
|
|
|
// Step 5. Let realm be the relevant realm of this.
|
|
// Step 6. Let promise be a new Promise.
|
|
let promise = Promise::new_in_realm(cx);
|
|
|
|
// Step 7. Return promise and perform the remaining steps in parallel.
|
|
let this = Trusted::new(self);
|
|
let trusted_promise = TrustedPromise::new(promise.clone());
|
|
let trusted_key = Trusted::new(key);
|
|
self.global()
|
|
.task_manager()
|
|
.dom_manipulation_task_source()
|
|
.queue(task!(decrypt: move || {
|
|
let subtle = this.root();
|
|
let promise = trusted_promise.root();
|
|
let key = trusted_key.root();
|
|
|
|
// Step 8. If the following steps or referenced procedures say to throw an error,
|
|
// queue a global task on the crypto task source, given realm's global object, to
|
|
// reject promise with the returned error; and then terminate the algorithm.
|
|
|
|
// Step 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.
|
|
if normalized_algorithm.name() != key.algorithm().name() {
|
|
subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
|
|
return;
|
|
}
|
|
|
|
// Step 10. If the [[usages]] internal slot of key does not contain an entry that
|
|
// is "decrypt", then throw an InvalidAccessError.
|
|
if !key.usages().contains(&KeyUsage::Decrypt) {
|
|
subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
|
|
return;
|
|
}
|
|
|
|
// Step 11. Let plaintext be the result of performing the decrypt operation
|
|
// specified by normalizedAlgorithm using key and algorithm and with data as
|
|
// ciphertext.
|
|
let plaintext = match normalized_algorithm.decrypt(&key, &data) {
|
|
Ok(plaintext) => plaintext,
|
|
Err(error) => {
|
|
subtle.reject_promise_with_error(promise, error);
|
|
return;
|
|
},
|
|
};
|
|
|
|
// Step 12. Queue a global task on the crypto task source, given realm's global
|
|
// object, to perform the remaining steps.
|
|
// Step 13. Let result be the result of creating an ArrayBuffer in realm,
|
|
// containing plaintext.
|
|
// Step 14. Resolve promise with result.
|
|
subtle.resolve_promise_with_data(promise, plaintext);
|
|
}));
|
|
promise
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-sign>
|
|
fn Sign(
|
|
&self,
|
|
cx: &mut CurrentRealm,
|
|
algorithm: AlgorithmIdentifier,
|
|
key: &CryptoKey,
|
|
data: ArrayBufferViewOrArrayBuffer,
|
|
) -> Rc<Promise> {
|
|
// Step 1. Let algorithm and key be the algorithm and key parameters passed to the sign()
|
|
// method, respectively.
|
|
// NOTE: We did that in method parameter.
|
|
|
|
// Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
|
|
// to algorithm and op set to "sign".
|
|
// Step 3. If an error occurred, return a Promise rejected with normalizedAlgorithm.
|
|
let normalized_algorithm = match normalize_algorithm::<SignOperation>(cx, &algorithm) {
|
|
Ok(normalized_algorithm) => normalized_algorithm,
|
|
Err(error) => {
|
|
let promise = Promise::new_in_realm(cx);
|
|
promise.reject_error(error, CanGc::from_cx(cx));
|
|
return promise;
|
|
},
|
|
};
|
|
|
|
// Step 4. Let data be the result of getting a copy of the bytes held by the data parameter
|
|
// passed to the sign() method.
|
|
let data = match &data {
|
|
ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
|
|
ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
|
|
};
|
|
|
|
// Step 5. Let realm be the relevant realm of this.
|
|
// Step 6. Let promise be a new Promise.
|
|
let promise = Promise::new_in_realm(cx);
|
|
|
|
// Step 7. Return promise and perform the remaining steps in parallel.
|
|
let this = Trusted::new(self);
|
|
let trusted_promise = TrustedPromise::new(promise.clone());
|
|
let trusted_key = Trusted::new(key);
|
|
self.global()
|
|
.task_manager()
|
|
.dom_manipulation_task_source()
|
|
.queue(task!(sign: move || {
|
|
let subtle = this.root();
|
|
let promise = trusted_promise.root();
|
|
let key = trusted_key.root();
|
|
|
|
// Step 8. If the following steps or referenced procedures say to throw an error,
|
|
// queue a global task on the crypto task source, given realm's global object, to
|
|
// reject promise with the returned error; and then terminate the algorithm.
|
|
|
|
// Step 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.
|
|
if normalized_algorithm.name() != key.algorithm().name() {
|
|
subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
|
|
return;
|
|
}
|
|
|
|
// Step 10. If the [[usages]] internal slot of key does not contain an entry that
|
|
// is "sign", then throw an InvalidAccessError.
|
|
if !key.usages().contains(&KeyUsage::Sign) {
|
|
subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
|
|
return;
|
|
}
|
|
|
|
// Step 11. Let signature be the result of performing the sign operation specified
|
|
// by normalizedAlgorithm using key and algorithm and with data as message.
|
|
let signature = match normalized_algorithm.sign(&key, &data) {
|
|
Ok(signature) => signature,
|
|
Err(error) => {
|
|
subtle.reject_promise_with_error(promise, error);
|
|
return;
|
|
},
|
|
};
|
|
|
|
// Step 12. Queue a global task on the crypto task source, given realm's global
|
|
// object, to perform the remaining steps.
|
|
// Step 13. Let result be the result of creating an ArrayBuffer in realm,
|
|
// containing signature.
|
|
// Step 14. Resolve promise with result.
|
|
subtle.resolve_promise_with_data(promise, signature);
|
|
}));
|
|
promise
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-verify>
|
|
fn Verify(
|
|
&self,
|
|
cx: &mut CurrentRealm,
|
|
algorithm: AlgorithmIdentifier,
|
|
key: &CryptoKey,
|
|
signature: ArrayBufferViewOrArrayBuffer,
|
|
data: ArrayBufferViewOrArrayBuffer,
|
|
) -> Rc<Promise> {
|
|
// Step 1. Let algorithm and key be the algorithm and key parameters passed to the verify()
|
|
// method, respectively.
|
|
// NOTE: We did that in method parameter.
|
|
|
|
// Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to
|
|
// algorithm and op set to "verify".
|
|
// Step 3. If an error occurred, return a Promise rejected with normalizedAlgorithm.
|
|
let normalized_algorithm = match normalize_algorithm::<VerifyOperation>(cx, &algorithm) {
|
|
Ok(algorithm) => algorithm,
|
|
Err(error) => {
|
|
let promise = Promise::new_in_realm(cx);
|
|
promise.reject_error(error, CanGc::from_cx(cx));
|
|
return promise;
|
|
},
|
|
};
|
|
|
|
// Step 4. Let signature be the result of getting a copy of the bytes held by the signature
|
|
// parameter passed to the verify() method.
|
|
let signature = match &signature {
|
|
ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
|
|
ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
|
|
};
|
|
|
|
// Step 5. Let data be the result of getting a copy of the bytes held by the data parameter
|
|
// passed to the verify() method.
|
|
let data = match &data {
|
|
ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
|
|
ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
|
|
};
|
|
|
|
// Step 6. Let realm be the relevant realm of this.
|
|
// Step 7. Let promise be a new Promise.
|
|
let promise = Promise::new_in_realm(cx);
|
|
|
|
// Step 8. Return promise and perform the remaining steps in parallel.
|
|
let this = Trusted::new(self);
|
|
let trusted_promise = TrustedPromise::new(promise.clone());
|
|
let trusted_key = Trusted::new(key);
|
|
self.global()
|
|
.task_manager()
|
|
.dom_manipulation_task_source()
|
|
.queue(task!(sign: move || {
|
|
let subtle = this.root();
|
|
let promise = trusted_promise.root();
|
|
let key = trusted_key.root();
|
|
|
|
// Step 9. If the following steps or referenced procedures say to throw an error,
|
|
// queue a global task on the crypto task source, given realm's global object, to
|
|
// reject promise with the returned error; and then terminate the algorithm.
|
|
|
|
// Step 10. If the name member of normalizedAlgorithm is not equal to the name
|
|
// attribute of the [[algorithm]] internal slot of key then throw an
|
|
// InvalidAccessError.
|
|
if normalized_algorithm.name() != key.algorithm().name() {
|
|
subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
|
|
return;
|
|
}
|
|
|
|
// Step 11. If the [[usages]] internal slot of key does not contain an entry that
|
|
// is "verify", then throw an InvalidAccessError.
|
|
if !key.usages().contains(&KeyUsage::Verify) {
|
|
subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
|
|
return;
|
|
}
|
|
|
|
// Step 12. Let result be the result of performing the verify operation specified
|
|
// by normalizedAlgorithm using key, algorithm and signature and with data as
|
|
// message.
|
|
let result = match normalized_algorithm.verify(&key, &data, &signature) {
|
|
Ok(result) => result,
|
|
Err(error) => {
|
|
subtle.reject_promise_with_error(promise, error);
|
|
return;
|
|
},
|
|
};
|
|
|
|
// Step 13. Queue a global task on the crypto task source, given realm's global
|
|
// object, to perform the remaining steps.
|
|
// Step 14. Resolve promise with result.
|
|
subtle.resolve_promise_with_bool(promise, result);
|
|
}));
|
|
promise
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-digest>
|
|
fn Digest(
|
|
&self,
|
|
cx: &mut CurrentRealm,
|
|
algorithm: AlgorithmIdentifier,
|
|
data: ArrayBufferViewOrArrayBuffer,
|
|
) -> Rc<Promise> {
|
|
// Step 1. Let algorithm be the algorithm parameter passed to the digest() method.
|
|
// NOTE: We did that in method parameter.
|
|
|
|
// Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm,
|
|
// with alg set to algorithm and op set to "digest".
|
|
// Step 3. If an error occurred, return a Promise rejected with normalizedAlgorithm.
|
|
let normalized_algorithm = match normalize_algorithm::<DigestOperation>(cx, &algorithm) {
|
|
Ok(normalized_algorithm) => normalized_algorithm,
|
|
Err(error) => {
|
|
let promise = Promise::new_in_realm(cx);
|
|
promise.reject_error(error, CanGc::from_cx(cx));
|
|
return promise;
|
|
},
|
|
};
|
|
|
|
// Step 4. Let data be the result of getting a copy of the bytes held by the
|
|
// data parameter passed to the digest() method.
|
|
let data = match data {
|
|
ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
|
|
ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
|
|
};
|
|
|
|
// Step 5. Let realm be the relevant realm of this.
|
|
// Step 6. Let promise be a new Promise.
|
|
let promise = Promise::new_in_realm(cx);
|
|
|
|
// Step 7. Return promise and perform the remaining steps in parallel.
|
|
let this = Trusted::new(self);
|
|
let trusted_promise = TrustedPromise::new(promise.clone());
|
|
self.global()
|
|
.task_manager()
|
|
.dom_manipulation_task_source()
|
|
.queue(task!(digest_: move || {
|
|
let subtle = this.root();
|
|
let promise = trusted_promise.root();
|
|
|
|
// Step 8. If the following steps or referenced procedures say to throw an error,
|
|
// queue a global task on the crypto task source, given realm's global object, to
|
|
// reject promise with the returned error; and then terminate the algorithm.
|
|
|
|
// Step 9. Let digest be the result of performing the digest operation specified by
|
|
// normalizedAlgorithm using algorithm, with data as message.
|
|
let digest = match normalized_algorithm.digest(&data) {
|
|
Ok(digest) => digest,
|
|
Err(error) => {
|
|
subtle.reject_promise_with_error(promise, error);
|
|
return;
|
|
}
|
|
};
|
|
|
|
// Step 10. Queue a global task on the crypto task source, given realm's global
|
|
// object, to perform the remaining steps.
|
|
// Step 11. Let result be the result of creating an ArrayBuffer in realm,
|
|
// containing digest.
|
|
// Step 12. Resolve promise with result.
|
|
subtle.resolve_promise_with_data(promise, digest);
|
|
}));
|
|
promise
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-generateKey>
|
|
fn GenerateKey(
|
|
&self,
|
|
cx: &mut CurrentRealm,
|
|
algorithm: AlgorithmIdentifier,
|
|
extractable: bool,
|
|
key_usages: Vec<KeyUsage>,
|
|
) -> Rc<Promise> {
|
|
// Step 1. Let algorithm, extractable and usages be the algorithm, extractable and
|
|
// keyUsages parameters passed to the generateKey() method, respectively.
|
|
|
|
// Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
|
|
// to algorithm and op set to "generateKey".
|
|
// Step 3. If an error occurred, return a Promise rejected with normalizedAlgorithm.
|
|
let promise = Promise::new_in_realm(cx);
|
|
let normalized_algorithm = match normalize_algorithm::<GenerateKeyOperation>(cx, &algorithm)
|
|
{
|
|
Ok(normalized_algorithm) => normalized_algorithm,
|
|
Err(error) => {
|
|
promise.reject_error(error, CanGc::from_cx(cx));
|
|
return promise;
|
|
},
|
|
};
|
|
|
|
// Step 4. Let realm be the relevant realm of this.
|
|
// Step 5. Let promise be a new Promise.
|
|
// NOTE: We did that in preparation of Step 3.
|
|
|
|
// Step 6. Return promise and perform the remaining steps in parallel.
|
|
let trusted_subtle = Trusted::new(self);
|
|
let trusted_promise = TrustedPromise::new(promise.clone());
|
|
self.global()
|
|
.task_manager()
|
|
.dom_manipulation_task_source()
|
|
.queue(task!(generate_key: move |cx| {
|
|
let subtle = trusted_subtle.root();
|
|
let promise = trusted_promise.root();
|
|
|
|
// Step 7. If the following steps or referenced procedures say to throw an error,
|
|
// queue a global task on the crypto task source, given realm's global object, to
|
|
// reject promise with the returned error; and then terminate the algorithm.
|
|
|
|
// Step 8. Let result be the result of performing the generate key operation
|
|
// specified by normalizedAlgorithm using algorithm, extractable and usages.
|
|
let result = match normalized_algorithm.generate_key(
|
|
cx,
|
|
&subtle.global(),
|
|
extractable,
|
|
key_usages,
|
|
) {
|
|
Ok(result) => result,
|
|
Err(error) => {
|
|
subtle.reject_promise_with_error(promise, error);
|
|
return;
|
|
}
|
|
};
|
|
|
|
// Step 9.
|
|
// If result is a CryptoKey object:
|
|
// If the [[type]] internal slot of result is "secret" or "private" and usages
|
|
// is empty, then throw a SyntaxError.
|
|
// If result is a CryptoKeyPair object:
|
|
// If the [[usages]] internal slot of the privateKey attribute of result is the
|
|
// empty sequence, then throw a SyntaxError.
|
|
match &result {
|
|
CryptoKeyOrCryptoKeyPair::CryptoKey(crpyto_key) => {
|
|
if matches!(crpyto_key.Type(), KeyType::Secret | KeyType::Private)
|
|
&& crpyto_key.usages().is_empty()
|
|
{
|
|
subtle.reject_promise_with_error(promise, Error::Syntax(None));
|
|
return;
|
|
}
|
|
},
|
|
CryptoKeyOrCryptoKeyPair::CryptoKeyPair(crypto_key_pair) => {
|
|
if crypto_key_pair
|
|
.privateKey
|
|
.as_ref()
|
|
.is_none_or(|private_key| private_key.usages().is_empty())
|
|
{
|
|
subtle.reject_promise_with_error(promise, Error::Syntax(None));
|
|
return;
|
|
}
|
|
}
|
|
};
|
|
|
|
// Step 10. Queue a global task on the crypto task source, given realm's global
|
|
// object, to perform the remaining steps.
|
|
// Step 11. Let result be the result of converting result to an ECMAScript Object
|
|
// in realm, as defined by [WebIDL].
|
|
// Step 12. Resolve promise with result.
|
|
match result {
|
|
CryptoKeyOrCryptoKeyPair::CryptoKey(key) => {
|
|
subtle.resolve_promise_with_key(promise, key);
|
|
},
|
|
CryptoKeyOrCryptoKeyPair::CryptoKeyPair(key_pair) => {
|
|
subtle.resolve_promise_with_key_pair(promise, key_pair);
|
|
},
|
|
}
|
|
}));
|
|
|
|
promise
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-deriveKey>
|
|
fn DeriveKey(
|
|
&self,
|
|
cx: &mut CurrentRealm,
|
|
algorithm: AlgorithmIdentifier,
|
|
base_key: &CryptoKey,
|
|
derived_key_type: AlgorithmIdentifier,
|
|
extractable: bool,
|
|
usages: Vec<KeyUsage>,
|
|
) -> Rc<Promise> {
|
|
// Step 1. Let algorithm, baseKey, derivedKeyType, extractable and usages be the algorithm,
|
|
// baseKey, derivedKeyType, extractable and keyUsages parameters passed to the deriveKey()
|
|
// method, respectively.
|
|
// NOTE: We did that in method parameter.
|
|
|
|
// Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
|
|
// to algorithm and op set to "deriveBits".
|
|
// Step 3. If an error occurred, return a Promise rejected with normalizedAlgorithm.
|
|
let promise = Promise::new_in_realm(cx);
|
|
let normalized_algorithm = match normalize_algorithm::<DeriveBitsOperation>(cx, &algorithm)
|
|
{
|
|
Ok(normalized_algorithm) => normalized_algorithm,
|
|
Err(error) => {
|
|
promise.reject_error(error, CanGc::from_cx(cx));
|
|
return promise;
|
|
},
|
|
};
|
|
|
|
// Step 4. Let normalizedDerivedKeyAlgorithmImport be the result of normalizing an
|
|
// algorithm, with alg set to derivedKeyType and op set to "importKey".
|
|
// Step 5. If an error occurred, return a Promise rejected with
|
|
// normalizedDerivedKeyAlgorithmImport.
|
|
let normalized_derived_key_algorithm_import =
|
|
match normalize_algorithm::<ImportKeyOperation>(cx, &derived_key_type) {
|
|
Ok(normalized_algorithm) => normalized_algorithm,
|
|
Err(error) => {
|
|
promise.reject_error(error, CanGc::from_cx(cx));
|
|
return promise;
|
|
},
|
|
};
|
|
|
|
// Step 6. Let normalizedDerivedKeyAlgorithmLength be the result of normalizing an
|
|
// algorithm, with alg set to derivedKeyType and op set to "get key length".
|
|
// Step 7. If an error occurred, return a Promise rejected with
|
|
// normalizedDerivedKeyAlgorithmLength.
|
|
let normalized_derived_key_algorithm_length =
|
|
match normalize_algorithm::<GetKeyLengthOperation>(cx, &derived_key_type) {
|
|
Ok(normalized_algorithm) => normalized_algorithm,
|
|
Err(error) => {
|
|
promise.reject_error(error, CanGc::from_cx(cx));
|
|
return promise;
|
|
},
|
|
};
|
|
|
|
// Step 8. Let realm be the relevant realm of this.
|
|
// Step 9. Let promise be a new Promise.
|
|
// NOTE: We did that in preparation of Step 3.
|
|
|
|
// Step 10. Return promise and perform the remaining steps in parallel.
|
|
let trusted_subtle = Trusted::new(self);
|
|
let trusted_base_key = Trusted::new(base_key);
|
|
let trusted_promise = TrustedPromise::new(promise.clone());
|
|
self.global().task_manager().dom_manipulation_task_source().queue(
|
|
task!(derive_key: move |cx| {
|
|
let subtle = trusted_subtle.root();
|
|
let base_key = trusted_base_key.root();
|
|
let promise = trusted_promise.root();
|
|
|
|
// Step 11. If the following steps or referenced procedures say to throw an error,
|
|
// queue a global task on the crypto task source, given realm's global object, to
|
|
// reject promise with the returned error; and then terminate the algorithm.
|
|
|
|
// Step 12. If the name member of normalizedAlgorithm is not equal to the name
|
|
// attribute of the [[algorithm]] internal slot of baseKey then throw an
|
|
// InvalidAccessError.
|
|
if normalized_algorithm.name() != base_key.algorithm().name() {
|
|
subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
|
|
return;
|
|
}
|
|
|
|
// Step 13. If the [[usages]] internal slot of baseKey does not contain an entry
|
|
// that is "deriveKey", then throw an InvalidAccessError.
|
|
if !base_key.usages().contains(&KeyUsage::DeriveKey) {
|
|
subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
|
|
return;
|
|
}
|
|
|
|
// Step 14. Let length be the result of performing the get key length algorithm
|
|
// specified by normalizedDerivedKeyAlgorithmLength using derivedKeyType.
|
|
let length = match normalized_derived_key_algorithm_length.get_key_length() {
|
|
Ok(length) => length,
|
|
Err(error) => {
|
|
subtle.reject_promise_with_error(promise, error);
|
|
return;
|
|
}
|
|
};
|
|
|
|
// Step 15. Let secret be the result of performing the derive bits operation
|
|
// specified by normalizedAlgorithm using key, algorithm and length.
|
|
let secret = match normalized_algorithm.derive_bits(&base_key, length) {
|
|
Ok(secret) => secret,
|
|
Err(error) => {
|
|
subtle.reject_promise_with_error(promise, error);
|
|
return;
|
|
}
|
|
};
|
|
|
|
// Step 16. Let result be the result of performing the import key operation
|
|
// specified by normalizedDerivedKeyAlgorithmImport using "raw" as format, secret
|
|
// as keyData, derivedKeyType as algorithm and using extractable and usages.
|
|
// NOTE: Use "raw-secret" instead, according to
|
|
// <https://wicg.github.io/webcrypto-modern-algos/#subtlecrypto-interface-keyformat>.
|
|
let result = match normalized_derived_key_algorithm_import.import_key(
|
|
cx,
|
|
&subtle.global(),
|
|
KeyFormat::Raw_secret,
|
|
&secret,
|
|
extractable,
|
|
usages.clone(),
|
|
) {
|
|
Ok(algorithm) => algorithm,
|
|
Err(error) => {
|
|
subtle.reject_promise_with_error(promise, error);
|
|
return;
|
|
},
|
|
};
|
|
|
|
// Step 17. If the [[type]] internal slot of result is "secret" or "private" and
|
|
// usages is empty, then throw a SyntaxError.
|
|
if matches!(result.Type(), KeyType::Secret | KeyType::Private) && usages.is_empty() {
|
|
subtle.reject_promise_with_error(promise, Error::Syntax(None));
|
|
return;
|
|
}
|
|
|
|
// Step 18. Set the [[extractable]] internal slot of result to extractable.
|
|
// Step 19. Set the [[usages]] internal slot of result to the normalized value of
|
|
// usages.
|
|
// NOTE: Done by normalized_derived_key_algorithm_import.import_key in Step 16.
|
|
|
|
// Step 20. Queue a global task on the crypto task source, given realm's global
|
|
// object, to perform the remaining steps.
|
|
// Step 20. Let result be the result of converting result to an ECMAScript Object
|
|
// in realm, as defined by [WebIDL].
|
|
// Step 20. Resolve promise with result.
|
|
subtle.resolve_promise_with_key(promise, result);
|
|
}),
|
|
);
|
|
promise
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-deriveBits>
|
|
fn DeriveBits(
|
|
&self,
|
|
cx: &mut CurrentRealm,
|
|
algorithm: AlgorithmIdentifier,
|
|
base_key: &CryptoKey,
|
|
length: Option<u32>,
|
|
) -> Rc<Promise> {
|
|
// Step 1. Let algorithm, baseKey and length, be the algorithm, baseKey and length
|
|
// parameters passed to the deriveBits() method, respectively.
|
|
// NOTE: We did that in method parameter.
|
|
|
|
// Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
|
|
// to algorithm and op set to "deriveBits".
|
|
// Step 3. If an error occurred, return a Promise rejected with normalizedAlgorithm.
|
|
let promise = Promise::new_in_realm(cx);
|
|
let normalized_algorithm = match normalize_algorithm::<DeriveBitsOperation>(cx, &algorithm)
|
|
{
|
|
Ok(normalized_algorithm) => normalized_algorithm,
|
|
Err(error) => {
|
|
promise.reject_error(error, CanGc::from_cx(cx));
|
|
return promise;
|
|
},
|
|
};
|
|
|
|
// Step 4. Let realm be the relevant realm of this.
|
|
// Step 5. Let promise be a new Promise.
|
|
// NOTE: We did that in preparation of Step 3.
|
|
|
|
// Step 5. Return promise and perform the remaining steps in parallel.
|
|
let trsuted_subtle = Trusted::new(self);
|
|
let trusted_base_key = Trusted::new(base_key);
|
|
let trusted_promise = TrustedPromise::new(promise.clone());
|
|
self.global()
|
|
.task_manager()
|
|
.dom_manipulation_task_source()
|
|
.queue(task!(import_key: move || {
|
|
let subtle = trsuted_subtle.root();
|
|
let base_key = trusted_base_key.root();
|
|
let promise = trusted_promise.root();
|
|
|
|
// Step 7. If the following steps or referenced procedures say to throw an error,
|
|
// queue a global task on the crypto task source, given realm's global object, to
|
|
// reject promise with the returned error; and then terminate the algorithm.
|
|
|
|
// Step 8. If the name member of normalizedAlgorithm is not equal to the name
|
|
// attribute of the [[algorithm]] internal slot of baseKey then throw an
|
|
// InvalidAccessError.
|
|
if normalized_algorithm.name() != base_key.algorithm().name() {
|
|
subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
|
|
return;
|
|
}
|
|
|
|
// Step 9. If the [[usages]] internal slot of baseKey does not contain an entry
|
|
// that is "deriveBits", then throw an InvalidAccessError.
|
|
if !base_key.usages().contains(&KeyUsage::DeriveBits) {
|
|
subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
|
|
return;
|
|
}
|
|
|
|
// Step 10. Let bits be the result of performing the derive bits operation
|
|
// specified by normalizedAlgorithm using baseKey, algorithm and length.
|
|
let bits = match normalized_algorithm.derive_bits(&base_key, length) {
|
|
Ok(bits) => bits,
|
|
Err(error) => {
|
|
subtle.reject_promise_with_error(promise, error);
|
|
return;
|
|
}
|
|
};
|
|
|
|
// Step 11. Queue a global task on the crypto task source, given realm's global
|
|
// object, to perform the remaining steps.
|
|
// Step 12. Let result be the result of creating an ArrayBuffer in realm,
|
|
// containing bits.
|
|
// Step 13. Resolve promise with result.
|
|
subtle.resolve_promise_with_data(promise, bits);
|
|
}));
|
|
promise
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-importKey>
|
|
fn ImportKey(
|
|
&self,
|
|
cx: &mut CurrentRealm,
|
|
format: KeyFormat,
|
|
key_data: ArrayBufferViewOrArrayBufferOrJsonWebKey,
|
|
algorithm: AlgorithmIdentifier,
|
|
extractable: bool,
|
|
key_usages: Vec<KeyUsage>,
|
|
) -> Rc<Promise> {
|
|
// Step 1. Let format, algorithm, extractable and usages, be the format, algorithm,
|
|
// extractable and keyUsages parameters passed to the importKey() method, respectively.
|
|
|
|
// Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
|
|
// to algorithm and op set to "importKey".
|
|
// Step 3. If an error occurred, return a Promise rejected with normalizedAlgorithm.
|
|
let normalized_algorithm = match normalize_algorithm::<ImportKeyOperation>(cx, &algorithm) {
|
|
Ok(algorithm) => algorithm,
|
|
Err(error) => {
|
|
let promise = Promise::new_in_realm(cx);
|
|
promise.reject_error(error, CanGc::from_cx(cx));
|
|
return promise;
|
|
},
|
|
};
|
|
|
|
// Step 4.
|
|
let key_data = match format {
|
|
// If format is equal to the string "jwk":
|
|
KeyFormat::Jwk => {
|
|
match key_data {
|
|
ArrayBufferViewOrArrayBufferOrJsonWebKey::ArrayBufferView(_) |
|
|
ArrayBufferViewOrArrayBufferOrJsonWebKey::ArrayBuffer(_) => {
|
|
// Step 4.1. If the keyData parameter passed to the importKey() method is
|
|
// not a JsonWebKey dictionary, throw a TypeError.
|
|
let promise = Promise::new_in_realm(cx);
|
|
promise.reject_error(
|
|
Error::Type(c"The keyData type does not match the format".to_owned()),
|
|
CanGc::from_cx(cx),
|
|
);
|
|
return promise;
|
|
},
|
|
|
|
ArrayBufferViewOrArrayBufferOrJsonWebKey::JsonWebKey(jwk) => {
|
|
// Step 4.2. Let keyData be the keyData parameter passed to the importKey()
|
|
// method.
|
|
//
|
|
// NOTE: Serialize JsonWebKey throught stringifying it.
|
|
// JsonWebKey::stringify internally relies on ToJSON, so it will raise an
|
|
// exception when a JS error is thrown. When this happens, we report the
|
|
// error.
|
|
match jwk.stringify(cx) {
|
|
Ok(stringified) => stringified.as_bytes().to_vec(),
|
|
Err(error) => {
|
|
let promise = Promise::new_in_realm(cx);
|
|
promise.reject_error(error, CanGc::from_cx(cx));
|
|
return promise;
|
|
},
|
|
}
|
|
},
|
|
}
|
|
},
|
|
// Otherwise:
|
|
_ => {
|
|
match key_data {
|
|
// Step 4.1. If the keyData parameter passed to the importKey() method is a
|
|
// JsonWebKey dictionary, throw a TypeError.
|
|
ArrayBufferViewOrArrayBufferOrJsonWebKey::JsonWebKey(_) => {
|
|
let promise = Promise::new_in_realm(cx);
|
|
promise.reject_error(
|
|
Error::Type(c"The keyData type does not match the format".to_owned()),
|
|
CanGc::from_cx(cx),
|
|
);
|
|
return promise;
|
|
},
|
|
|
|
// Step 4.2. Let keyData be the result of getting a copy of the bytes held by
|
|
// the keyData parameter passed to the importKey() method.
|
|
ArrayBufferViewOrArrayBufferOrJsonWebKey::ArrayBufferView(view) => {
|
|
view.to_vec()
|
|
},
|
|
ArrayBufferViewOrArrayBufferOrJsonWebKey::ArrayBuffer(buffer) => {
|
|
buffer.to_vec()
|
|
},
|
|
}
|
|
},
|
|
};
|
|
|
|
// Step 5. Let realm be the relevant realm of this.
|
|
// Step 6. Let promise be a new Promise.
|
|
let promise = Promise::new_in_realm(cx);
|
|
|
|
// Step 7. Return promise and perform the remaining steps in parallel.
|
|
let this = Trusted::new(self);
|
|
let trusted_promise = TrustedPromise::new(promise.clone());
|
|
self.global()
|
|
.task_manager()
|
|
.dom_manipulation_task_source()
|
|
.queue(task!(import_key: move |cx| {
|
|
let subtle = this.root();
|
|
let promise = trusted_promise.root();
|
|
|
|
// Step 8. If the following steps or referenced procedures say to throw an error,
|
|
// queue a global task on the crypto task source, given realm's global object, to
|
|
// reject promise with the returned error; and then terminate the algorithm.
|
|
|
|
// Step 9. Let result be the CryptoKey object that results from performing the
|
|
// import key operation specified by normalizedAlgorithm using keyData, algorithm,
|
|
// format, extractable and usages.
|
|
let result = match normalized_algorithm.import_key(
|
|
cx,
|
|
&subtle.global(),
|
|
format,
|
|
&key_data,
|
|
extractable,
|
|
key_usages.clone(),
|
|
) {
|
|
Ok(key) => key,
|
|
Err(error) => {
|
|
subtle.reject_promise_with_error(promise, error);
|
|
return;
|
|
},
|
|
};
|
|
|
|
// Step 10. If the [[type]] internal slot of result is "secret" or "private" and
|
|
// usages is empty, then throw a SyntaxError.
|
|
if matches!(result.Type(), KeyType::Secret | KeyType::Private) && key_usages.is_empty() {
|
|
subtle.reject_promise_with_error(promise, Error::Syntax(None));
|
|
return;
|
|
}
|
|
|
|
// Step 11. Set the [[extractable]] internal slot of result to extractable.
|
|
result.set_extractable(extractable);
|
|
|
|
// Step 12. Set the [[usages]] internal slot of result to the normalized value of usages.
|
|
result.set_usages(cx, &key_usages);
|
|
|
|
// Step 13. Queue a global task on the crypto task source, given realm's global
|
|
// object, to perform the remaining steps.
|
|
// Step 14. Let result be the result of converting result to an ECMAScript Object
|
|
// in realm, as defined by [WebIDL].
|
|
// Step 15. Resolve promise with result.
|
|
subtle.resolve_promise_with_key(promise, result);
|
|
}));
|
|
|
|
promise
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-exportKey>
|
|
fn ExportKey(&self, cx: &mut CurrentRealm, format: KeyFormat, key: &CryptoKey) -> Rc<Promise> {
|
|
// Step 1. Let format and key be the format and key parameters passed to the exportKey()
|
|
// method, respectively.
|
|
// NOTE: We did that in method parameter.
|
|
|
|
// Step 2. Let realm be the relevant realm of this.
|
|
// Step 3. Let promise be a new Promise.
|
|
let promise = Promise::new_in_realm(cx);
|
|
|
|
// Step 4. Return promise and perform the remaining steps in parallel.
|
|
let trusted_subtle = Trusted::new(self);
|
|
let trusted_promise = TrustedPromise::new(promise.clone());
|
|
let trusted_key = Trusted::new(key);
|
|
self.global()
|
|
.task_manager()
|
|
.dom_manipulation_task_source()
|
|
.queue(task!(export_key: move |cx| {
|
|
let subtle = trusted_subtle.root();
|
|
let promise = trusted_promise.root();
|
|
let key = trusted_key.root();
|
|
|
|
// Step 5. If the following steps or referenced procedures say to throw an error,
|
|
// queue a global task on the crypto task source, given realm's global object, to
|
|
// reject promise with the returned error; and then terminate the algorithm.
|
|
|
|
// Step 6. If the name member of the [[algorithm]] internal slot of key does not
|
|
// identify a registered algorithm that supports the export key operation, then
|
|
// throw a NotSupportedError.
|
|
//
|
|
// NOTE: We rely on [`normalize_algorithm`] to check whether the algorithm supports
|
|
// the export key operation.
|
|
let export_key_algorithm = match normalize_algorithm::<ExportKeyOperation>(
|
|
cx,
|
|
&AlgorithmIdentifier::String(DOMString::from(key.algorithm().name().as_str())),
|
|
) {
|
|
Ok(normalized_algorithm) => normalized_algorithm,
|
|
Err(error) => {
|
|
subtle.reject_promise_with_error(promise, error);
|
|
return;
|
|
},
|
|
};
|
|
|
|
// Step 7. If the [[extractable]] internal slot of key is false, then throw an
|
|
// InvalidAccessError.
|
|
if !key.Extractable() {
|
|
subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
|
|
return;
|
|
}
|
|
|
|
// Step 8. Let result be the result of performing the export key operation
|
|
// specified by the [[algorithm]] internal slot of key using key and format.
|
|
let result = match export_key_algorithm.export_key(format, &key) {
|
|
Ok(exported_key) => exported_key,
|
|
Err(error) => {
|
|
subtle.reject_promise_with_error(promise, error);
|
|
return;
|
|
},
|
|
};
|
|
|
|
// Step 9. Queue a global task on the crypto task source, given realm's global
|
|
// object, to perform the remaining steps.
|
|
// Step 10.
|
|
// If format is equal to the string "jwk":
|
|
// Let result be the result of converting result to an ECMAScript Object in
|
|
// realm, as defined by [WebIDL].
|
|
// Otherwise:
|
|
// Let result be the result of creating an ArrayBuffer in realm, containing
|
|
// result.
|
|
// Step 11. Resolve promise with result.
|
|
// NOTE: We determine the format by pattern matching on result, which is an
|
|
// ExportedKey enum.
|
|
match result {
|
|
ExportedKey::Bytes(bytes) => {
|
|
subtle.resolve_promise_with_data(promise, bytes);
|
|
},
|
|
ExportedKey::Jwk(jwk) => {
|
|
subtle.resolve_promise_with_jwk(cx, promise, jwk);
|
|
},
|
|
}
|
|
}));
|
|
promise
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-wrapKey>
|
|
fn WrapKey(
|
|
&self,
|
|
cx: &mut CurrentRealm,
|
|
format: KeyFormat,
|
|
key: &CryptoKey,
|
|
wrapping_key: &CryptoKey,
|
|
algorithm: AlgorithmIdentifier,
|
|
) -> Rc<Promise> {
|
|
// Step 1. Let format, key, wrappingKey and algorithm be the format, key, wrappingKey and
|
|
// wrapAlgorithm parameters passed to the wrapKey() method, respectively.
|
|
// NOTE: We did that in method parameter.
|
|
|
|
// Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
|
|
// to algorithm and op set to "wrapKey".
|
|
// Step 3. If an error occurred, let normalizedAlgorithm be the result of normalizing an
|
|
// algorithm, with alg set to algorithm and op set to "encrypt".
|
|
// Step 4. If an error occurred, return a Promise rejected with normalizedAlgorithm.
|
|
enum WrapKeyAlgorithmOrEncryptAlgorithm {
|
|
WrapKeyAlgorithm(WrapKeyAlgorithm),
|
|
EncryptAlgorithm(EncryptAlgorithm),
|
|
}
|
|
let normalized_algorithm = if let Ok(algorithm) =
|
|
normalize_algorithm::<WrapKeyOperation>(cx, &algorithm)
|
|
{
|
|
WrapKeyAlgorithmOrEncryptAlgorithm::WrapKeyAlgorithm(algorithm)
|
|
} else {
|
|
match normalize_algorithm::<EncryptOperation>(cx, &algorithm) {
|
|
Ok(algorithm) => WrapKeyAlgorithmOrEncryptAlgorithm::EncryptAlgorithm(algorithm),
|
|
Err(error) => {
|
|
let promise = Promise::new_in_realm(cx);
|
|
promise.reject_error(error, CanGc::from_cx(cx));
|
|
return promise;
|
|
},
|
|
}
|
|
};
|
|
|
|
// Step 5. Let realm be the relevant realm of this.
|
|
// Step 6. Let promise be a new Promise.
|
|
let promise = Promise::new_in_realm(cx);
|
|
|
|
// Step 7. Return promise and perform the remaining steps in parallel.
|
|
let trusted_subtle = Trusted::new(self);
|
|
let trusted_key = Trusted::new(key);
|
|
let trusted_wrapping_key = Trusted::new(wrapping_key);
|
|
let trusted_promise = TrustedPromise::new(promise.clone());
|
|
self.global()
|
|
.task_manager()
|
|
.dom_manipulation_task_source()
|
|
.queue(task!(wrap_key: move |cx| {
|
|
let subtle = trusted_subtle.root();
|
|
let key = trusted_key.root();
|
|
let wrapping_key = trusted_wrapping_key.root();
|
|
let promise = trusted_promise.root();
|
|
|
|
// Step 8. If the following steps or referenced procedures say to throw an error,
|
|
// queue a global task on the crypto task source, given realm's global object, to
|
|
// reject promise with the returned error; and then terminate the algorithm.
|
|
|
|
// Step 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.
|
|
let normalized_algorithm_name = match &normalized_algorithm {
|
|
WrapKeyAlgorithmOrEncryptAlgorithm::WrapKeyAlgorithm(algorithm) => {
|
|
algorithm.name()
|
|
},
|
|
WrapKeyAlgorithmOrEncryptAlgorithm::EncryptAlgorithm(algorithm) => {
|
|
algorithm.name()
|
|
},
|
|
};
|
|
if normalized_algorithm_name != wrapping_key.algorithm().name() {
|
|
subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
|
|
return;
|
|
}
|
|
|
|
// Step 10. If the [[usages]] internal slot of wrappingKey does not contain an
|
|
// entry that is "wrapKey", then throw an InvalidAccessError.
|
|
if !wrapping_key.usages().contains(&KeyUsage::WrapKey) {
|
|
subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
|
|
return;
|
|
}
|
|
|
|
// Step 11. If the algorithm identified by the [[algorithm]] internal slot of key
|
|
// does not support the export key operation, then throw a NotSupportedError.
|
|
//
|
|
// NOTE: We rely on [`normalize_algorithm`] to check whether the algorithm supports
|
|
// the export key operation.
|
|
let export_key_algorithm = match normalize_algorithm::<ExportKeyOperation>(
|
|
cx,
|
|
&AlgorithmIdentifier::String(DOMString::from(key.algorithm().name().as_str())),
|
|
) {
|
|
Ok(normalized_algorithm) => normalized_algorithm,
|
|
Err(error) => {
|
|
subtle.reject_promise_with_error(promise, error);
|
|
return;
|
|
},
|
|
};
|
|
|
|
// Step 12. If the [[extractable]] internal slot of key is false, then throw an
|
|
// InvalidAccessError.
|
|
if !key.Extractable() {
|
|
subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
|
|
return;
|
|
}
|
|
|
|
// Step 13. Let exportedKey be the result of performing the export key operation
|
|
// specified by the [[algorithm]] internal slot of key using key and format.
|
|
let exported_key = match export_key_algorithm.export_key(format, &key) {
|
|
Ok(exported_key) => exported_key,
|
|
Err(error) => {
|
|
subtle.reject_promise_with_error(promise, error);
|
|
return;
|
|
},
|
|
};
|
|
|
|
// Step 14.
|
|
// If format is equal to the string "jwk":
|
|
// Step 14.1. Let json be the result of representing exportedKey as a UTF-16
|
|
// string conforming to the JSON grammar; for example, by executing the
|
|
// JSON.stringify algorithm specified in [ECMA-262] in the context of a new
|
|
// global object.
|
|
// Step 14.2. Let bytes be the result of UTF-8 encoding json.
|
|
// Otherwise:
|
|
// Let bytes be exportedKey.
|
|
// NOTE: We determine the format by pattern matching on result, which is an
|
|
// ExportedKey enum.
|
|
let bytes = match exported_key {
|
|
ExportedKey::Bytes(bytes) => bytes,
|
|
ExportedKey::Jwk(jwk) => match jwk.stringify(cx) {
|
|
Ok(stringified_jwk) => stringified_jwk.as_bytes().to_vec(),
|
|
Err(error) => {
|
|
subtle.reject_promise_with_error(promise, error);
|
|
return;
|
|
},
|
|
},
|
|
};
|
|
|
|
// Step 15.
|
|
// If normalizedAlgorithm supports the wrap key operation:
|
|
// Let result be the result of performing the wrap key operation specified by
|
|
// normalizedAlgorithm using algorithm, wrappingKey as key and bytes as
|
|
// plaintext.
|
|
// Otherwise, if normalizedAlgorithm supports the encrypt operation:
|
|
// Let result be the result of performing the encrypt operation specified by
|
|
// normalizedAlgorithm using algorithm, wrappingKey as key and bytes as
|
|
// plaintext.
|
|
// Otherwise:
|
|
// throw a NotSupportedError.
|
|
let result = match normalized_algorithm {
|
|
WrapKeyAlgorithmOrEncryptAlgorithm::WrapKeyAlgorithm(algorithm) => {
|
|
algorithm.wrap_key(&wrapping_key, &bytes)
|
|
},
|
|
WrapKeyAlgorithmOrEncryptAlgorithm::EncryptAlgorithm(algorithm) => {
|
|
algorithm.encrypt(&wrapping_key, &bytes)
|
|
},
|
|
};
|
|
let result = match result {
|
|
Ok(result) => result,
|
|
Err(error) => {
|
|
subtle.reject_promise_with_error(promise, error);
|
|
return;
|
|
},
|
|
};
|
|
|
|
// Step 16. Queue a global task on the crypto task source, given realm's global
|
|
// object, to perform the remaining steps.
|
|
// Step 17. Let result be the result of creating an ArrayBuffer in realm,
|
|
// containing result.
|
|
// Step 18. Resolve promise with result.
|
|
subtle.resolve_promise_with_data(promise, result);
|
|
}));
|
|
promise
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-unwrapKey>
|
|
fn UnwrapKey(
|
|
&self,
|
|
cx: &mut CurrentRealm,
|
|
format: KeyFormat,
|
|
wrapped_key: ArrayBufferViewOrArrayBuffer,
|
|
unwrapping_key: &CryptoKey,
|
|
algorithm: AlgorithmIdentifier,
|
|
unwrapped_key_algorithm: AlgorithmIdentifier,
|
|
extractable: bool,
|
|
usages: Vec<KeyUsage>,
|
|
) -> Rc<Promise> {
|
|
// Step 1. Let format, unwrappingKey, algorithm, unwrappedKeyAlgorithm, extractable and
|
|
// usages, be the format, unwrappingKey, unwrapAlgorithm, unwrappedKeyAlgorithm,
|
|
// extractable and keyUsages parameters passed to the unwrapKey() method, respectively.
|
|
// NOTE: We did that in method parameter.
|
|
|
|
// Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
|
|
// to algorithm and op set to "unwrapKey".
|
|
// Step 3. If an error occurred, let normalizedAlgorithm be the result of normalizing an
|
|
// algorithm, with alg set to algorithm and op set to "decrypt".
|
|
// Step 4. If an error occurred, return a Promise rejected with normalizedAlgorithm.
|
|
enum UnwrapKeyAlgorithmOrDecryptAlgorithm {
|
|
UnwrapKeyAlgorithm(UnwrapKeyAlgorithm),
|
|
DecryptAlgorithm(DecryptAlgorithm),
|
|
}
|
|
let normalized_algorithm = if let Ok(algorithm) =
|
|
normalize_algorithm::<UnwrapKeyOperation>(cx, &algorithm)
|
|
{
|
|
UnwrapKeyAlgorithmOrDecryptAlgorithm::UnwrapKeyAlgorithm(algorithm)
|
|
} else {
|
|
match normalize_algorithm::<DecryptOperation>(cx, &algorithm) {
|
|
Ok(algorithm) => UnwrapKeyAlgorithmOrDecryptAlgorithm::DecryptAlgorithm(algorithm),
|
|
Err(error) => {
|
|
let promise = Promise::new_in_realm(cx);
|
|
promise.reject_error(error, CanGc::from_cx(cx));
|
|
return promise;
|
|
},
|
|
}
|
|
};
|
|
|
|
// Step 5. Let normalizedKeyAlgorithm be the result of normalizing an algorithm, with alg
|
|
// set to unwrappedKeyAlgorithm and op set to "importKey".
|
|
// Step 6. If an error occurred, return a Promise rejected with normalizedKeyAlgorithm.
|
|
let normalized_key_algorithm =
|
|
match normalize_algorithm::<ImportKeyOperation>(cx, &unwrapped_key_algorithm) {
|
|
Ok(algorithm) => algorithm,
|
|
Err(error) => {
|
|
let promise = Promise::new_in_realm(cx);
|
|
promise.reject_error(error, CanGc::from_cx(cx));
|
|
return promise;
|
|
},
|
|
};
|
|
|
|
// Step 7. Let wrappedKey be the result of getting a copy of the bytes held by the
|
|
// wrappedKey parameter passed to the unwrapKey() method.
|
|
let wrapped_key = match wrapped_key {
|
|
ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
|
|
ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
|
|
};
|
|
|
|
// Step 8. Let realm be the relevant realm of this.
|
|
// Step 9. Let promise be a new Promise.
|
|
let promise = Promise::new_in_realm(cx);
|
|
|
|
// Step 10. Return promise and perform the remaining steps in parallel.
|
|
let trusted_subtle = Trusted::new(self);
|
|
let trusted_unwrapping_key = Trusted::new(unwrapping_key);
|
|
let trusted_promise = TrustedPromise::new(promise.clone());
|
|
self.global().task_manager().dom_manipulation_task_source().queue(
|
|
task!(unwrap_key: move |cx| {
|
|
let subtle = trusted_subtle.root();
|
|
let unwrapping_key = trusted_unwrapping_key.root();
|
|
let promise = trusted_promise.root();
|
|
|
|
// Step 11. If the following steps or referenced procedures say to throw an error,
|
|
// queue a global task on the crypto task source, given realm's global object, to
|
|
// reject promise with the returned error; and then terminate the algorithm.
|
|
|
|
// Step 12. If the name member of normalizedAlgorithm is not equal to the name
|
|
// attribute of the [[algorithm]] internal slot of unwrappingKey then throw an
|
|
// InvalidAccessError.
|
|
let normalized_algorithm_name = match &normalized_algorithm {
|
|
UnwrapKeyAlgorithmOrDecryptAlgorithm::UnwrapKeyAlgorithm(algorithm) => {
|
|
algorithm.name()
|
|
},
|
|
UnwrapKeyAlgorithmOrDecryptAlgorithm::DecryptAlgorithm(algorithm) => {
|
|
algorithm.name()
|
|
},
|
|
};
|
|
if normalized_algorithm_name != unwrapping_key.algorithm().name() {
|
|
subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
|
|
return;
|
|
}
|
|
|
|
// Step 13. If the [[usages]] internal slot of unwrappingKey does not contain an
|
|
// entry that is "unwrapKey", then throw an InvalidAccessError.
|
|
if !unwrapping_key.usages().contains(&KeyUsage::UnwrapKey) {
|
|
subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
|
|
return;
|
|
}
|
|
|
|
// Step 14.
|
|
// If normalizedAlgorithm supports an unwrap key operation:
|
|
// Let bytes be the result of performing the unwrap key operation specified by
|
|
// normalizedAlgorithm using algorithm, unwrappingKey as key and wrappedKey as
|
|
// ciphertext.
|
|
// Otherwise, if normalizedAlgorithm supports a decrypt operation:
|
|
// Let bytes be the result of performing the decrypt operation specified by
|
|
// normalizedAlgorithm using algorithm, unwrappingKey as key and wrappedKey as
|
|
// ciphertext.
|
|
// Otherwise:
|
|
// throw a NotSupportedError.
|
|
let bytes = match normalized_algorithm {
|
|
UnwrapKeyAlgorithmOrDecryptAlgorithm::UnwrapKeyAlgorithm(algorithm) => {
|
|
algorithm.unwrap_key(&unwrapping_key, &wrapped_key)
|
|
},
|
|
UnwrapKeyAlgorithmOrDecryptAlgorithm::DecryptAlgorithm(algorithm) => {
|
|
algorithm.decrypt(&unwrapping_key, &wrapped_key)
|
|
},
|
|
};
|
|
let bytes = match bytes {
|
|
Ok(bytes) => bytes,
|
|
Err(error) => {
|
|
subtle.reject_promise_with_error(promise, error);
|
|
return;
|
|
},
|
|
};
|
|
|
|
// Step 15.
|
|
// If format is equal to the string "jwk":
|
|
// Let key be the result of executing the parse a JWK algorithm, with bytes as
|
|
// the data to be parsed.
|
|
// NOTE: We only parse bytes by executing the parse a JWK algorithm, but keep
|
|
// it as raw bytes for later steps, instead of converting it to a JsonWebKey
|
|
// dictionary.
|
|
//
|
|
// Otherwise:
|
|
// Let key be bytes.
|
|
if format == KeyFormat::Jwk {
|
|
if let Err(error) = JsonWebKey::parse(cx, &bytes) {
|
|
subtle.reject_promise_with_error(promise, error);
|
|
return;
|
|
}
|
|
}
|
|
let key = bytes;
|
|
|
|
// Step 16. Let result be the result of performing the import key operation
|
|
// specified by normalizedKeyAlgorithm using unwrappedKeyAlgorithm as algorithm,
|
|
// format, usages and extractable and with key as keyData.
|
|
let result = match normalized_key_algorithm.import_key(
|
|
cx,
|
|
&subtle.global(),
|
|
format,
|
|
&key,
|
|
extractable,
|
|
usages.clone(),
|
|
) {
|
|
Ok(result) => result,
|
|
Err(error) => {
|
|
subtle.reject_promise_with_error(promise, error);
|
|
return;
|
|
},
|
|
};
|
|
|
|
// Step 17. If the [[type]] internal slot of result is "secret" or "private" and
|
|
// usages is empty, then throw a SyntaxError.
|
|
if matches!(result.Type(), KeyType::Secret | KeyType::Private) && usages.is_empty() {
|
|
subtle.reject_promise_with_error(promise, Error::Syntax(None));
|
|
return;
|
|
}
|
|
|
|
// Step 18. Set the [[extractable]] internal slot of result to extractable.
|
|
// Step 19. Set the [[usages]] internal slot of result to the normalized value of
|
|
// usages.
|
|
// NOTE: Done by normalized_algorithm.import_key in Step 16.
|
|
|
|
// Step 20. Queue a global task on the crypto task source, given realm's global
|
|
// object, to perform the remaining steps.
|
|
// Step 21. Let result be the result of converting result to an ECMAScript Object
|
|
// in realm, as defined by [WebIDL].
|
|
// Step 22. Resolve promise with result.
|
|
subtle.resolve_promise_with_key(promise, result);
|
|
}),
|
|
);
|
|
promise
|
|
}
|
|
|
|
/// <https://wicg.github.io/webcrypto-modern-algos/#SubtleCrypto-method-encapsulateKey>
|
|
fn EncapsulateKey(
|
|
&self,
|
|
cx: &mut CurrentRealm,
|
|
encapsulation_algorithm: AlgorithmIdentifier,
|
|
encapsulation_key: &CryptoKey,
|
|
shared_key_algorithm: AlgorithmIdentifier,
|
|
extractable: bool,
|
|
usages: Vec<KeyUsage>,
|
|
) -> Rc<Promise> {
|
|
// Step 1. Let encapsulationAlgorithm, encapsulationKey, sharedKeyAlgorithm, extractable
|
|
// and usages be the encapsulationAlgorithm, encapsulationKey, sharedKeyAlgorithm,
|
|
// extractable and keyUsages parameters passed to the encapsulateKey() method,
|
|
// respectively.
|
|
|
|
// Step 2. Let normalizedEncapsulationAlgorithm be the result of normalizing an algorithm,
|
|
// with alg set to encapsulationAlgorithm and op set to "encapsulate".
|
|
// Step 3. If an error occurred, return a Promise rejected with
|
|
// normalizedEncapsulationAlgorithm.
|
|
let promise = Promise::new_in_realm(cx);
|
|
let normalized_encapsulation_algorithm =
|
|
match normalize_algorithm::<EncapsulateOperation>(cx, &encapsulation_algorithm) {
|
|
Ok(algorithm) => algorithm,
|
|
Err(error) => {
|
|
promise.reject_error(error, CanGc::from_cx(cx));
|
|
return promise;
|
|
},
|
|
};
|
|
|
|
// Step 4. Let normalizedSharedKeyAlgorithm be the result of normalizing an algorithm, with
|
|
// alg set to sharedKeyAlgorithm and op set to "importKey".
|
|
// Step 5. If an error occurred, return a Promise rejected with
|
|
// normalizedSharedKeyAlgorithm.
|
|
let normalized_shared_key_algorithm =
|
|
match normalize_algorithm::<ImportKeyOperation>(cx, &shared_key_algorithm) {
|
|
Ok(algorithm) => algorithm,
|
|
Err(error) => {
|
|
promise.reject_error(error, CanGc::from_cx(cx));
|
|
return promise;
|
|
},
|
|
};
|
|
|
|
// Step 6. Let realm be the relevant realm of this.
|
|
// Step 7. Let promise be a new Promise.
|
|
// NOTE: We did that in preparation of Step 3.
|
|
|
|
// Step 8. Return promise and perform the remaining steps in parallel.
|
|
let trusted_subtle = Trusted::new(self);
|
|
let trusted_encapsulated_key = Trusted::new(encapsulation_key);
|
|
let trusted_promise = TrustedPromise::new(promise.clone());
|
|
self.global().task_manager().dom_manipulation_task_source().queue(
|
|
task!(encapsulate_keys: move |cx| {
|
|
let subtle = trusted_subtle.root();
|
|
let encapsulation_key = trusted_encapsulated_key.root();
|
|
let promise = trusted_promise.root();
|
|
|
|
// Step 9. If the following steps or referenced procedures say to throw an error,
|
|
// queue a global task on the crypto task source, given realm's global object, to
|
|
// reject promise with the returned error; and then terminate the algorithm.
|
|
|
|
// Step 10. If the name member of normalizedEncapsulationAlgorithm is not equal to
|
|
// the name attribute of the [[algorithm]] internal slot of encapsulationKey then
|
|
// throw an InvalidAccessError.
|
|
if normalized_encapsulation_algorithm.name() != encapsulation_key.algorithm().name() {
|
|
subtle.reject_promise_with_error(promise, Error::InvalidAccess(Some(
|
|
"[[algorithm]] internal slot of encapsulationKey is not equal to \
|
|
normalizedEncapsulationAlgorithm".to_string(),
|
|
)));
|
|
return;
|
|
}
|
|
|
|
// Step 11. If the [[usages]] internal slot of encapsulationKey does not contain an
|
|
// entry that is "encapsulateKey", then throw an InvalidAccessError.
|
|
if !encapsulation_key.usages().contains(&KeyUsage::EncapsulateKey) {
|
|
subtle.reject_promise_with_error(promise, Error::InvalidAccess(Some(
|
|
"[[usages]] internal slot of encapsulationKey does not contain an \
|
|
entry that is \"encapsulateBits\"".to_string(),
|
|
)));
|
|
return;
|
|
}
|
|
|
|
// Step 12. Let encapsulatedBits be the result of performing the encapsulate
|
|
// operation specified by the [[algorithm]] internal slot of encapsulationKey using
|
|
// encapsulationKey.
|
|
// NOTE: Step 10 guarantees normalizedEncapsulationAlgorithm specifies the same
|
|
// algorithm as the [[algorithm]] internal slot of encapsulationKey.
|
|
let encapsulated_bits_result =
|
|
normalized_encapsulation_algorithm.encapsulate(&encapsulation_key);
|
|
let encapsulated_bits = match encapsulated_bits_result {
|
|
Ok(encapsulated_bits) => encapsulated_bits,
|
|
Err(error) => {
|
|
subtle.reject_promise_with_error(promise, error);
|
|
return;
|
|
},
|
|
};
|
|
|
|
// Step 13. Let sharedKey be the result of performing the import key operation
|
|
// specified by normalizedSharedKeyAlgorithm using "raw-secret" as format, the
|
|
// sharedKey field of encapsulatedBits as keyData, sharedKeyAlgorithm as algorithm
|
|
// and using extractable and usages.
|
|
// Step 14. Set the [[extractable]] internal slot of sharedKey to extractable.
|
|
// Step 15. Set the [[usages]] internal slot of sharedKey to the normalized value
|
|
// of usages.
|
|
let encapsulated_shared_key = match &encapsulated_bits.shared_key {
|
|
Some(shared_key) => shared_key,
|
|
None => {
|
|
subtle.reject_promise_with_error(promise, Error::Operation(Some(
|
|
"Shared key is missing in the result of the encapsulate operation"
|
|
.to_string())));
|
|
return;
|
|
},
|
|
};
|
|
let shared_key_result = normalized_shared_key_algorithm.import_key(
|
|
cx,
|
|
&subtle.global(),
|
|
KeyFormat::Raw_secret,
|
|
encapsulated_shared_key,
|
|
extractable,
|
|
usages.clone(),
|
|
);
|
|
let shared_key = match shared_key_result {
|
|
Ok(shared_key) => shared_key,
|
|
Err(error) => {
|
|
subtle.reject_promise_with_error(promise, error);
|
|
return;
|
|
},
|
|
};
|
|
|
|
// Step 16. Let encapsulatedKey be a new EncapsulatedKey dictionary with sharedKey
|
|
// set to sharedKey and ciphertext set to the ciphertext field of encapsulatedBits.
|
|
let encapsulated_key = SubtleEncapsulatedKey {
|
|
shared_key: Some(Trusted::new(&shared_key)),
|
|
ciphertext:encapsulated_bits.ciphertext,
|
|
};
|
|
|
|
// Step 17. Queue a global task on the crypto task source, given realm's global
|
|
// object, to perform the remaining steps.
|
|
// Step 18. Let result be the result of converting encapsulatedKey to an ECMAScript
|
|
// Object in realm, as defined by [WebIDL].
|
|
// Step 19. Resolve promise with result.
|
|
subtle.resolve_promise_with_encapsulated_key(promise, encapsulated_key);
|
|
})
|
|
);
|
|
promise
|
|
}
|
|
|
|
/// <https://wicg.github.io/webcrypto-modern-algos/#SubtleCrypto-method-encapsulateBits>
|
|
fn EncapsulateBits(
|
|
&self,
|
|
cx: &mut CurrentRealm,
|
|
encapsulation_algorithm: AlgorithmIdentifier,
|
|
encapsulation_key: &CryptoKey,
|
|
) -> Rc<Promise> {
|
|
// Step 1. Let encapsulationAlgorithm and encapsulationKey be the encapsulationAlgorithm
|
|
// and encapsulationKey parameters passed to the encapsulateBits() method, respectively.
|
|
|
|
// Step 2. Let normalizedEncapsulationAlgorithm be the result of normalizing an algorithm,
|
|
// with alg set to encapsulationAlgorithm and op set to "encapsulate".
|
|
// Step 3. If an error occurred, return a Promise rejected with
|
|
// normalizedEncapsulationAlgorithm.
|
|
let promise = Promise::new_in_realm(cx);
|
|
let normalized_encapsulation_algorithm =
|
|
match normalize_algorithm::<EncapsulateOperation>(cx, &encapsulation_algorithm) {
|
|
Ok(algorithm) => algorithm,
|
|
Err(error) => {
|
|
promise.reject_error(error, CanGc::from_cx(cx));
|
|
return promise;
|
|
},
|
|
};
|
|
|
|
// Step 4. Let realm be the relevant realm of this.
|
|
// Step 5. Let promise be a new Promise.
|
|
// NOTE: We did that in preparation of Step 3.
|
|
|
|
// Step 6. Return promise and perform the remaining steps in parallel.
|
|
let trusted_subtle = Trusted::new(self);
|
|
let trusted_encapsulation_key = Trusted::new(encapsulation_key);
|
|
let trusted_promise = TrustedPromise::new(promise.clone());
|
|
self.global().task_manager().dom_manipulation_task_source().queue(
|
|
task!(derive_key: move || {
|
|
let subtle = trusted_subtle.root();
|
|
let encapsulation_key = trusted_encapsulation_key.root();
|
|
let promise = trusted_promise.root();
|
|
|
|
// Step 7. If the following steps or referenced procedures say to throw an error,
|
|
// queue a global task on the crypto task source, given realm's global object, to
|
|
// reject promise with the returned error; and then terminate the algorithm.
|
|
|
|
// Step 8. If the name member of normalizedEncapsulationAlgorithm is not equal to
|
|
// the name attribute of the [[algorithm]] internal slot of encapsulationKey then
|
|
// throw an InvalidAccessError.
|
|
if normalized_encapsulation_algorithm.name() != encapsulation_key.algorithm().name() {
|
|
subtle.reject_promise_with_error(promise, Error::InvalidAccess(Some(
|
|
"[[algorithm]] internal slot of encapsulationKey is not equal to \
|
|
normalizedEncapsulationAlgorithm".to_string(),
|
|
)));
|
|
return;
|
|
}
|
|
|
|
// Step 9. If the [[usages]] internal slot of encapsulationKey does not contain an
|
|
// entry that is "encapsulateBits", then throw an InvalidAccessError.
|
|
if !encapsulation_key.usages().contains(&KeyUsage::EncapsulateBits) {
|
|
subtle.reject_promise_with_error(promise, Error::InvalidAccess(Some(
|
|
"[[usages]] internal slot of encapsulationKey does not contain an \
|
|
entry that is \"encapsulateBits\"".to_string(),
|
|
)));
|
|
return;
|
|
}
|
|
|
|
// Step 10. Let encapsulatedBits be the result of performing the encapsulate
|
|
// operation specified by the [[algorithm]] internal slot of encapsulationKey using
|
|
// encapsulationKey.
|
|
// NOTE: Step 8 guarantees normalizedEncapsulationAlgorithm specifies the same
|
|
// algorithm as the [[algorithm]] internal slot of encapsulationKey.
|
|
let encapsulated_bits =
|
|
match normalized_encapsulation_algorithm.encapsulate(&encapsulation_key) {
|
|
Ok(encapsulated_bits) => encapsulated_bits,
|
|
Err(error) => {
|
|
subtle.reject_promise_with_error(promise, error);
|
|
return;
|
|
},
|
|
};
|
|
|
|
// Step 11. Queue a global task on the crypto task source, given realm's global
|
|
// object, to perform the remaining steps.
|
|
// Step 12. Let result be the result of converting encapsulatedBits to an
|
|
// ECMAScript Object in realm, as defined by [WebIDL].
|
|
// Step 13. Resolve promise with result.
|
|
subtle.resolve_promise_with_encapsulated_bits(promise, encapsulated_bits);
|
|
}),
|
|
);
|
|
promise
|
|
}
|
|
|
|
/// <https://wicg.github.io/webcrypto-modern-algos/#SubtleCrypto-method-decapsulateKey>
|
|
fn DecapsulateKey(
|
|
&self,
|
|
cx: &mut CurrentRealm,
|
|
decapsulation_algorithm: AlgorithmIdentifier,
|
|
decapsulation_key: &CryptoKey,
|
|
ciphertext: ArrayBufferViewOrArrayBuffer,
|
|
shared_key_algorithm: AlgorithmIdentifier,
|
|
extractable: bool,
|
|
usages: Vec<KeyUsage>,
|
|
) -> Rc<Promise> {
|
|
// Step 1. Let decapsulationAlgorithm, decapsulationKey, sharedKeyAlgorithm, extractable
|
|
// and usages be the decapsulationAlgorithm, decapsulationKey, sharedKeyAlgorithm,
|
|
// extractable and keyUsages parameters passed to the decapsulateKey() method,
|
|
// respectively.
|
|
|
|
// Step 2. Let normalizedDecapsulationAlgorithm be the result of normalizing an algorithm,
|
|
// with alg set to decapsulationAlgorithm and op set to "decapsulate".
|
|
// Step 3. If an error occurred, return a Promise rejected with
|
|
// normalizedDecapsulationAlgorithm.
|
|
let normalized_decapsulation_algorithm =
|
|
match normalize_algorithm::<DecapsulateOperation>(cx, &decapsulation_algorithm) {
|
|
Ok(normalized_algorithm) => normalized_algorithm,
|
|
Err(error) => {
|
|
let promise = Promise::new_in_realm(cx);
|
|
promise.reject_error(error, CanGc::from_cx(cx));
|
|
return promise;
|
|
},
|
|
};
|
|
|
|
// Step 4. Let normalizedSharedKeyAlgorithm be the result of normalizing an algorithm, with
|
|
// alg set to sharedKeyAlgorithm and op set to "importKey".
|
|
// Step 5. If an error occurred, return a Promise rejected with
|
|
// normalizedSharedKeyAlgorithm.
|
|
let normalized_shared_key_algorithm =
|
|
match normalize_algorithm::<ImportKeyOperation>(cx, &shared_key_algorithm) {
|
|
Ok(normalized_algorithm) => normalized_algorithm,
|
|
Err(error) => {
|
|
let promise = Promise::new_in_realm(cx);
|
|
promise.reject_error(error, CanGc::from_cx(cx));
|
|
return promise;
|
|
},
|
|
};
|
|
|
|
// Step 6. Let ciphertext be the result of getting a copy of the bytes held by the
|
|
// ciphertext parameter passed to the decapsulateKey() method.
|
|
let ciphertext = match ciphertext {
|
|
ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
|
|
ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
|
|
};
|
|
|
|
// Step 7. Let realm be the relevant realm of this.
|
|
// Step 8. Let promise be a new Promise.
|
|
let promise = Promise::new_in_realm(cx);
|
|
|
|
// Step 9. Return promise and perform the remaining steps in parallel.
|
|
let trusted_subtle = Trusted::new(self);
|
|
let trusted_decapsulation_key = Trusted::new(decapsulation_key);
|
|
let trusted_promise = TrustedPromise::new(promise.clone());
|
|
self.global()
|
|
.task_manager()
|
|
.dom_manipulation_task_source()
|
|
.queue(task!(decapsulate_key: move |cx| {
|
|
let subtle = trusted_subtle.root();
|
|
let promise = trusted_promise.root();
|
|
let decapsulation_key = trusted_decapsulation_key.root();
|
|
|
|
// Step 10. If the following steps or referenced procedures say to throw an error,
|
|
// queue a global task on the crypto task source, given realm's global object, to
|
|
// reject promise with the returned error; and then terminate the algorithm.
|
|
|
|
// Step 11. If the name member of normalizedDecapsulationAlgorithm is not equal to
|
|
// the name attribute of the [[algorithm]] internal slot of decapsulationKey then
|
|
// throw an InvalidAccessError.
|
|
if normalized_decapsulation_algorithm.name() != decapsulation_key.algorithm().name() {
|
|
subtle.reject_promise_with_error(promise, Error::InvalidAccess(Some(
|
|
"[[algorithm]] internal slot of decapsulationKey is not equal to \
|
|
normalizedDecapsulationAlgorithm".to_string()
|
|
)));
|
|
return;
|
|
}
|
|
|
|
// Step 12. If the [[usages]] internal slot of decapsulationKey does not contain an
|
|
// entry that is "decapsulateKey", then throw an InvalidAccessError.
|
|
if !decapsulation_key.usages().contains(&KeyUsage::DecapsulateKey) {
|
|
subtle.reject_promise_with_error(promise, Error::InvalidAccess(Some(
|
|
"[[usages]] internal slot of decapsulationKey does not contain an \
|
|
entry that is \"decapsulateBits\"".to_string(),
|
|
)));
|
|
return;
|
|
}
|
|
|
|
// Step 13. Let decapsulatedBits be the result of performing the decapsulate
|
|
// operation specified by the [[algorithm]] internal slot of decapsulationKey using
|
|
// decapsulationKey and ciphertext.
|
|
// NOTE: Step 11 guarantees normalizedDecapsulationAlgorithm specifies the same
|
|
// algorithm as the [[algorithm]] internal slot of decapsulationKey.
|
|
let decapsulated_bits_result =
|
|
normalized_decapsulation_algorithm.decapsulate(&decapsulation_key, &ciphertext);
|
|
let decapsulated_bits = match decapsulated_bits_result {
|
|
Ok(decapsulated_bits) => decapsulated_bits,
|
|
Err(error) => {
|
|
subtle.reject_promise_with_error(promise, error);
|
|
return;
|
|
},
|
|
};
|
|
|
|
|
|
// Step 14. Let sharedKey be the result of performing the import key operation
|
|
// specified by normalizedSharedKeyAlgorithm using "raw-secret" as format, the
|
|
// decapsulatedBits as keyData, sharedKeyAlgorithm as algorithm and using
|
|
// extractable and usages.
|
|
// Step 15. Set the [[extractable]] internal slot of sharedKey to extractable.
|
|
// Step 16. Set the [[usages]] internal slot of sharedKey to the normalized value
|
|
// of usages.
|
|
let shared_key_result = normalized_shared_key_algorithm.import_key(
|
|
cx,
|
|
&subtle.global(),
|
|
KeyFormat::Raw_secret,
|
|
&decapsulated_bits,
|
|
extractable,
|
|
usages.clone(),
|
|
);
|
|
let shared_key = match shared_key_result {
|
|
Ok(shared_key) => shared_key,
|
|
Err(error) => {
|
|
subtle.reject_promise_with_error(promise, error);
|
|
return;
|
|
},
|
|
};
|
|
|
|
|
|
// Step 17. Queue a global task on the crypto task source, given realm's global
|
|
// object, to perform the remaining steps.
|
|
// Step 18. Let result be the result of converting sharedKey to an ECMAScript
|
|
// Object in realm, as defined by [WebIDL].
|
|
// Step 19. Resolve promise with result.
|
|
subtle.resolve_promise_with_key(promise, shared_key);
|
|
}));
|
|
promise
|
|
}
|
|
|
|
/// <https://wicg.github.io/webcrypto-modern-algos/#SubtleCrypto-method-decapsulateBits>
|
|
fn DecapsulateBits(
|
|
&self,
|
|
cx: &mut CurrentRealm,
|
|
decapsulation_algorithm: AlgorithmIdentifier,
|
|
decapsulation_key: &CryptoKey,
|
|
ciphertext: ArrayBufferViewOrArrayBuffer,
|
|
) -> Rc<Promise> {
|
|
// Step 1. Let decapsulationAlgorithm and decapsulationKey be the decapsulationAlgorithm
|
|
// and decapsulationKey parameters passed to the decapsulateBits() method, respectively.
|
|
|
|
// Step 2. Let normalizedDecapsulationAlgorithm be the result of normalizing an algorithm,
|
|
// with alg set to decapsulationAlgorithm and op set to "decapsulate".
|
|
// Step 3. If an error occurred, return a Promise rejected with
|
|
// normalizedDecapsulationAlgorithm.
|
|
let normalized_decapsulation_algorithm =
|
|
match normalize_algorithm::<DecapsulateOperation>(cx, &decapsulation_algorithm) {
|
|
Ok(normalized_algorithm) => normalized_algorithm,
|
|
Err(error) => {
|
|
let promise = Promise::new_in_realm(cx);
|
|
promise.reject_error(error, CanGc::from_cx(cx));
|
|
return promise;
|
|
},
|
|
};
|
|
|
|
// Step 4. Let ciphertext be the result of getting a copy of the bytes held by the
|
|
// ciphertext parameter passed to the decapsulateBits() method.
|
|
let ciphertext = match ciphertext {
|
|
ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
|
|
ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
|
|
};
|
|
|
|
// Step 5. Let realm be the relevant realm of this.
|
|
// Step 6. Let promise be a new Promise.
|
|
let promise = Promise::new_in_realm(cx);
|
|
|
|
// Step 7. Return promise and perform the remaining steps in parallel.
|
|
let trusted_subtle = Trusted::new(self);
|
|
let trusted_decapsulation_key = Trusted::new(decapsulation_key);
|
|
let trusted_promise = TrustedPromise::new(promise.clone());
|
|
self.global()
|
|
.task_manager()
|
|
.dom_manipulation_task_source()
|
|
.queue(task!(decapsulate_bits: move || {
|
|
let subtle = trusted_subtle.root();
|
|
let promise = trusted_promise.root();
|
|
let decapsulation_key = trusted_decapsulation_key.root();
|
|
|
|
// Step 8. If the following steps or referenced procedures say to throw an error,
|
|
// queue a global task on the crypto task source, given realm's global object, to
|
|
// reject promise with the returned error; and then terminate the algorithm.
|
|
|
|
// Step 9. If the name member of normalizedDecapsulationAlgorithm is not equal to
|
|
// the name attribute of the [[algorithm]] internal slot of decapsulationKey then
|
|
// throw an InvalidAccessError.
|
|
if normalized_decapsulation_algorithm.name() != decapsulation_key.algorithm().name() {
|
|
subtle.reject_promise_with_error(promise, Error::InvalidAccess(Some(
|
|
"[[algorithm]] internal slot of decapsulationKey is not equal to \
|
|
normalizedDecapsulationAlgorithm".to_string()
|
|
)));
|
|
return;
|
|
}
|
|
|
|
// Step 10. If the [[usages]] internal slot of decapsulationKey does not contain an
|
|
// entry that is "decapsulateBits", then throw an InvalidAccessError.
|
|
if !decapsulation_key.usages().contains(&KeyUsage::DecapsulateBits) {
|
|
subtle.reject_promise_with_error(promise, Error::InvalidAccess(Some(
|
|
"[[usages]] internal slot of decapsulationKey does not contain an \
|
|
entry that is \"decapsulateBits\"".to_string(),
|
|
)));
|
|
return;
|
|
}
|
|
|
|
// Step 11. Let decapsulatedBits be the result of performing the decapsulate
|
|
// operation specified by the [[algorithm]] internal slot of decapsulationKey using
|
|
// decapsulationKey and ciphertext.
|
|
// NOTE: Step 9 guarantees normalizedDecapsulationAlgorithm specifies the same
|
|
// algorithm as the [[algorithm]] internal slot of decapsulationKey.
|
|
let decapsulated_bits_result =
|
|
normalized_decapsulation_algorithm.decapsulate(&decapsulation_key, &ciphertext);
|
|
let decapsulated_bits = match decapsulated_bits_result {
|
|
Ok(decapsulated_bits) => decapsulated_bits,
|
|
Err(error) => {
|
|
subtle.reject_promise_with_error(promise, error);
|
|
return;
|
|
},
|
|
};
|
|
|
|
// Step 12. Queue a global task on the crypto task source, given realm's global
|
|
// object, to perform the remaining steps.
|
|
// Step 13. Let result be the result of creating an ArrayBuffer in realm,
|
|
// containing decapsulatedBits.
|
|
// Step 14. Resolve promise with result.
|
|
subtle.resolve_promise_with_data(promise, decapsulated_bits);
|
|
}));
|
|
promise
|
|
}
|
|
|
|
/// <https://wicg.github.io/webcrypto-modern-algos/#SubtleCrypto-method-getPublicKey>
|
|
fn GetPublicKey(
|
|
&self,
|
|
cx: &mut CurrentRealm,
|
|
key: &CryptoKey,
|
|
usages: Vec<KeyUsage>,
|
|
) -> Rc<Promise> {
|
|
// Step 1. Let key and usages be the key and keyUsages parameters passed to the
|
|
// getPublicKey() method, respectively.
|
|
|
|
// Step 2. Let algorithm be the [[algorithm]] internal slot of key.
|
|
let algorithm = key.algorithm();
|
|
|
|
// Step 3. If the cryptographic algorithm identified by algorithm does not support deriving
|
|
// a public key from a private key, then return a Promise rejected with a
|
|
// NotSupportedError.
|
|
//
|
|
// NOTE: We rely on [`normalize_algorithm`] to check whether the algorithm supports the
|
|
// getPublicKey operation.
|
|
let get_public_key_algorithm = match normalize_algorithm::<GetPublicKeyOperation>(
|
|
cx,
|
|
&AlgorithmIdentifier::String(DOMString::from(algorithm.name().as_str())),
|
|
) {
|
|
Ok(normalized_algorithm) => normalized_algorithm,
|
|
Err(error) => {
|
|
let promise = Promise::new_in_realm(cx);
|
|
promise.reject_error(error, CanGc::from_cx(cx));
|
|
return promise;
|
|
},
|
|
};
|
|
|
|
// Step 4. Let realm be the relevant realm of this.
|
|
// Step 5. Let promise be a new Promise.
|
|
let promise = Promise::new_in_realm(cx);
|
|
|
|
// Step 6. Return promise and perform the remaining steps in parallel.
|
|
let trusted_subtle = Trusted::new(self);
|
|
let trusted_promise = TrustedPromise::new(promise.clone());
|
|
let trusted_key = Trusted::new(key);
|
|
self.global()
|
|
.task_manager()
|
|
.dom_manipulation_task_source()
|
|
.queue(task!(get_public_key: move |cx| {
|
|
let subtle = trusted_subtle.root();
|
|
let promise = trusted_promise.root();
|
|
let key = trusted_key.root();
|
|
|
|
// Step 7. If the following steps or referenced procedures say to throw an error,
|
|
// queue a global task on the crypto task source, given realm's global object, to
|
|
// reject promise with the returned error; and then terminate the algorithm.
|
|
|
|
// Step 8. If the [[type]] internal slot of key is not "private", then throw an
|
|
// InvalidAccessError.
|
|
if key.Type() != KeyType::Private {
|
|
subtle.reject_promise_with_error(promise, Error::InvalidAccess(Some(
|
|
"[[type]] internal slot of key is not \"private\"".to_string()
|
|
)));
|
|
return;
|
|
}
|
|
|
|
// Step 9. If usages contains an entry which is not supported for a public key by
|
|
// the algorithm identified by algorithm, then throw a SyntaxError.
|
|
// Step 10. Let publicKey be a new CryptoKey representing the public key
|
|
// corresponding to the private key represented by the [[handle]] internal slot of
|
|
// key.
|
|
// Step 11. If an error occurred, then throw a OperationError.
|
|
// Step 12. Set the [[type]] internal slot of publicKey to "public".
|
|
// Step 13. Set the [[algorithm]] internal slot of publicKey to algorithm.
|
|
// Step 14. Set the [[extractable]] internal slot of publicKey to true.
|
|
// Step 15. Set the [[usages]] internal slot of publicKey to usages.
|
|
//
|
|
// NOTE: We run these steps in the "getPublicKey" operations of the supported
|
|
// cryptographic algorithms.
|
|
let result = match get_public_key_algorithm.get_public_key(
|
|
cx,
|
|
&subtle.global(),
|
|
&key,
|
|
key.algorithm(),
|
|
usages.clone(),
|
|
) {
|
|
Ok(public_key) => public_key,
|
|
Err(error) => {
|
|
subtle.reject_promise_with_error(promise, error);
|
|
return;
|
|
},
|
|
};
|
|
|
|
// Step 16. Queue a global task on the crypto task source, given realm's global
|
|
// object, to perform the remaining steps.
|
|
// Step 17. Let result be the result of converting publicKey to an ECMAScript
|
|
// Object in realm, as defined by [WebIDL].
|
|
// Step 18. Resolve promise with result.
|
|
subtle.resolve_promise_with_key(promise, result);
|
|
}));
|
|
promise
|
|
}
|
|
}
|
|
|
|
/// Alternative to std::convert::TryFrom, with `&mut js::context::JSContext`
|
|
trait TryFromWithCx<T>: Sized {
|
|
type Error;
|
|
|
|
fn try_from_with_cx(value: T, cx: &mut js::context::JSContext) -> Result<Self, Self::Error>;
|
|
}
|
|
|
|
/// Alternative to std::convert::TryInto, with `&mut js::context::JSContext`
|
|
trait TryIntoWithCx<T>: Sized {
|
|
type Error;
|
|
|
|
fn try_into_with_cx(self, cx: &mut js::context::JSContext) -> Result<T, Self::Error>;
|
|
}
|
|
|
|
impl<T, U> TryIntoWithCx<U> for T
|
|
where
|
|
U: TryFromWithCx<T>,
|
|
{
|
|
type Error = U::Error;
|
|
|
|
fn try_into_with_cx(self, cx: &mut js::context::JSContext) -> Result<U, Self::Error> {
|
|
U::try_from_with_cx(self, cx)
|
|
}
|
|
}
|
|
|
|
// These "subtle" structs are proxies for the codegen'd dicts which don't hold a DOMString
|
|
// so they can be sent safely when running steps in parallel.
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-Algorithm>
|
|
#[derive(Clone, MallocSizeOf)]
|
|
struct SubtleAlgorithm {
|
|
/// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
|
|
name: CryptoAlgorithm,
|
|
}
|
|
|
|
impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleAlgorithm {
|
|
type Error = Error;
|
|
|
|
fn try_from_with_cx(
|
|
value: HandleValue<'a>,
|
|
cx: &mut js::context::JSContext,
|
|
) -> Result<Self, Self::Error> {
|
|
let dictionary = dictionary_from_jsval::<Algorithm>(cx, value)?;
|
|
|
|
Ok(SubtleAlgorithm {
|
|
name: CryptoAlgorithm::from_domstring(&dictionary.name)?,
|
|
})
|
|
}
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-KeyAlgorithm>
|
|
#[derive(Clone, MallocSizeOf)]
|
|
pub(crate) struct SubtleKeyAlgorithm {
|
|
/// <https://w3c.github.io/webcrypto/#dom-keyalgorithm-name>
|
|
name: CryptoAlgorithm,
|
|
}
|
|
|
|
impl SafeToJSValConvertible for SubtleKeyAlgorithm {
|
|
fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
|
|
let dictionary = KeyAlgorithm {
|
|
name: self.name.as_str().into(),
|
|
};
|
|
dictionary.safe_to_jsval(cx, rval, can_gc);
|
|
}
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-RsaHashedKeyGenParams>
|
|
#[derive(Clone, MallocSizeOf)]
|
|
pub(crate) struct SubtleRsaHashedKeyGenParams {
|
|
/// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
|
|
name: CryptoAlgorithm,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-RsaKeyGenParams-modulusLength>
|
|
modulus_length: u32,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-RsaKeyGenParams-publicExponent>
|
|
public_exponent: Vec<u8>,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-RsaHashedKeyGenParams-hash>
|
|
hash: DigestAlgorithm,
|
|
}
|
|
|
|
impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleRsaHashedKeyGenParams {
|
|
type Error = Error;
|
|
|
|
fn try_from_with_cx(
|
|
value: HandleValue,
|
|
cx: &mut js::context::JSContext,
|
|
) -> Result<Self, Self::Error> {
|
|
let dictionary =
|
|
dictionary_from_jsval::<RootedTraceableBox<RsaHashedKeyGenParams>>(cx, value)?;
|
|
|
|
Ok(SubtleRsaHashedKeyGenParams {
|
|
name: CryptoAlgorithm::from_domstring(&dictionary.parent.parent.name)?,
|
|
modulus_length: dictionary.parent.modulusLength,
|
|
public_exponent: dictionary.parent.publicExponent.to_vec(),
|
|
hash: normalize_algorithm::<DigestOperation>(cx, &dictionary.hash)?,
|
|
})
|
|
}
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-RsaHashedKeyAlgorithm>
|
|
#[derive(Clone, MallocSizeOf)]
|
|
pub(crate) struct SubtleRsaHashedKeyAlgorithm {
|
|
/// <https://w3c.github.io/webcrypto/#dom-keyalgorithm-name>
|
|
name: CryptoAlgorithm,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-RsaKeyAlgorithm-modulusLength>
|
|
modulus_length: u32,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-RsaKeyAlgorithm-publicExponent>
|
|
public_exponent: Vec<u8>,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-RsaHashedKeyAlgorithm-hash>
|
|
hash: DigestAlgorithm,
|
|
}
|
|
|
|
impl SafeToJSValConvertible for SubtleRsaHashedKeyAlgorithm {
|
|
fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
|
|
rooted!(in(*cx) let mut js_object = ptr::null_mut::<JSObject>());
|
|
let public_exponent =
|
|
create_buffer_source(cx, &self.public_exponent, js_object.handle_mut(), can_gc)
|
|
.expect("Fail to convert publicExponent to Uint8Array");
|
|
let key_algorithm = KeyAlgorithm {
|
|
name: self.name.as_str().into(),
|
|
};
|
|
let rsa_key_algorithm = RootedTraceableBox::new(RsaKeyAlgorithm {
|
|
parent: key_algorithm,
|
|
modulusLength: self.modulus_length,
|
|
publicExponent: public_exponent,
|
|
});
|
|
let rsa_hashed_key_algorithm = RootedTraceableBox::new(RsaHashedKeyAlgorithm {
|
|
parent: rsa_key_algorithm,
|
|
hash: KeyAlgorithm {
|
|
name: self.hash.name().as_str().into(),
|
|
},
|
|
});
|
|
rsa_hashed_key_algorithm.safe_to_jsval(cx, rval, can_gc);
|
|
}
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-RsaHashedImportParams>
|
|
#[derive(Clone, MallocSizeOf)]
|
|
struct SubtleRsaHashedImportParams {
|
|
/// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
|
|
name: CryptoAlgorithm,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-RsaHashedImportParams-hash>
|
|
hash: DigestAlgorithm,
|
|
}
|
|
|
|
impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleRsaHashedImportParams {
|
|
type Error = Error;
|
|
|
|
fn try_from_with_cx(
|
|
value: HandleValue,
|
|
cx: &mut js::context::JSContext,
|
|
) -> Result<Self, Self::Error> {
|
|
let dictionary =
|
|
dictionary_from_jsval::<RootedTraceableBox<RsaHashedImportParams>>(cx, value)?;
|
|
|
|
Ok(SubtleRsaHashedImportParams {
|
|
name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
|
|
hash: normalize_algorithm::<DigestOperation>(cx, &dictionary.hash)?,
|
|
})
|
|
}
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-RsaPssParams>
|
|
#[derive(Clone, MallocSizeOf)]
|
|
struct SubtleRsaPssParams {
|
|
/// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
|
|
name: CryptoAlgorithm,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-RsaPssParams-saltLength>
|
|
salt_length: u32,
|
|
}
|
|
|
|
impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleRsaPssParams {
|
|
type Error = Error;
|
|
|
|
fn try_from_with_cx(
|
|
value: HandleValue,
|
|
cx: &mut js::context::JSContext,
|
|
) -> Result<Self, Self::Error> {
|
|
let dictionary = dictionary_from_jsval::<RsaPssParams>(cx, value)?;
|
|
|
|
Ok(SubtleRsaPssParams {
|
|
name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
|
|
salt_length: dictionary.saltLength,
|
|
})
|
|
}
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-RsaOaepParams>
|
|
#[derive(Clone, MallocSizeOf)]
|
|
struct SubtleRsaOaepParams {
|
|
/// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
|
|
name: CryptoAlgorithm,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-RsaOaepParams-label>
|
|
label: Option<Vec<u8>>,
|
|
}
|
|
|
|
impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleRsaOaepParams {
|
|
type Error = Error;
|
|
|
|
fn try_from_with_cx(
|
|
value: HandleValue<'a>,
|
|
cx: &mut js::context::JSContext,
|
|
) -> Result<Self, Self::Error> {
|
|
let dictionary = dictionary_from_jsval::<RootedTraceableBox<RsaOaepParams>>(cx, value)?;
|
|
|
|
let label = dictionary.label.as_ref().map(|label| match label {
|
|
ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
|
|
ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
|
|
});
|
|
|
|
Ok(SubtleRsaOaepParams {
|
|
name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
|
|
label,
|
|
})
|
|
}
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-EcdsaParams>
|
|
#[derive(Clone, MallocSizeOf)]
|
|
struct SubtleEcdsaParams {
|
|
/// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
|
|
name: CryptoAlgorithm,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-EcdsaParams-hash>
|
|
hash: DigestAlgorithm,
|
|
}
|
|
|
|
impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleEcdsaParams {
|
|
type Error = Error;
|
|
|
|
fn try_from_with_cx(
|
|
value: HandleValue<'a>,
|
|
cx: &mut js::context::JSContext,
|
|
) -> Result<Self, Self::Error> {
|
|
let dictionary = dictionary_from_jsval::<RootedTraceableBox<EcdsaParams>>(cx, value)?;
|
|
|
|
Ok(SubtleEcdsaParams {
|
|
name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
|
|
hash: normalize_algorithm::<DigestOperation>(cx, &dictionary.hash)?,
|
|
})
|
|
}
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-EcKeyGenParams>
|
|
#[derive(Clone, MallocSizeOf)]
|
|
struct SubtleEcKeyGenParams {
|
|
/// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
|
|
name: CryptoAlgorithm,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-EcKeyGenParams-namedCurve>
|
|
named_curve: String,
|
|
}
|
|
|
|
impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleEcKeyGenParams {
|
|
type Error = Error;
|
|
|
|
fn try_from_with_cx(
|
|
value: HandleValue<'a>,
|
|
cx: &mut js::context::JSContext,
|
|
) -> Result<Self, Self::Error> {
|
|
let dictionary = dictionary_from_jsval::<EcKeyGenParams>(cx, value)?;
|
|
|
|
Ok(SubtleEcKeyGenParams {
|
|
name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
|
|
named_curve: dictionary.namedCurve.to_string(),
|
|
})
|
|
}
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-EcKeyAlgorithm>
|
|
#[derive(Clone, MallocSizeOf)]
|
|
pub(crate) struct SubtleEcKeyAlgorithm {
|
|
/// <https://w3c.github.io/webcrypto/#dom-keyalgorithm-name>
|
|
name: CryptoAlgorithm,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-EcKeyAlgorithm-namedCurve>
|
|
named_curve: String,
|
|
}
|
|
|
|
impl SafeToJSValConvertible for SubtleEcKeyAlgorithm {
|
|
fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
|
|
let parent = KeyAlgorithm {
|
|
name: self.name.as_str().into(),
|
|
};
|
|
let dictionary = EcKeyAlgorithm {
|
|
parent,
|
|
namedCurve: self.named_curve.clone().into(),
|
|
};
|
|
dictionary.safe_to_jsval(cx, rval, can_gc);
|
|
}
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-EcKeyImportParams>
|
|
#[derive(Clone, MallocSizeOf)]
|
|
struct SubtleEcKeyImportParams {
|
|
/// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
|
|
name: CryptoAlgorithm,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-EcKeyImportParams-namedCurve>
|
|
named_curve: String,
|
|
}
|
|
|
|
impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleEcKeyImportParams {
|
|
type Error = Error;
|
|
|
|
fn try_from_with_cx(
|
|
value: HandleValue<'a>,
|
|
cx: &mut js::context::JSContext,
|
|
) -> Result<Self, Self::Error> {
|
|
let dictionary = dictionary_from_jsval::<EcKeyImportParams>(cx, value)?;
|
|
|
|
Ok(SubtleEcKeyImportParams {
|
|
name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
|
|
named_curve: dictionary.namedCurve.to_string(),
|
|
})
|
|
}
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-EcdhKeyDeriveParams>
|
|
#[derive(Clone, MallocSizeOf)]
|
|
struct SubtleEcdhKeyDeriveParams {
|
|
/// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
|
|
name: CryptoAlgorithm,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-EcdhKeyDeriveParams-public>
|
|
public: Trusted<CryptoKey>,
|
|
}
|
|
|
|
impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleEcdhKeyDeriveParams {
|
|
type Error = Error;
|
|
|
|
fn try_from_with_cx(
|
|
value: HandleValue<'a>,
|
|
cx: &mut js::context::JSContext,
|
|
) -> Result<Self, Self::Error> {
|
|
let dictionary = dictionary_from_jsval::<EcdhKeyDeriveParams>(cx, value)?;
|
|
|
|
Ok(SubtleEcdhKeyDeriveParams {
|
|
name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
|
|
public: Trusted::new(&dictionary.public),
|
|
})
|
|
}
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-AesCtrParams>
|
|
#[derive(Clone, MallocSizeOf)]
|
|
struct SubtleAesCtrParams {
|
|
/// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
|
|
name: CryptoAlgorithm,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-AesCtrParams-counter>
|
|
counter: Vec<u8>,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-AesCtrParams-length>
|
|
length: u8,
|
|
}
|
|
|
|
impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleAesCtrParams {
|
|
type Error = Error;
|
|
|
|
fn try_from_with_cx(
|
|
value: HandleValue<'a>,
|
|
cx: &mut js::context::JSContext,
|
|
) -> Result<Self, Self::Error> {
|
|
let dictionary = dictionary_from_jsval::<RootedTraceableBox<AesCtrParams>>(cx, value)?;
|
|
|
|
let counter = match &dictionary.counter {
|
|
ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
|
|
ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
|
|
};
|
|
|
|
Ok(SubtleAesCtrParams {
|
|
name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
|
|
counter,
|
|
length: dictionary.length,
|
|
})
|
|
}
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-AesKeyAlgorithm>
|
|
#[derive(Clone, MallocSizeOf)]
|
|
pub(crate) struct SubtleAesKeyAlgorithm {
|
|
/// <https://w3c.github.io/webcrypto/#dom-keyalgorithm-name>
|
|
name: CryptoAlgorithm,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-AesKeyAlgorithm-length>
|
|
length: u16,
|
|
}
|
|
|
|
impl SafeToJSValConvertible for SubtleAesKeyAlgorithm {
|
|
fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
|
|
let parent = KeyAlgorithm {
|
|
name: self.name.as_str().into(),
|
|
};
|
|
let dictionary = AesKeyAlgorithm {
|
|
parent,
|
|
length: self.length,
|
|
};
|
|
dictionary.safe_to_jsval(cx, rval, can_gc);
|
|
}
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-AesKeyGenParams>
|
|
#[derive(Clone, MallocSizeOf)]
|
|
struct SubtleAesKeyGenParams {
|
|
/// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
|
|
name: CryptoAlgorithm,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-AesKeyGenParams-length>
|
|
length: u16,
|
|
}
|
|
|
|
impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleAesKeyGenParams {
|
|
type Error = Error;
|
|
|
|
fn try_from_with_cx(
|
|
value: HandleValue<'a>,
|
|
cx: &mut js::context::JSContext,
|
|
) -> Result<Self, Self::Error> {
|
|
let dictionary = dictionary_from_jsval::<AesKeyGenParams>(cx, value)?;
|
|
|
|
Ok(SubtleAesKeyGenParams {
|
|
name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
|
|
length: dictionary.length,
|
|
})
|
|
}
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-AesDerivedKeyParams>
|
|
#[derive(Clone, MallocSizeOf)]
|
|
struct SubtleAesDerivedKeyParams {
|
|
/// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
|
|
name: CryptoAlgorithm,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-AesDerivedKeyParams-length>
|
|
length: u16,
|
|
}
|
|
|
|
impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleAesDerivedKeyParams {
|
|
type Error = Error;
|
|
|
|
fn try_from_with_cx(
|
|
value: HandleValue<'a>,
|
|
cx: &mut js::context::JSContext,
|
|
) -> Result<Self, Self::Error> {
|
|
let dictionary = dictionary_from_jsval::<AesDerivedKeyParams>(cx, value)?;
|
|
|
|
Ok(SubtleAesDerivedKeyParams {
|
|
name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
|
|
length: dictionary.length,
|
|
})
|
|
}
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-AesCbcParams>
|
|
#[derive(Clone, MallocSizeOf)]
|
|
struct SubtleAesCbcParams {
|
|
/// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
|
|
name: CryptoAlgorithm,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-AesCbcParams-iv>
|
|
iv: Vec<u8>,
|
|
}
|
|
|
|
impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleAesCbcParams {
|
|
type Error = Error;
|
|
|
|
fn try_from_with_cx(
|
|
value: HandleValue<'a>,
|
|
cx: &mut js::context::JSContext,
|
|
) -> Result<Self, Self::Error> {
|
|
let dictionary = dictionary_from_jsval::<RootedTraceableBox<AesCbcParams>>(cx, value)?;
|
|
|
|
let iv = match &dictionary.iv {
|
|
ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
|
|
ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
|
|
};
|
|
|
|
Ok(SubtleAesCbcParams {
|
|
name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
|
|
iv,
|
|
})
|
|
}
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-AesGcmParams>
|
|
#[derive(Clone, MallocSizeOf)]
|
|
struct SubtleAesGcmParams {
|
|
/// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
|
|
name: CryptoAlgorithm,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-AesGcmParams-iv>
|
|
iv: Vec<u8>,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-AesGcmParams-additionalData>
|
|
additional_data: Option<Vec<u8>>,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-AesGcmParams-tagLength>
|
|
tag_length: Option<u8>,
|
|
}
|
|
|
|
impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleAesGcmParams {
|
|
type Error = Error;
|
|
|
|
fn try_from_with_cx(
|
|
value: HandleValue<'a>,
|
|
cx: &mut js::context::JSContext,
|
|
) -> Result<Self, Self::Error> {
|
|
let dictionary = dictionary_from_jsval::<RootedTraceableBox<AesGcmParams>>(cx, value)?;
|
|
|
|
let iv = match &dictionary.iv {
|
|
ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
|
|
ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
|
|
};
|
|
let additional_data = dictionary.additionalData.as_ref().map(|data| match data {
|
|
ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
|
|
ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
|
|
});
|
|
|
|
Ok(SubtleAesGcmParams {
|
|
name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
|
|
iv,
|
|
additional_data,
|
|
tag_length: dictionary.tagLength,
|
|
})
|
|
}
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-HmacImportParams>
|
|
#[derive(Clone, MallocSizeOf)]
|
|
struct SubtleHmacImportParams {
|
|
/// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
|
|
name: CryptoAlgorithm,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-HmacImportParams-hash>
|
|
hash: DigestAlgorithm,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-HmacImportParams-length>
|
|
length: Option<u32>,
|
|
}
|
|
|
|
impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleHmacImportParams {
|
|
type Error = Error;
|
|
|
|
fn try_from_with_cx(
|
|
value: HandleValue<'a>,
|
|
cx: &mut js::context::JSContext,
|
|
) -> Result<Self, Self::Error> {
|
|
let dictionary = dictionary_from_jsval::<RootedTraceableBox<HmacImportParams>>(cx, value)?;
|
|
|
|
Ok(SubtleHmacImportParams {
|
|
name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
|
|
hash: normalize_algorithm::<DigestOperation>(cx, &dictionary.hash)?,
|
|
length: dictionary.length,
|
|
})
|
|
}
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-HmacKeyAlgorithm>
|
|
#[derive(Clone, MallocSizeOf)]
|
|
pub(crate) struct SubtleHmacKeyAlgorithm {
|
|
/// <https://w3c.github.io/webcrypto/#dom-keyalgorithm-name>
|
|
name: CryptoAlgorithm,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-HmacKeyAlgorithm-hash>
|
|
hash: SubtleKeyAlgorithm,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-HmacKeyGenParams-length>
|
|
length: u32,
|
|
}
|
|
|
|
impl SafeToJSValConvertible for SubtleHmacKeyAlgorithm {
|
|
fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
|
|
let parent = KeyAlgorithm {
|
|
name: self.name.as_str().into(),
|
|
};
|
|
let hash = KeyAlgorithm {
|
|
name: self.hash.name.as_str().into(),
|
|
};
|
|
let dictionary = HmacKeyAlgorithm {
|
|
parent,
|
|
hash,
|
|
length: self.length,
|
|
};
|
|
dictionary.safe_to_jsval(cx, rval, can_gc);
|
|
}
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-HmacKeyGenParams>
|
|
#[derive(Clone, MallocSizeOf)]
|
|
struct SubtleHmacKeyGenParams {
|
|
/// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
|
|
name: CryptoAlgorithm,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-HmacKeyGenParams-hash>
|
|
hash: DigestAlgorithm,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-HmacKeyGenParams-length>
|
|
length: Option<u32>,
|
|
}
|
|
|
|
impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleHmacKeyGenParams {
|
|
type Error = Error;
|
|
|
|
fn try_from_with_cx(
|
|
value: HandleValue<'a>,
|
|
cx: &mut js::context::JSContext,
|
|
) -> Result<Self, Self::Error> {
|
|
let dictionary = dictionary_from_jsval::<RootedTraceableBox<HmacKeyGenParams>>(cx, value)?;
|
|
|
|
Ok(SubtleHmacKeyGenParams {
|
|
name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
|
|
hash: normalize_algorithm::<DigestOperation>(cx, &dictionary.hash)?,
|
|
length: dictionary.length,
|
|
})
|
|
}
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-HkdfParams>
|
|
#[derive(Clone, MallocSizeOf)]
|
|
pub(crate) struct SubtleHkdfParams {
|
|
/// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
|
|
name: CryptoAlgorithm,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-HkdfParams-hash>
|
|
hash: DigestAlgorithm,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-HkdfParams-salt>
|
|
salt: Vec<u8>,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-HkdfParams-info>
|
|
info: Vec<u8>,
|
|
}
|
|
|
|
impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleHkdfParams {
|
|
type Error = Error;
|
|
|
|
fn try_from_with_cx(
|
|
value: HandleValue<'a>,
|
|
cx: &mut js::context::JSContext,
|
|
) -> Result<Self, Self::Error> {
|
|
let dictionary = dictionary_from_jsval::<RootedTraceableBox<HkdfParams>>(cx, value)?;
|
|
|
|
let salt = match &dictionary.salt {
|
|
ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
|
|
ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
|
|
};
|
|
let info = match &dictionary.info {
|
|
ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
|
|
ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
|
|
};
|
|
|
|
Ok(SubtleHkdfParams {
|
|
name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
|
|
hash: normalize_algorithm::<DigestOperation>(cx, &dictionary.hash)?,
|
|
salt,
|
|
info,
|
|
})
|
|
}
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-Pbkdf2Params>
|
|
#[derive(Clone, MallocSizeOf)]
|
|
pub(crate) struct SubtlePbkdf2Params {
|
|
/// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
|
|
name: CryptoAlgorithm,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-Pbkdf2Params-salt>
|
|
salt: Vec<u8>,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-Pbkdf2Params-iterations>
|
|
iterations: u32,
|
|
|
|
/// <https://w3c.github.io/webcrypto/#dfn-Pbkdf2Params-hash>
|
|
hash: DigestAlgorithm,
|
|
}
|
|
|
|
impl<'a> TryFromWithCx<HandleValue<'a>> for SubtlePbkdf2Params {
|
|
type Error = Error;
|
|
|
|
fn try_from_with_cx(
|
|
value: HandleValue<'a>,
|
|
cx: &mut js::context::JSContext,
|
|
) -> Result<Self, Self::Error> {
|
|
let dictionary = dictionary_from_jsval::<RootedTraceableBox<Pbkdf2Params>>(cx, value)?;
|
|
|
|
let salt = match &dictionary.salt {
|
|
ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
|
|
ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
|
|
};
|
|
|
|
Ok(SubtlePbkdf2Params {
|
|
name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
|
|
salt,
|
|
iterations: dictionary.iterations,
|
|
hash: normalize_algorithm::<DigestOperation>(cx, &dictionary.hash)?,
|
|
})
|
|
}
|
|
}
|
|
|
|
/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-ContextParams>
|
|
#[derive(Clone, MallocSizeOf)]
|
|
struct SubtleContextParams {
|
|
/// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
|
|
name: CryptoAlgorithm,
|
|
|
|
/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-ContextParams-context>
|
|
context: Option<Vec<u8>>,
|
|
}
|
|
|
|
impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleContextParams {
|
|
type Error = Error;
|
|
|
|
fn try_from_with_cx(
|
|
value: HandleValue<'a>,
|
|
cx: &mut js::context::JSContext,
|
|
) -> Result<Self, Self::Error> {
|
|
let dictionary = dictionary_from_jsval::<RootedTraceableBox<ContextParams>>(cx, value)?;
|
|
|
|
let context = dictionary.context.as_ref().map(|context| match context {
|
|
ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
|
|
ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
|
|
});
|
|
|
|
Ok(SubtleContextParams {
|
|
name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
|
|
context,
|
|
})
|
|
}
|
|
}
|
|
|
|
/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-AeadParams>
|
|
#[derive(Clone, MallocSizeOf)]
|
|
struct SubtleAeadParams {
|
|
/// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
|
|
name: CryptoAlgorithm,
|
|
|
|
/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-AeadParams-iv>
|
|
iv: Vec<u8>,
|
|
|
|
/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-AeadParams-additionalData>
|
|
additional_data: Option<Vec<u8>>,
|
|
|
|
/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-AeadParams-tagLength>
|
|
tag_length: Option<u8>,
|
|
}
|
|
|
|
impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleAeadParams {
|
|
type Error = Error;
|
|
|
|
fn try_from_with_cx(
|
|
value: HandleValue<'a>,
|
|
cx: &mut js::context::JSContext,
|
|
) -> Result<Self, Self::Error> {
|
|
let dictionary = dictionary_from_jsval::<RootedTraceableBox<AeadParams>>(cx, value)?;
|
|
|
|
let iv = match &dictionary.iv {
|
|
ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
|
|
ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
|
|
};
|
|
let additional_data = dictionary.additionalData.as_ref().map(|data| match data {
|
|
ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
|
|
ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
|
|
});
|
|
|
|
Ok(SubtleAeadParams {
|
|
name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
|
|
iv,
|
|
additional_data,
|
|
tag_length: dictionary.tagLength,
|
|
})
|
|
}
|
|
}
|
|
|
|
/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-CShakeParams>
|
|
#[derive(Clone, MallocSizeOf)]
|
|
struct SubtleCShakeParams {
|
|
/// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
|
|
name: CryptoAlgorithm,
|
|
|
|
/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-CShakeParams-length>
|
|
length: u32,
|
|
|
|
/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-CShakeParams-functionName>
|
|
function_name: Option<Vec<u8>>,
|
|
|
|
/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-CShakeParams-customization>
|
|
customization: Option<Vec<u8>>,
|
|
}
|
|
|
|
impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleCShakeParams {
|
|
type Error = Error;
|
|
|
|
fn try_from_with_cx(
|
|
value: HandleValue<'a>,
|
|
cx: &mut js::context::JSContext,
|
|
) -> Result<Self, Self::Error> {
|
|
let dictionary = dictionary_from_jsval::<RootedTraceableBox<CShakeParams>>(cx, value)?;
|
|
|
|
let function_name =
|
|
dictionary
|
|
.functionName
|
|
.as_ref()
|
|
.map(|function_name| match function_name {
|
|
ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
|
|
ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
|
|
});
|
|
let customization =
|
|
dictionary
|
|
.customization
|
|
.as_ref()
|
|
.map(|customization| match customization {
|
|
ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
|
|
ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
|
|
});
|
|
|
|
Ok(SubtleCShakeParams {
|
|
name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
|
|
length: dictionary.length,
|
|
function_name,
|
|
customization,
|
|
})
|
|
}
|
|
}
|
|
|
|
/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params>
|
|
#[derive(Clone, MallocSizeOf)]
|
|
struct SubtleArgon2Params {
|
|
/// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
|
|
name: CryptoAlgorithm,
|
|
|
|
/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-nonce>
|
|
nonce: Vec<u8>,
|
|
|
|
/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-parallelism>
|
|
parallelism: u32,
|
|
|
|
/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-memory>
|
|
memory: u32,
|
|
|
|
/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-passes>
|
|
passes: u32,
|
|
|
|
/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-version>
|
|
version: Option<u8>,
|
|
|
|
/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-secretValue>
|
|
secret_value: Option<Vec<u8>>,
|
|
|
|
/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-associatedData>
|
|
associated_data: Option<Vec<u8>>,
|
|
}
|
|
|
|
impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleArgon2Params {
|
|
type Error = Error;
|
|
|
|
fn try_from_with_cx(
|
|
value: HandleValue<'a>,
|
|
cx: &mut js::context::JSContext,
|
|
) -> Result<Self, Self::Error> {
|
|
let dictionary = dictionary_from_jsval::<RootedTraceableBox<Argon2Params>>(cx, value)?;
|
|
|
|
let nonce = match &dictionary.nonce {
|
|
ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
|
|
ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
|
|
};
|
|
let secret_value = dictionary
|
|
.secretValue
|
|
.as_ref()
|
|
.map(|secret_value| match secret_value {
|
|
ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
|
|
ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
|
|
});
|
|
let associated_data =
|
|
dictionary
|
|
.associatedData
|
|
.as_ref()
|
|
.map(|associated_data| match associated_data {
|
|
ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
|
|
ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
|
|
});
|
|
|
|
Ok(SubtleArgon2Params {
|
|
name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
|
|
nonce,
|
|
parallelism: dictionary.parallelism,
|
|
memory: dictionary.memory,
|
|
passes: dictionary.passes,
|
|
version: dictionary.version,
|
|
secret_value,
|
|
associated_data,
|
|
})
|
|
}
|
|
}
|
|
|
|
/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-EncapsulatedKey>
|
|
struct SubtleEncapsulatedKey {
|
|
/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-EncapsulatedKey-sharedKey>
|
|
shared_key: Option<Trusted<CryptoKey>>,
|
|
|
|
/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-EncapsulatedKey-ciphertext>
|
|
ciphertext: Option<Vec<u8>>,
|
|
}
|
|
|
|
impl SafeToJSValConvertible for SubtleEncapsulatedKey {
|
|
fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
|
|
let shared_key = self.shared_key.as_ref().map(|shared_key| shared_key.root());
|
|
let ciphertext = self.ciphertext.as_ref().map(|data| {
|
|
rooted!(in(*cx) let mut ciphertext_ptr = ptr::null_mut::<JSObject>());
|
|
create_buffer_source::<ArrayBufferU8>(cx, data, ciphertext_ptr.handle_mut(), can_gc)
|
|
.expect("Failed to convert ciphertext to ArrayBufferU8")
|
|
});
|
|
let encapsulated_key = RootedTraceableBox::new(EncapsulatedKey {
|
|
sharedKey: shared_key,
|
|
ciphertext,
|
|
});
|
|
encapsulated_key.safe_to_jsval(cx, rval, can_gc);
|
|
}
|
|
}
|
|
|
|
/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-EncapsulatedBits>
|
|
struct SubtleEncapsulatedBits {
|
|
/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-EncapsulatedBits-sharedKey>
|
|
shared_key: Option<Vec<u8>>,
|
|
|
|
/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-EncapsulatedBits-ciphertext>
|
|
ciphertext: Option<Vec<u8>>,
|
|
}
|
|
|
|
impl SafeToJSValConvertible for SubtleEncapsulatedBits {
|
|
fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
|
|
let shared_key = self.shared_key.as_ref().map(|data| {
|
|
rooted!(in(*cx) let mut shared_key_ptr = ptr::null_mut::<JSObject>());
|
|
create_buffer_source::<ArrayBufferU8>(cx, data, shared_key_ptr.handle_mut(), can_gc)
|
|
.expect("Failed to convert shared key to ArrayBufferU8")
|
|
});
|
|
let ciphertext = self.ciphertext.as_ref().map(|data| {
|
|
rooted!(in(*cx) let mut ciphertext_ptr = ptr::null_mut::<JSObject>());
|
|
create_buffer_source::<ArrayBufferU8>(cx, data, ciphertext_ptr.handle_mut(), can_gc)
|
|
.expect("Failed to convert ciphertext to ArrayBufferU8")
|
|
});
|
|
let encapsulated_bits = RootedTraceableBox::new(EncapsulatedBits {
|
|
sharedKey: shared_key,
|
|
ciphertext,
|
|
});
|
|
encapsulated_bits.safe_to_jsval(cx, rval, can_gc);
|
|
}
|
|
}
|
|
|
|
/// Helper to abstract the conversion process of a JS value into many different WebIDL dictionaries.
|
|
fn dictionary_from_jsval<T>(cx: &mut js::context::JSContext, value: HandleValue) -> Fallible<T>
|
|
where
|
|
T: SafeFromJSValConvertible<Config = ()>,
|
|
{
|
|
let conversion = T::safe_from_jsval(cx.into(), value, (), CanGc::from_cx(cx))
|
|
.map_err(|_| Error::JSFailed)?;
|
|
match conversion {
|
|
ConversionResult::Success(dictionary) => Ok(dictionary),
|
|
ConversionResult::Failure(error) => Err(Error::Type(error.into_owned())),
|
|
}
|
|
}
|
|
|
|
/// The returned type of the successful export key operation. `Bytes` should be used when the key
|
|
/// is exported in "raw", "spki" or "pkcs8" format. `Jwk` should be used when the key is exported
|
|
/// in "jwk" format.
|
|
enum ExportedKey {
|
|
Bytes(Vec<u8>),
|
|
Jwk(Box<JsonWebKey>),
|
|
}
|
|
|
|
/// Union type of KeyAlgorithm and IDL dictionary types derived from it. Note that we actually use
|
|
/// our "subtle" structs of the corresponding IDL dictionary types so that they can be easily
|
|
/// passed to another threads.
|
|
#[derive(Clone, MallocSizeOf)]
|
|
#[expect(clippy::enum_variant_names)]
|
|
pub(crate) enum KeyAlgorithmAndDerivatives {
|
|
KeyAlgorithm(SubtleKeyAlgorithm),
|
|
RsaHashedKeyAlgorithm(SubtleRsaHashedKeyAlgorithm),
|
|
EcKeyAlgorithm(SubtleEcKeyAlgorithm),
|
|
AesKeyAlgorithm(SubtleAesKeyAlgorithm),
|
|
HmacKeyAlgorithm(SubtleHmacKeyAlgorithm),
|
|
}
|
|
|
|
impl KeyAlgorithmAndDerivatives {
|
|
fn name(&self) -> CryptoAlgorithm {
|
|
match self {
|
|
KeyAlgorithmAndDerivatives::KeyAlgorithm(algorithm) => algorithm.name,
|
|
KeyAlgorithmAndDerivatives::RsaHashedKeyAlgorithm(algorithm) => algorithm.name,
|
|
KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algorithm) => algorithm.name,
|
|
KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algorithm) => algorithm.name,
|
|
KeyAlgorithmAndDerivatives::HmacKeyAlgorithm(algorithm) => algorithm.name,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl SafeToJSValConvertible for KeyAlgorithmAndDerivatives {
|
|
fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
|
|
match self {
|
|
KeyAlgorithmAndDerivatives::KeyAlgorithm(algo) => algo.safe_to_jsval(cx, rval, can_gc),
|
|
KeyAlgorithmAndDerivatives::RsaHashedKeyAlgorithm(algo) => {
|
|
algo.safe_to_jsval(cx, rval, can_gc)
|
|
},
|
|
KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algo) => {
|
|
algo.safe_to_jsval(cx, rval, can_gc)
|
|
},
|
|
KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algo) => {
|
|
algo.safe_to_jsval(cx, rval, can_gc)
|
|
},
|
|
KeyAlgorithmAndDerivatives::HmacKeyAlgorithm(algo) => {
|
|
algo.safe_to_jsval(cx, rval, can_gc)
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Copy)]
|
|
enum JwkStringField {
|
|
X,
|
|
Y,
|
|
D,
|
|
N,
|
|
E,
|
|
P,
|
|
Q,
|
|
DP,
|
|
DQ,
|
|
QI,
|
|
K,
|
|
Priv,
|
|
Pub,
|
|
}
|
|
|
|
impl Display for JwkStringField {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
let field_name = match self {
|
|
JwkStringField::X => "x",
|
|
JwkStringField::Y => "y",
|
|
JwkStringField::D => "d",
|
|
JwkStringField::N => "n",
|
|
JwkStringField::E => "e",
|
|
JwkStringField::P => "q",
|
|
JwkStringField::Q => "q",
|
|
JwkStringField::DP => "dp",
|
|
JwkStringField::DQ => "dq",
|
|
JwkStringField::QI => "qi",
|
|
JwkStringField::K => "k",
|
|
JwkStringField::Priv => "priv",
|
|
JwkStringField::Pub => "pub",
|
|
};
|
|
write!(f, "{}", field_name)
|
|
}
|
|
}
|
|
|
|
trait JsonWebKeyExt {
|
|
fn parse(cx: &mut js::context::JSContext, data: &[u8]) -> Result<JsonWebKey, Error>;
|
|
fn stringify(&self, cx: &mut js::context::JSContext) -> Result<DOMString, Error>;
|
|
fn get_usages_from_key_ops(&self) -> Result<Vec<KeyUsage>, Error>;
|
|
fn check_key_ops(&self, specified_usages: &[KeyUsage]) -> Result<(), Error>;
|
|
fn set_key_ops(&mut self, usages: Vec<KeyUsage>);
|
|
fn encode_string_field(&mut self, field: JwkStringField, data: &[u8]);
|
|
fn decode_optional_string_field(&self, field: JwkStringField)
|
|
-> Result<Option<Vec<u8>>, Error>;
|
|
fn decode_required_string_field(&self, field: JwkStringField) -> Result<Vec<u8>, Error>;
|
|
fn decode_primes_from_oth_field(&self, primes: &mut Vec<Vec<u8>>) -> Result<(), Error>;
|
|
}
|
|
|
|
impl JsonWebKeyExt for JsonWebKey {
|
|
/// <https://w3c.github.io/webcrypto/#concept-parse-a-jwk>
|
|
#[expect(unsafe_code)]
|
|
fn parse(cx: &mut js::context::JSContext, data: &[u8]) -> Result<JsonWebKey, Error> {
|
|
// Step 1. Let data be the sequence of bytes to be parsed.
|
|
// (It is given as a method paramter.)
|
|
|
|
// Step 2. Let json be the Unicode string that results from interpreting data according to UTF-8.
|
|
let json = String::from_utf8_lossy(data);
|
|
|
|
// Step 3. Convert json to UTF-16.
|
|
let json: Vec<_> = json.encode_utf16().collect();
|
|
|
|
// Step 4. Let result be the object literal that results from executing the JSON.parse
|
|
// internal function in the context of a new global object, with text argument set to a
|
|
// JavaScript String containing json.
|
|
rooted!(&in(cx) let mut result = UndefinedValue());
|
|
unsafe {
|
|
if !JS_ParseJSON(cx, json.as_ptr(), json.len() as u32, result.handle_mut()) {
|
|
return Err(Error::JSFailed);
|
|
}
|
|
}
|
|
|
|
// Step 5. Let key be the result of converting result to the IDL dictionary type of JsonWebKey.
|
|
let key = match JsonWebKey::new(cx.into(), result.handle(), CanGc::from_cx(cx)) {
|
|
Ok(ConversionResult::Success(key)) => key,
|
|
Ok(ConversionResult::Failure(error)) => {
|
|
return Err(Error::Type(error.into_owned()));
|
|
},
|
|
Err(()) => {
|
|
return Err(Error::JSFailed);
|
|
},
|
|
};
|
|
|
|
// Step 6. If the kty field of key is not defined, then throw a DataError.
|
|
if key.kty.is_none() {
|
|
return Err(Error::Data(None));
|
|
}
|
|
|
|
// Step 7. Result key.
|
|
Ok(key)
|
|
}
|
|
|
|
/// Convert a JsonWebKey value to DOMString. We first convert the JsonWebKey value to
|
|
/// JavaScript value, and then serialize it by performing steps in
|
|
/// <https://infra.spec.whatwg.org/#serialize-a-javascript-value-to-a-json-string>. This acts
|
|
/// like the opposite of JsonWebKey::parse if you further convert the stringified result to
|
|
/// bytes.
|
|
fn stringify(&self, cx: &mut js::context::JSContext) -> Result<DOMString, Error> {
|
|
rooted!(&in(cx) let mut data = UndefinedValue());
|
|
self.safe_to_jsval(cx.into(), data.handle_mut(), CanGc::from_cx(cx));
|
|
serialize_jsval_to_json_utf8(cx.into(), data.handle())
|
|
}
|
|
|
|
fn get_usages_from_key_ops(&self) -> Result<Vec<KeyUsage>, Error> {
|
|
let mut usages = vec![];
|
|
for op in self.key_ops.as_ref().ok_or(Error::Data(None))? {
|
|
usages.push(KeyUsage::from_str(&op.str()).map_err(|_| Error::Data(None))?);
|
|
}
|
|
Ok(usages)
|
|
}
|
|
|
|
/// If the key_ops field of jwk is present, and is invalid according to the requirements of
|
|
/// JSON Web Key [JWK] or does not contain all of the specified usages values, then throw a
|
|
/// DataError.
|
|
fn check_key_ops(&self, specified_usages: &[KeyUsage]) -> Result<(), Error> {
|
|
// If the key_ops field of jwk is present,
|
|
if let Some(ref key_ops) = self.key_ops {
|
|
// and is invalid according to the requirements of JSON Web Key [JWK]:
|
|
// 1. Duplicate key operation values MUST NOT be present in the array.
|
|
if key_ops
|
|
.iter()
|
|
.collect::<std::collections::HashSet<_>>()
|
|
.len() <
|
|
key_ops.len()
|
|
{
|
|
return Err(Error::Data(None));
|
|
}
|
|
// 2. The "use" and "key_ops" JWK members SHOULD NOT be used together; however, if both
|
|
// are used, the information they convey MUST be consistent.
|
|
if let Some(ref use_) = self.use_ {
|
|
if key_ops.iter().any(|op| op != use_) {
|
|
return Err(Error::Data(None));
|
|
}
|
|
}
|
|
|
|
// or does not contain all of the specified usages values
|
|
let key_ops_as_usages = self.get_usages_from_key_ops()?;
|
|
if !specified_usages
|
|
.iter()
|
|
.all(|specified_usage| key_ops_as_usages.contains(specified_usage))
|
|
{
|
|
return Err(Error::Data(None));
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
// Set the key_ops attribute of jwk to equal the given usages.
|
|
fn set_key_ops(&mut self, usages: Vec<KeyUsage>) {
|
|
self.key_ops = Some(
|
|
usages
|
|
.into_iter()
|
|
.map(|usage| DOMString::from(usage.as_str()))
|
|
.collect(),
|
|
);
|
|
}
|
|
|
|
// Encode a byte sequence to a base64url-encoded string, and set the field to the encoded
|
|
// string.
|
|
fn encode_string_field(&mut self, field: JwkStringField, data: &[u8]) {
|
|
let encoded_data = DOMString::from(Base64UrlUnpadded::encode_string(data));
|
|
match field {
|
|
JwkStringField::X => self.x = Some(encoded_data),
|
|
JwkStringField::Y => self.y = Some(encoded_data),
|
|
JwkStringField::D => self.d = Some(encoded_data),
|
|
JwkStringField::N => self.n = Some(encoded_data),
|
|
JwkStringField::E => self.e = Some(encoded_data),
|
|
JwkStringField::P => self.p = Some(encoded_data),
|
|
JwkStringField::Q => self.q = Some(encoded_data),
|
|
JwkStringField::DP => self.dp = Some(encoded_data),
|
|
JwkStringField::DQ => self.dq = Some(encoded_data),
|
|
JwkStringField::QI => self.qi = Some(encoded_data),
|
|
JwkStringField::K => self.k = Some(encoded_data),
|
|
JwkStringField::Priv => self.priv_ = Some(encoded_data),
|
|
JwkStringField::Pub => self.pub_ = Some(encoded_data),
|
|
}
|
|
}
|
|
|
|
// Decode a field from a base64url-encoded string to a byte sequence. If the field is not a
|
|
// valid base64url-encoded string, then throw a DataError.
|
|
fn decode_optional_string_field(
|
|
&self,
|
|
field: JwkStringField,
|
|
) -> Result<Option<Vec<u8>>, Error> {
|
|
let field_string = match field {
|
|
JwkStringField::X => &self.x,
|
|
JwkStringField::Y => &self.y,
|
|
JwkStringField::D => &self.d,
|
|
JwkStringField::N => &self.n,
|
|
JwkStringField::E => &self.e,
|
|
JwkStringField::P => &self.p,
|
|
JwkStringField::Q => &self.q,
|
|
JwkStringField::DP => &self.dp,
|
|
JwkStringField::DQ => &self.dq,
|
|
JwkStringField::QI => &self.qi,
|
|
JwkStringField::K => &self.k,
|
|
JwkStringField::Priv => &self.priv_,
|
|
JwkStringField::Pub => &self.pub_,
|
|
};
|
|
|
|
field_string
|
|
.as_ref()
|
|
.map(|field_string| Base64UrlUnpadded::decode_vec(&field_string.str()))
|
|
.transpose()
|
|
.map_err(|_| Error::Data(Some(format!("Failed to decode {} field in jwk", field))))
|
|
}
|
|
|
|
// Decode a field from a base64url-encoded string to a byte sequence. If the field is not
|
|
// present or it is not a valid base64url-encoded string, then throw a DataError.
|
|
fn decode_required_string_field(&self, field: JwkStringField) -> Result<Vec<u8>, Error> {
|
|
self.decode_optional_string_field(field)?
|
|
.ok_or(Error::Data(Some(format!(
|
|
"The {} field is not present in jwk",
|
|
field
|
|
))))
|
|
}
|
|
|
|
// Decode the "r", "d" and "t" field of each entry in the "oth" array, from a base64url-encoded
|
|
// string to a byte sequence, and append the decoded "r" field to the `primes` list, in the
|
|
// order of presence in the "oth" array.
|
|
//
|
|
// If the "oth" field is present and any of the "p", "q", "dp", "dq" or "qi" field is not
|
|
// present, then throw a DataError. For each entry in the "oth" array, if any of the "r", "d"
|
|
// and "t" field is not present or it is not a valid base64url-encoded string, then throw a
|
|
// DataError.
|
|
fn decode_primes_from_oth_field(&self, primes: &mut Vec<Vec<u8>>) -> Result<(), Error> {
|
|
if self.oth.is_some() &&
|
|
(self.p.is_none() ||
|
|
self.q.is_none() ||
|
|
self.dp.is_none() ||
|
|
self.dq.is_none() ||
|
|
self.qi.is_none())
|
|
{
|
|
return Err(Error::Data(Some(
|
|
"The oth field is present while at least one of p, q, dp, dq, qi is missing, in jwk".to_string()
|
|
)));
|
|
}
|
|
|
|
for rsa_other_prime_info in self.oth.as_ref().unwrap_or(&Vec::new()) {
|
|
let r = Base64UrlUnpadded::decode_vec(
|
|
&rsa_other_prime_info
|
|
.r
|
|
.as_ref()
|
|
.ok_or(Error::Data(Some(
|
|
"The r field is not present in one of the entry of oth field in jwk"
|
|
.to_string(),
|
|
)))?
|
|
.str(),
|
|
)
|
|
.map_err(|_| {
|
|
Error::Data(Some(
|
|
"Fail to decode r field in one of the entry of oth field in jwk".to_string(),
|
|
))
|
|
})?;
|
|
primes.push(r);
|
|
|
|
let _d = Base64UrlUnpadded::decode_vec(
|
|
&rsa_other_prime_info
|
|
.d
|
|
.as_ref()
|
|
.ok_or(Error::Data(Some(
|
|
"The d field is not present in one of the entry of oth field in jwk"
|
|
.to_string(),
|
|
)))?
|
|
.str(),
|
|
)
|
|
.map_err(|_| {
|
|
Error::Data(Some(
|
|
"Fail to decode d field in one of the entry of oth field in jwk".to_string(),
|
|
))
|
|
})?;
|
|
|
|
let _t = Base64UrlUnpadded::decode_vec(
|
|
&rsa_other_prime_info
|
|
.t
|
|
.as_ref()
|
|
.ok_or(Error::Data(Some(
|
|
"The t field is not present in one of the entry of oth field in jwk"
|
|
.to_string(),
|
|
)))?
|
|
.str(),
|
|
)
|
|
.map_err(|_| {
|
|
Error::Data(Some(
|
|
"Fail to decode t field in one of the entry of oth field in jwk".to_string(),
|
|
))
|
|
})?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
/// <https://w3c.github.io/webcrypto/#algorithm-normalization-normalize-an-algorithm>
|
|
fn normalize_algorithm<Op: Operation>(
|
|
cx: &mut js::context::JSContext,
|
|
algorithm: &AlgorithmIdentifier,
|
|
) -> Result<Op::RegisteredAlgorithm, Error> {
|
|
match algorithm {
|
|
// If alg is an instance of a DOMString:
|
|
ObjectOrString::String(name) => {
|
|
// Return the result of running the normalize an algorithm algorithm, with the alg set
|
|
// to a new Algorithm dictionary whose name attribute is alg, and with the op set to
|
|
// op.
|
|
let algorithm = Algorithm {
|
|
name: name.to_owned(),
|
|
};
|
|
rooted!(&in(cx) let mut algorithm_value = UndefinedValue());
|
|
algorithm.safe_to_jsval(cx.into(), algorithm_value.handle_mut(), CanGc::from_cx(cx));
|
|
let algorithm_object = RootedTraceableBox::new(Heap::default());
|
|
algorithm_object.set(algorithm_value.to_object());
|
|
normalize_algorithm::<Op>(cx, &ObjectOrString::Object(algorithm_object))
|
|
},
|
|
// If alg is an object:
|
|
ObjectOrString::Object(object) => {
|
|
// Step 1. Let registeredAlgorithms be the associative container stored at the op key
|
|
// of supportedAlgorithms.
|
|
|
|
// Stpe 2. Let initialAlg be the result of converting the ECMAScript object represented
|
|
// by alg to the IDL dictionary type Algorithm, as defined by [WebIDL].
|
|
// Step 3. If an error occurred, return the error and terminate this algorithm.
|
|
rooted!(&in(cx) let value = ObjectValue(object.get()));
|
|
let initial_algorithm = dictionary_from_jsval::<Algorithm>(cx, value.handle())?;
|
|
|
|
// Step 4. Let algName be the value of the name attribute of initialAlg.
|
|
let algorithm_name =
|
|
CryptoAlgorithm::from_str_ignore_case(&initial_algorithm.name.str())?;
|
|
|
|
// Step 5.
|
|
// If registeredAlgorithms contains a key that is a case-insensitive string match
|
|
// for algName:
|
|
// Step 5.1. Set algName to the value of the matching key.
|
|
// Step 5.2. Let desiredType be the IDL dictionary type stored at algName in
|
|
// registeredAlgorithms.
|
|
// Otherwise:
|
|
// Return a new NotSupportedError and terminate this algorithm.
|
|
// Step 6. Let normalizedAlgorithm be the result of converting the ECMAScript object
|
|
// represented by alg to the IDL dictionary type desiredType, as defined by [WebIDL].
|
|
// Step 7. Set the name attribute of normalizedAlgorithm to algName.
|
|
// Step 8. If an error occurred, return the error and terminate this algorithm.
|
|
// Step 9. Let dictionaries be a list consisting of the IDL dictionary type desiredType
|
|
// and all of desiredType's inherited dictionaries, in order from least to most
|
|
// derived.
|
|
// Step 10. For each dictionary dictionary in dictionaries:
|
|
// Step 10.1. For each dictionary member member declared on dictionary, in order:
|
|
// Step 10.1.1. Let key be the identifier of member.
|
|
// Step 10.1.2. Let idlValue be the value of the dictionary member with key
|
|
// name of key on normalizedAlgorithm.
|
|
// Step 10.1.3.
|
|
// If member is of the type BufferSource and is present:
|
|
// Set the dictionary member on normalizedAlgorithm with key name key
|
|
// to the result of getting a copy of the bytes held by idlValue,
|
|
// replacing the current value.
|
|
// If member is of the type HashAlgorithmIdentifier:
|
|
// Set the dictionary member on normalizedAlgorithm with key name key
|
|
// to the result of normalizing an algorithm, with the alg set to
|
|
// idlValue and the op set to "digest".
|
|
// If member is of the type AlgorithmIdentifier:
|
|
// Set the dictionary member on normalizedAlgorithm with key name key
|
|
// to the result of normalizing an algorithm, with the alg set to
|
|
// idlValue and the op set to the operation defined by the
|
|
// specification that defines the algorithm identified by algName.
|
|
//
|
|
// NOTE: Step 7 is done by writing algName back to the name attribute of the JS object
|
|
// before dictionary conversion in Step 6, in order to streamline the conversion. Step
|
|
// 9 and 10 are done by the calling `TryIntoWithCx::try_into_with_cx` within the trait
|
|
// implementation of `Op::RegisteredAlgorithm::from_object_value`.
|
|
rooted!(&in(cx) let mut algorithm_name_value = UndefinedValue());
|
|
algorithm_name.as_str().safe_to_jsval(
|
|
cx.into(),
|
|
algorithm_name_value.handle_mut(),
|
|
CanGc::from_cx(cx),
|
|
);
|
|
set_dictionary_property(
|
|
cx.into(),
|
|
object.handle(),
|
|
c"name",
|
|
algorithm_name_value.handle(),
|
|
)
|
|
.map_err(|_| Error::JSFailed)?;
|
|
let normalized_algorithm =
|
|
Op::RegisteredAlgorithm::from_object_value(cx, algorithm_name, value.handle())?;
|
|
|
|
// Step 11. Return normalizedAlgorithm.
|
|
Ok(normalized_algorithm)
|
|
},
|
|
}
|
|
}
|
|
|
|
// <https://w3c.github.io/webcrypto/#dfn-supportedAlgorithms>
|
|
//
|
|
// We implement the internal object
|
|
// [supportedAlgorithms](https://w3c.github.io/webcrypto/#dfn-supportedAlgorithms) for algorithm
|
|
// registration, in the following way.
|
|
//
|
|
// For each operation v in the list of [supported
|
|
// operations](https://w3c.github.io/webcrypto/#supported-operation), we define a struct to
|
|
// represent it, which acts a key of the internal object supportedAlgorithms.
|
|
//
|
|
// We then implement the [`Operation`] trait for these structs. When implementing the trait for
|
|
// each of these structs, we set the associated type [`RegisteredAlgorithm`] of [`Operation`] to an
|
|
// enum as the value of the operation v in supportedAlgorithms. The enum lists all algorithhms
|
|
// supporting the operation v as its variants.
|
|
//
|
|
// To [define an algorithm](https://w3c.github.io/webcrypto/#concept-define-an-algorithm), each
|
|
// variant in the enum has an inner type corresponding to the desired input IDL dictionary type for
|
|
// the supported algorithm represented by the variant. Moreover, the enum also need to implement
|
|
// the [`NormalizedAlgorithm`] trait since it is used as the output of
|
|
// [`normalize_algorithm`].
|
|
//
|
|
// For example, we define the [`EncryptOperation`] struct to represent the "encrypt" operation, and
|
|
// implement the [`Operation`] trait for it. The associated type [`RegisteredAlgorithm`] of
|
|
// [`Operation`] is set to the [`EncryptAlgorithm`] enum, whose variants are cryptographic
|
|
// algorithms that support the "encrypt" operation. The variant [`EncryptAlgorithm::AesCtr`] has an
|
|
// inner type [`SubtleAesCtrParams`] since the desired input IDL dictionary type for "encrypt"
|
|
// operation of AES-CTR algorithm is the `AesCtrParams` dictionary. The [`EncryptAlgorithm`] enum
|
|
// also implements the [`NormalizedAlgorithm`] trait accordingly.
|
|
//
|
|
// The algorithm registrations are specified in:
|
|
// RSASSA-PKCS1-v1_5: <https://w3c.github.io/webcrypto/#rsassa-pkcs1-registration>
|
|
// RSA-PSS: <https://w3c.github.io/webcrypto/#rsa-pss-registration>
|
|
// RSA-OAEP: <https://w3c.github.io/webcrypto/#rsa-oaep-registration>
|
|
// ECDSA: <https://w3c.github.io/webcrypto/#ecdsa-registration>
|
|
// ECDH: <https://w3c.github.io/webcrypto/#ecdh-registration>
|
|
// Ed25519: <https://w3c.github.io/webcrypto/#ed25519-registration>
|
|
// X25519: <https://w3c.github.io/webcrypto/#x25519-registration>
|
|
// AES-CTR: <https://w3c.github.io/webcrypto/#aes-ctr-registration>
|
|
// AES-CBC: <https://w3c.github.io/webcrypto/#aes-cbc-registration>
|
|
// AES-GCM: <https://w3c.github.io/webcrypto/#aes-gcm-registration>
|
|
// AES-KW: <https://w3c.github.io/webcrypto/#aes-kw-registration>
|
|
// HMAC: <https://w3c.github.io/webcrypto/#hmac-registration>
|
|
// SHA: <https://w3c.github.io/webcrypto/#sha-registration>
|
|
// HKDF: <https://w3c.github.io/webcrypto/#hkdf-registration>
|
|
// PBKDF2: <https://w3c.github.io/webcrypto/#pbkdf2-registration>
|
|
// ML-KEM: <https://wicg.github.io/webcrypto-modern-algos/#ml-kem-registration>
|
|
// ML-DSA: <https://wicg.github.io/webcrypto-modern-algos/#ml-dsa-registration>
|
|
// AES-OCB: <https://wicg.github.io/webcrypto-modern-algos/#aes-ocb-registration>
|
|
// ChaCha20-Poly1305: <https://wicg.github.io/webcrypto-modern-algos/#chacha20-poly1305-registration>
|
|
// SHA-3: <https://wicg.github.io/webcrypto-modern-algos/#sha3-registration>
|
|
// cSHAKE: <https://wicg.github.io/webcrypto-modern-algos/#cshake-registration>
|
|
// Argon2: <https://wicg.github.io/webcrypto-modern-algos/#argon2-registration>
|
|
|
|
trait Operation {
|
|
type RegisteredAlgorithm: NormalizedAlgorithm;
|
|
}
|
|
|
|
trait NormalizedAlgorithm: Sized {
|
|
/// Step 4 - 10 of <https://w3c.github.io/webcrypto/#algorithm-normalization-normalize-an-algorithm>
|
|
fn from_object_value(
|
|
cx: &mut js::context::JSContext,
|
|
algorithm_name: CryptoAlgorithm,
|
|
value: HandleValue,
|
|
) -> Fallible<Self>;
|
|
fn name(&self) -> CryptoAlgorithm;
|
|
}
|
|
|
|
/// The value of the key "encrypt" in the internal object supportedAlgorithms
|
|
struct EncryptOperation {}
|
|
|
|
impl Operation for EncryptOperation {
|
|
type RegisteredAlgorithm = EncryptAlgorithm;
|
|
}
|
|
|
|
/// Normalized algorithm for the "encrypt" operation, used as output of
|
|
/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
|
|
enum EncryptAlgorithm {
|
|
RsaOaep(SubtleRsaOaepParams),
|
|
AesCtr(SubtleAesCtrParams),
|
|
AesCbc(SubtleAesCbcParams),
|
|
AesGcm(SubtleAesGcmParams),
|
|
AesOcb(SubtleAeadParams),
|
|
ChaCha20Poly1305(SubtleAeadParams),
|
|
}
|
|
|
|
impl NormalizedAlgorithm for EncryptAlgorithm {
|
|
fn from_object_value(
|
|
cx: &mut js::context::JSContext,
|
|
algorithm_name: CryptoAlgorithm,
|
|
value: HandleValue,
|
|
) -> Fallible<Self> {
|
|
match algorithm_name {
|
|
CryptoAlgorithm::RsaOaep => Ok(EncryptAlgorithm::RsaOaep(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::AesCtr => Ok(EncryptAlgorithm::AesCtr(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::AesCbc => Ok(EncryptAlgorithm::AesCbc(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::AesGcm => Ok(EncryptAlgorithm::AesGcm(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::AesOcb => Ok(EncryptAlgorithm::AesOcb(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::ChaCha20Poly1305 => Ok(EncryptAlgorithm::ChaCha20Poly1305(
|
|
value.try_into_with_cx(cx)?,
|
|
)),
|
|
_ => Err(Error::NotSupported(Some(format!(
|
|
"{} does not support \"encrypt\" operation",
|
|
algorithm_name.as_str()
|
|
)))),
|
|
}
|
|
}
|
|
|
|
fn name(&self) -> CryptoAlgorithm {
|
|
match self {
|
|
EncryptAlgorithm::RsaOaep(algorithm) => algorithm.name,
|
|
EncryptAlgorithm::AesCtr(algorithm) => algorithm.name,
|
|
EncryptAlgorithm::AesCbc(algorithm) => algorithm.name,
|
|
EncryptAlgorithm::AesGcm(algorithm) => algorithm.name,
|
|
EncryptAlgorithm::AesOcb(algorithm) => algorithm.name,
|
|
EncryptAlgorithm::ChaCha20Poly1305(algorithm) => algorithm.name,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl EncryptAlgorithm {
|
|
fn encrypt(&self, key: &CryptoKey, plaintext: &[u8]) -> Result<Vec<u8>, Error> {
|
|
match self {
|
|
EncryptAlgorithm::RsaOaep(algorithm) => {
|
|
rsa_oaep_operation::encrypt(algorithm, key, plaintext)
|
|
},
|
|
EncryptAlgorithm::AesCtr(algorithm) => {
|
|
aes_ctr_operation::encrypt(algorithm, key, plaintext)
|
|
},
|
|
EncryptAlgorithm::AesCbc(algorithm) => {
|
|
aes_cbc_operation::encrypt(algorithm, key, plaintext)
|
|
},
|
|
EncryptAlgorithm::AesGcm(algorithm) => {
|
|
aes_gcm_operation::encrypt(algorithm, key, plaintext)
|
|
},
|
|
EncryptAlgorithm::AesOcb(algorithm) => {
|
|
aes_ocb_operation::encrypt(algorithm, key, plaintext)
|
|
},
|
|
EncryptAlgorithm::ChaCha20Poly1305(algorithm) => {
|
|
chacha20_poly1305_operation::encrypt(algorithm, key, plaintext)
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The value of the key "decrypt" in the internal object supportedAlgorithms
|
|
struct DecryptOperation {}
|
|
|
|
impl Operation for DecryptOperation {
|
|
type RegisteredAlgorithm = DecryptAlgorithm;
|
|
}
|
|
|
|
/// Normalized algorithm for the "decrypt" operation, used as output of
|
|
/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
|
|
enum DecryptAlgorithm {
|
|
RsaOaep(SubtleRsaOaepParams),
|
|
AesCtr(SubtleAesCtrParams),
|
|
AesCbc(SubtleAesCbcParams),
|
|
AesGcm(SubtleAesGcmParams),
|
|
AesOcb(SubtleAeadParams),
|
|
ChaCha20Poly1305(SubtleAeadParams),
|
|
}
|
|
|
|
impl NormalizedAlgorithm for DecryptAlgorithm {
|
|
fn from_object_value(
|
|
cx: &mut js::context::JSContext,
|
|
algorithm_name: CryptoAlgorithm,
|
|
value: HandleValue,
|
|
) -> Fallible<Self> {
|
|
match algorithm_name {
|
|
CryptoAlgorithm::RsaOaep => Ok(DecryptAlgorithm::RsaOaep(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::AesCtr => Ok(DecryptAlgorithm::AesCtr(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::AesCbc => Ok(DecryptAlgorithm::AesCbc(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::AesGcm => Ok(DecryptAlgorithm::AesGcm(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::AesOcb => Ok(DecryptAlgorithm::AesOcb(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::ChaCha20Poly1305 => Ok(DecryptAlgorithm::ChaCha20Poly1305(
|
|
value.try_into_with_cx(cx)?,
|
|
)),
|
|
_ => Err(Error::NotSupported(Some(format!(
|
|
"{} does not support \"decrypt\" operation",
|
|
algorithm_name.as_str()
|
|
)))),
|
|
}
|
|
}
|
|
|
|
fn name(&self) -> CryptoAlgorithm {
|
|
match self {
|
|
DecryptAlgorithm::RsaOaep(algorithm) => algorithm.name,
|
|
DecryptAlgorithm::AesCtr(algorithm) => algorithm.name,
|
|
DecryptAlgorithm::AesCbc(algorithm) => algorithm.name,
|
|
DecryptAlgorithm::AesGcm(algorithm) => algorithm.name,
|
|
DecryptAlgorithm::AesOcb(algorithm) => algorithm.name,
|
|
DecryptAlgorithm::ChaCha20Poly1305(algorithm) => algorithm.name,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl DecryptAlgorithm {
|
|
fn decrypt(&self, key: &CryptoKey, ciphertext: &[u8]) -> Result<Vec<u8>, Error> {
|
|
match self {
|
|
DecryptAlgorithm::RsaOaep(algorithm) => {
|
|
rsa_oaep_operation::decrypt(algorithm, key, ciphertext)
|
|
},
|
|
DecryptAlgorithm::AesCtr(algorithm) => {
|
|
aes_ctr_operation::decrypt(algorithm, key, ciphertext)
|
|
},
|
|
DecryptAlgorithm::AesCbc(algorithm) => {
|
|
aes_cbc_operation::decrypt(algorithm, key, ciphertext)
|
|
},
|
|
DecryptAlgorithm::AesGcm(algorithm) => {
|
|
aes_gcm_operation::decrypt(algorithm, key, ciphertext)
|
|
},
|
|
DecryptAlgorithm::AesOcb(algorithm) => {
|
|
aes_ocb_operation::decrypt(algorithm, key, ciphertext)
|
|
},
|
|
DecryptAlgorithm::ChaCha20Poly1305(algorithm) => {
|
|
chacha20_poly1305_operation::decrypt(algorithm, key, ciphertext)
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The value of the key "sign" in the internal object supportedAlgorithms
|
|
struct SignOperation {}
|
|
|
|
impl Operation for SignOperation {
|
|
type RegisteredAlgorithm = SignAlgorithm;
|
|
}
|
|
|
|
/// Normalized algorithm for the "sign" operation, used as output of
|
|
/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
|
|
enum SignAlgorithm {
|
|
RsassaPkcs1V1_5(SubtleAlgorithm),
|
|
RsaPss(SubtleRsaPssParams),
|
|
Ecdsa(SubtleEcdsaParams),
|
|
Ed25519(SubtleAlgorithm),
|
|
Hmac(SubtleAlgorithm),
|
|
MlDsa(SubtleContextParams),
|
|
}
|
|
|
|
impl NormalizedAlgorithm for SignAlgorithm {
|
|
fn from_object_value(
|
|
cx: &mut js::context::JSContext,
|
|
algorithm_name: CryptoAlgorithm,
|
|
value: HandleValue,
|
|
) -> Fallible<Self> {
|
|
match algorithm_name {
|
|
CryptoAlgorithm::RsassaPkcs1V1_5 => {
|
|
Ok(SignAlgorithm::RsassaPkcs1V1_5(value.try_into_with_cx(cx)?))
|
|
},
|
|
CryptoAlgorithm::RsaPss => Ok(SignAlgorithm::RsaPss(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::Ecdsa => Ok(SignAlgorithm::Ecdsa(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::Ed25519 => Ok(SignAlgorithm::Ed25519(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::Hmac => Ok(SignAlgorithm::Hmac(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::MlDsa44 | CryptoAlgorithm::MlDsa65 | CryptoAlgorithm::MlDsa87 => {
|
|
Ok(SignAlgorithm::MlDsa(value.try_into_with_cx(cx)?))
|
|
},
|
|
_ => Err(Error::NotSupported(Some(format!(
|
|
"{} does not support \"sign\" operation",
|
|
algorithm_name.as_str()
|
|
)))),
|
|
}
|
|
}
|
|
|
|
fn name(&self) -> CryptoAlgorithm {
|
|
match self {
|
|
SignAlgorithm::RsassaPkcs1V1_5(algorithm) => algorithm.name,
|
|
SignAlgorithm::RsaPss(algorithm) => algorithm.name,
|
|
SignAlgorithm::Ecdsa(algorithm) => algorithm.name,
|
|
SignAlgorithm::Ed25519(algorithm) => algorithm.name,
|
|
SignAlgorithm::Hmac(algorithm) => algorithm.name,
|
|
SignAlgorithm::MlDsa(algorithm) => algorithm.name,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl SignAlgorithm {
|
|
fn sign(&self, key: &CryptoKey, message: &[u8]) -> Result<Vec<u8>, Error> {
|
|
match self {
|
|
SignAlgorithm::RsassaPkcs1V1_5(_algorithm) => {
|
|
rsassa_pkcs1_v1_5_operation::sign(key, message)
|
|
},
|
|
SignAlgorithm::RsaPss(algorithm) => rsa_pss_operation::sign(algorithm, key, message),
|
|
SignAlgorithm::Ecdsa(algorithm) => ecdsa_operation::sign(algorithm, key, message),
|
|
SignAlgorithm::Ed25519(_algorithm) => ed25519_operation::sign(key, message),
|
|
SignAlgorithm::Hmac(_algorithm) => hmac_operation::sign(key, message),
|
|
SignAlgorithm::MlDsa(algorithm) => ml_dsa_operation::sign(algorithm, key, message),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The value of the key "verify" in the internal object supportedAlgorithms
|
|
struct VerifyOperation {}
|
|
|
|
impl Operation for VerifyOperation {
|
|
type RegisteredAlgorithm = VerifyAlgorithm;
|
|
}
|
|
|
|
/// Normalized algorithm for the "verify" operation, used as output of
|
|
/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
|
|
enum VerifyAlgorithm {
|
|
RsassaPkcs1V1_5(SubtleAlgorithm),
|
|
RsaPss(SubtleRsaPssParams),
|
|
Ecdsa(SubtleEcdsaParams),
|
|
Ed25519(SubtleAlgorithm),
|
|
Hmac(SubtleAlgorithm),
|
|
MlDsa(SubtleContextParams),
|
|
}
|
|
|
|
impl NormalizedAlgorithm for VerifyAlgorithm {
|
|
fn from_object_value(
|
|
cx: &mut js::context::JSContext,
|
|
algorithm_name: CryptoAlgorithm,
|
|
value: HandleValue,
|
|
) -> Fallible<Self> {
|
|
match algorithm_name {
|
|
CryptoAlgorithm::RsassaPkcs1V1_5 => Ok(VerifyAlgorithm::RsassaPkcs1V1_5(
|
|
value.try_into_with_cx(cx)?,
|
|
)),
|
|
CryptoAlgorithm::RsaPss => Ok(VerifyAlgorithm::RsaPss(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::Ecdsa => Ok(VerifyAlgorithm::Ecdsa(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::Ed25519 => Ok(VerifyAlgorithm::Ed25519(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::Hmac => Ok(VerifyAlgorithm::Hmac(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::MlDsa44 | CryptoAlgorithm::MlDsa65 | CryptoAlgorithm::MlDsa87 => {
|
|
Ok(VerifyAlgorithm::MlDsa(value.try_into_with_cx(cx)?))
|
|
},
|
|
_ => Err(Error::NotSupported(Some(format!(
|
|
"{} does not support \"verify\" operation",
|
|
algorithm_name.as_str()
|
|
)))),
|
|
}
|
|
}
|
|
|
|
fn name(&self) -> CryptoAlgorithm {
|
|
match self {
|
|
VerifyAlgorithm::RsassaPkcs1V1_5(algorithm) => algorithm.name,
|
|
VerifyAlgorithm::RsaPss(algorithm) => algorithm.name,
|
|
VerifyAlgorithm::Ecdsa(algorithm) => algorithm.name,
|
|
VerifyAlgorithm::Ed25519(algorithm) => algorithm.name,
|
|
VerifyAlgorithm::Hmac(algorithm) => algorithm.name,
|
|
VerifyAlgorithm::MlDsa(algorithm) => algorithm.name,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl VerifyAlgorithm {
|
|
fn verify(&self, key: &CryptoKey, message: &[u8], signature: &[u8]) -> Result<bool, Error> {
|
|
match self {
|
|
VerifyAlgorithm::RsassaPkcs1V1_5(_algorithm) => {
|
|
rsassa_pkcs1_v1_5_operation::verify(key, message, signature)
|
|
},
|
|
VerifyAlgorithm::RsaPss(algorithm) => {
|
|
rsa_pss_operation::verify(algorithm, key, message, signature)
|
|
},
|
|
VerifyAlgorithm::Ecdsa(algorithm) => {
|
|
ecdsa_operation::verify(algorithm, key, message, signature)
|
|
},
|
|
VerifyAlgorithm::Ed25519(_algorithm) => {
|
|
ed25519_operation::verify(key, message, signature)
|
|
},
|
|
VerifyAlgorithm::Hmac(_algorithm) => hmac_operation::verify(key, message, signature),
|
|
VerifyAlgorithm::MlDsa(algorithm) => {
|
|
ml_dsa_operation::verify(algorithm, key, message, signature)
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The value of the key "digest" in the internal object supportedAlgorithms
|
|
struct DigestOperation {}
|
|
|
|
impl Operation for DigestOperation {
|
|
type RegisteredAlgorithm = DigestAlgorithm;
|
|
}
|
|
|
|
/// Normalized algorithm for the "digest" operation, used as output of
|
|
/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
|
|
#[derive(Clone, MallocSizeOf)]
|
|
enum DigestAlgorithm {
|
|
Sha(SubtleAlgorithm),
|
|
Sha3(SubtleAlgorithm),
|
|
CShake(SubtleCShakeParams),
|
|
}
|
|
|
|
impl NormalizedAlgorithm for DigestAlgorithm {
|
|
fn from_object_value(
|
|
cx: &mut js::context::JSContext,
|
|
algorithm_name: CryptoAlgorithm,
|
|
value: HandleValue,
|
|
) -> Fallible<Self> {
|
|
match algorithm_name {
|
|
CryptoAlgorithm::Sha1 |
|
|
CryptoAlgorithm::Sha256 |
|
|
CryptoAlgorithm::Sha384 |
|
|
CryptoAlgorithm::Sha512 => Ok(DigestAlgorithm::Sha(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::Sha3_256 | CryptoAlgorithm::Sha3_384 | CryptoAlgorithm::Sha3_512 => {
|
|
Ok(DigestAlgorithm::Sha3(value.try_into_with_cx(cx)?))
|
|
},
|
|
CryptoAlgorithm::CShake128 | CryptoAlgorithm::CShake256 => {
|
|
Ok(DigestAlgorithm::CShake(value.try_into_with_cx(cx)?))
|
|
},
|
|
_ => Err(Error::NotSupported(Some(format!(
|
|
"{} does not support \"digest\" operation",
|
|
algorithm_name.as_str()
|
|
)))),
|
|
}
|
|
}
|
|
|
|
fn name(&self) -> CryptoAlgorithm {
|
|
match self {
|
|
DigestAlgorithm::Sha(algorithm) => algorithm.name,
|
|
DigestAlgorithm::Sha3(algorithm) => algorithm.name,
|
|
DigestAlgorithm::CShake(algorithm) => algorithm.name,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl DigestAlgorithm {
|
|
fn digest(&self, message: &[u8]) -> Result<Vec<u8>, Error> {
|
|
match self {
|
|
DigestAlgorithm::Sha(algorithm) => sha_operation::digest(algorithm, message),
|
|
DigestAlgorithm::Sha3(algorithm) => sha3_operation::digest(algorithm, message),
|
|
DigestAlgorithm::CShake(algorithm) => cshake_operation::digest(algorithm, message),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The value of the key "deriveBits" in the internal object supportedAlgorithms
|
|
struct DeriveBitsOperation {}
|
|
|
|
impl Operation for DeriveBitsOperation {
|
|
type RegisteredAlgorithm = DeriveBitsAlgorithm;
|
|
}
|
|
|
|
/// Normalized algorithm for the "deriveBits" operation, used as output of
|
|
/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
|
|
enum DeriveBitsAlgorithm {
|
|
Ecdh(SubtleEcdhKeyDeriveParams),
|
|
X25519(SubtleEcdhKeyDeriveParams),
|
|
Hkdf(SubtleHkdfParams),
|
|
Pbkdf2(SubtlePbkdf2Params),
|
|
Argon2(SubtleArgon2Params),
|
|
}
|
|
|
|
impl NormalizedAlgorithm for DeriveBitsAlgorithm {
|
|
fn from_object_value(
|
|
cx: &mut js::context::JSContext,
|
|
algorithm_name: CryptoAlgorithm,
|
|
value: HandleValue,
|
|
) -> Fallible<Self> {
|
|
match algorithm_name {
|
|
CryptoAlgorithm::Ecdh => Ok(DeriveBitsAlgorithm::Ecdh(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::X25519 => Ok(DeriveBitsAlgorithm::X25519(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::Hkdf => Ok(DeriveBitsAlgorithm::Hkdf(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::Pbkdf2 => Ok(DeriveBitsAlgorithm::Pbkdf2(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::Argon2D | CryptoAlgorithm::Argon2I | CryptoAlgorithm::Argon2ID => {
|
|
Ok(DeriveBitsAlgorithm::Argon2(value.try_into_with_cx(cx)?))
|
|
},
|
|
_ => Err(Error::NotSupported(Some(format!(
|
|
"{} does not support \"deriveBits\" operation",
|
|
algorithm_name.as_str()
|
|
)))),
|
|
}
|
|
}
|
|
|
|
fn name(&self) -> CryptoAlgorithm {
|
|
match self {
|
|
DeriveBitsAlgorithm::Ecdh(algorithm) => algorithm.name,
|
|
DeriveBitsAlgorithm::X25519(algorithm) => algorithm.name,
|
|
DeriveBitsAlgorithm::Hkdf(algorithm) => algorithm.name,
|
|
DeriveBitsAlgorithm::Pbkdf2(algorithm) => algorithm.name,
|
|
DeriveBitsAlgorithm::Argon2(algorithm) => algorithm.name,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl DeriveBitsAlgorithm {
|
|
fn derive_bits(&self, key: &CryptoKey, length: Option<u32>) -> Result<Vec<u8>, Error> {
|
|
match self {
|
|
DeriveBitsAlgorithm::Ecdh(algorithm) => {
|
|
ecdh_operation::derive_bits(algorithm, key, length)
|
|
},
|
|
DeriveBitsAlgorithm::X25519(algorithm) => {
|
|
x25519_operation::derive_bits(algorithm, key, length)
|
|
},
|
|
DeriveBitsAlgorithm::Hkdf(algorithm) => {
|
|
hkdf_operation::derive_bits(algorithm, key, length)
|
|
},
|
|
DeriveBitsAlgorithm::Pbkdf2(algorithm) => {
|
|
pbkdf2_operation::derive_bits(algorithm, key, length)
|
|
},
|
|
DeriveBitsAlgorithm::Argon2(algorithm) => {
|
|
argon2_operation::derive_bits(algorithm, key, length)
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The value of the key "wrapKey" in the internal object supportedAlgorithms
|
|
struct WrapKeyOperation {}
|
|
|
|
impl Operation for WrapKeyOperation {
|
|
type RegisteredAlgorithm = WrapKeyAlgorithm;
|
|
}
|
|
|
|
/// Normalized algorithm for the "wrapKey" operation, used as output of
|
|
/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
|
|
enum WrapKeyAlgorithm {
|
|
AesKw(SubtleAlgorithm),
|
|
}
|
|
|
|
impl NormalizedAlgorithm for WrapKeyAlgorithm {
|
|
fn from_object_value(
|
|
cx: &mut js::context::JSContext,
|
|
algorithm_name: CryptoAlgorithm,
|
|
value: HandleValue,
|
|
) -> Fallible<Self> {
|
|
match algorithm_name {
|
|
CryptoAlgorithm::AesKw => Ok(WrapKeyAlgorithm::AesKw(value.try_into_with_cx(cx)?)),
|
|
_ => Err(Error::NotSupported(Some(format!(
|
|
"{} does not support \"wrapKey\" operation",
|
|
algorithm_name.as_str()
|
|
)))),
|
|
}
|
|
}
|
|
|
|
fn name(&self) -> CryptoAlgorithm {
|
|
match self {
|
|
WrapKeyAlgorithm::AesKw(algorithm) => algorithm.name,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl WrapKeyAlgorithm {
|
|
fn wrap_key(&self, key: &CryptoKey, plaintext: &[u8]) -> Result<Vec<u8>, Error> {
|
|
match self {
|
|
WrapKeyAlgorithm::AesKw(_algorithm) => aes_kw_operation::wrap_key(key, plaintext),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The value of the key "unwrapKey" in the internal object supportedAlgorithms
|
|
struct UnwrapKeyOperation {}
|
|
|
|
impl Operation for UnwrapKeyOperation {
|
|
type RegisteredAlgorithm = UnwrapKeyAlgorithm;
|
|
}
|
|
|
|
/// Normalized algorithm for the "unwrapKey" operation, used as output of
|
|
/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
|
|
enum UnwrapKeyAlgorithm {
|
|
AesKw(SubtleAlgorithm),
|
|
}
|
|
|
|
impl NormalizedAlgorithm for UnwrapKeyAlgorithm {
|
|
fn from_object_value(
|
|
cx: &mut js::context::JSContext,
|
|
algorithm_name: CryptoAlgorithm,
|
|
value: HandleValue,
|
|
) -> Fallible<Self> {
|
|
match algorithm_name {
|
|
CryptoAlgorithm::AesKw => Ok(UnwrapKeyAlgorithm::AesKw(value.try_into_with_cx(cx)?)),
|
|
_ => Err(Error::NotSupported(Some(format!(
|
|
"{} does not support \"unwrapKey\" operation",
|
|
algorithm_name.as_str()
|
|
)))),
|
|
}
|
|
}
|
|
|
|
fn name(&self) -> CryptoAlgorithm {
|
|
match self {
|
|
UnwrapKeyAlgorithm::AesKw(algorithm) => algorithm.name,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl UnwrapKeyAlgorithm {
|
|
fn unwrap_key(&self, key: &CryptoKey, ciphertext: &[u8]) -> Result<Vec<u8>, Error> {
|
|
match self {
|
|
UnwrapKeyAlgorithm::AesKw(_algorithm) => aes_kw_operation::unwrap_key(key, ciphertext),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The value of the key "unwrapKey" in the internal object supportedAlgorithms
|
|
struct GenerateKeyOperation {}
|
|
|
|
impl Operation for GenerateKeyOperation {
|
|
type RegisteredAlgorithm = GenerateKeyAlgorithm;
|
|
}
|
|
|
|
/// Normalized algorithm for the "generateKey" operation, used as output of
|
|
/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
|
|
enum GenerateKeyAlgorithm {
|
|
RsassaPkcs1V1_5(SubtleRsaHashedKeyGenParams),
|
|
RsaPss(SubtleRsaHashedKeyGenParams),
|
|
RsaOaep(SubtleRsaHashedKeyGenParams),
|
|
Ecdsa(SubtleEcKeyGenParams),
|
|
Ecdh(SubtleEcKeyGenParams),
|
|
Ed25519(SubtleAlgorithm),
|
|
X25519(SubtleAlgorithm),
|
|
AesCtr(SubtleAesKeyGenParams),
|
|
AesCbc(SubtleAesKeyGenParams),
|
|
AesGcm(SubtleAesKeyGenParams),
|
|
AesKw(SubtleAesKeyGenParams),
|
|
Hmac(SubtleHmacKeyGenParams),
|
|
MlKem(SubtleAlgorithm),
|
|
MlDsa(SubtleAlgorithm),
|
|
AesOcb(SubtleAesKeyGenParams),
|
|
ChaCha20Poly1305(SubtleAlgorithm),
|
|
}
|
|
|
|
impl NormalizedAlgorithm for GenerateKeyAlgorithm {
|
|
fn from_object_value(
|
|
cx: &mut js::context::JSContext,
|
|
algorithm_name: CryptoAlgorithm,
|
|
value: HandleValue,
|
|
) -> Fallible<Self> {
|
|
match algorithm_name {
|
|
CryptoAlgorithm::RsassaPkcs1V1_5 => Ok(GenerateKeyAlgorithm::RsassaPkcs1V1_5(
|
|
value.try_into_with_cx(cx)?,
|
|
)),
|
|
CryptoAlgorithm::RsaPss => {
|
|
Ok(GenerateKeyAlgorithm::RsaPss(value.try_into_with_cx(cx)?))
|
|
},
|
|
CryptoAlgorithm::RsaOaep => {
|
|
Ok(GenerateKeyAlgorithm::RsaOaep(value.try_into_with_cx(cx)?))
|
|
},
|
|
CryptoAlgorithm::Ecdsa => Ok(GenerateKeyAlgorithm::Ecdsa(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::Ecdh => Ok(GenerateKeyAlgorithm::Ecdh(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::Ed25519 => {
|
|
Ok(GenerateKeyAlgorithm::Ed25519(value.try_into_with_cx(cx)?))
|
|
},
|
|
CryptoAlgorithm::X25519 => {
|
|
Ok(GenerateKeyAlgorithm::X25519(value.try_into_with_cx(cx)?))
|
|
},
|
|
CryptoAlgorithm::AesCtr => {
|
|
Ok(GenerateKeyAlgorithm::AesCtr(value.try_into_with_cx(cx)?))
|
|
},
|
|
CryptoAlgorithm::AesCbc => {
|
|
Ok(GenerateKeyAlgorithm::AesCbc(value.try_into_with_cx(cx)?))
|
|
},
|
|
CryptoAlgorithm::AesGcm => {
|
|
Ok(GenerateKeyAlgorithm::AesGcm(value.try_into_with_cx(cx)?))
|
|
},
|
|
CryptoAlgorithm::AesKw => Ok(GenerateKeyAlgorithm::AesKw(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::Hmac => Ok(GenerateKeyAlgorithm::Hmac(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::MlKem512 | CryptoAlgorithm::MlKem768 | CryptoAlgorithm::MlKem1024 => {
|
|
Ok(GenerateKeyAlgorithm::MlKem(value.try_into_with_cx(cx)?))
|
|
},
|
|
CryptoAlgorithm::MlDsa44 | CryptoAlgorithm::MlDsa65 | CryptoAlgorithm::MlDsa87 => {
|
|
Ok(GenerateKeyAlgorithm::MlDsa(value.try_into_with_cx(cx)?))
|
|
},
|
|
CryptoAlgorithm::AesOcb => {
|
|
Ok(GenerateKeyAlgorithm::AesOcb(value.try_into_with_cx(cx)?))
|
|
},
|
|
CryptoAlgorithm::ChaCha20Poly1305 => Ok(GenerateKeyAlgorithm::ChaCha20Poly1305(
|
|
value.try_into_with_cx(cx)?,
|
|
)),
|
|
_ => Err(Error::NotSupported(Some(format!(
|
|
"{} does not support \"generateKey\" operation",
|
|
algorithm_name.as_str()
|
|
)))),
|
|
}
|
|
}
|
|
|
|
fn name(&self) -> CryptoAlgorithm {
|
|
match self {
|
|
GenerateKeyAlgorithm::RsassaPkcs1V1_5(algorithm) => algorithm.name,
|
|
GenerateKeyAlgorithm::RsaPss(algorithm) => algorithm.name,
|
|
GenerateKeyAlgorithm::RsaOaep(algorithm) => algorithm.name,
|
|
GenerateKeyAlgorithm::Ecdsa(algorithm) => algorithm.name,
|
|
GenerateKeyAlgorithm::Ecdh(algorithm) => algorithm.name,
|
|
GenerateKeyAlgorithm::Ed25519(algorithm) => algorithm.name,
|
|
GenerateKeyAlgorithm::X25519(algorithm) => algorithm.name,
|
|
GenerateKeyAlgorithm::AesCtr(algorithm) => algorithm.name,
|
|
GenerateKeyAlgorithm::AesCbc(algorithm) => algorithm.name,
|
|
GenerateKeyAlgorithm::AesGcm(algorithm) => algorithm.name,
|
|
GenerateKeyAlgorithm::AesKw(algorithm) => algorithm.name,
|
|
GenerateKeyAlgorithm::Hmac(algorithm) => algorithm.name,
|
|
GenerateKeyAlgorithm::MlKem(algorithm) => algorithm.name,
|
|
GenerateKeyAlgorithm::MlDsa(algorithm) => algorithm.name,
|
|
GenerateKeyAlgorithm::AesOcb(algorithm) => algorithm.name,
|
|
GenerateKeyAlgorithm::ChaCha20Poly1305(algorithm) => algorithm.name,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl GenerateKeyAlgorithm {
|
|
fn generate_key(
|
|
&self,
|
|
cx: &mut js::context::JSContext,
|
|
global: &GlobalScope,
|
|
extractable: bool,
|
|
usages: Vec<KeyUsage>,
|
|
) -> Result<CryptoKeyOrCryptoKeyPair, Error> {
|
|
match self {
|
|
GenerateKeyAlgorithm::RsassaPkcs1V1_5(algorithm) => {
|
|
rsassa_pkcs1_v1_5_operation::generate_key(
|
|
cx,
|
|
global,
|
|
algorithm,
|
|
extractable,
|
|
usages,
|
|
)
|
|
.map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
|
|
},
|
|
GenerateKeyAlgorithm::RsaPss(algorithm) => {
|
|
rsa_pss_operation::generate_key(cx, global, algorithm, extractable, usages)
|
|
.map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
|
|
},
|
|
GenerateKeyAlgorithm::RsaOaep(algorithm) => {
|
|
rsa_oaep_operation::generate_key(cx, global, algorithm, extractable, usages)
|
|
.map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
|
|
},
|
|
GenerateKeyAlgorithm::Ecdsa(algorithm) => {
|
|
ecdsa_operation::generate_key(cx, global, algorithm, extractable, usages)
|
|
.map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
|
|
},
|
|
GenerateKeyAlgorithm::Ecdh(algorithm) => {
|
|
ecdh_operation::generate_key(cx, global, algorithm, extractable, usages)
|
|
.map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
|
|
},
|
|
GenerateKeyAlgorithm::Ed25519(_algorithm) => {
|
|
ed25519_operation::generate_key(cx, global, extractable, usages)
|
|
.map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
|
|
},
|
|
GenerateKeyAlgorithm::X25519(_algorithm) => {
|
|
x25519_operation::generate_key(cx, global, extractable, usages)
|
|
.map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
|
|
},
|
|
GenerateKeyAlgorithm::AesCtr(algorithm) => {
|
|
aes_ctr_operation::generate_key(cx, global, algorithm, extractable, usages)
|
|
.map(CryptoKeyOrCryptoKeyPair::CryptoKey)
|
|
},
|
|
GenerateKeyAlgorithm::AesCbc(algorithm) => {
|
|
aes_cbc_operation::generate_key(cx, global, algorithm, extractable, usages)
|
|
.map(CryptoKeyOrCryptoKeyPair::CryptoKey)
|
|
},
|
|
GenerateKeyAlgorithm::AesGcm(algorithm) => {
|
|
aes_gcm_operation::generate_key(cx, global, algorithm, extractable, usages)
|
|
.map(CryptoKeyOrCryptoKeyPair::CryptoKey)
|
|
},
|
|
GenerateKeyAlgorithm::AesKw(algorithm) => {
|
|
aes_kw_operation::generate_key(cx, global, algorithm, extractable, usages)
|
|
.map(CryptoKeyOrCryptoKeyPair::CryptoKey)
|
|
},
|
|
GenerateKeyAlgorithm::Hmac(algorithm) => {
|
|
hmac_operation::generate_key(cx, global, algorithm, extractable, usages)
|
|
.map(CryptoKeyOrCryptoKeyPair::CryptoKey)
|
|
},
|
|
GenerateKeyAlgorithm::MlKem(algorithm) => {
|
|
ml_kem_operation::generate_key(cx, global, algorithm, extractable, usages)
|
|
.map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
|
|
},
|
|
GenerateKeyAlgorithm::MlDsa(algorithm) => {
|
|
ml_dsa_operation::generate_key(cx, global, algorithm, extractable, usages)
|
|
.map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
|
|
},
|
|
GenerateKeyAlgorithm::AesOcb(algorithm) => {
|
|
aes_ocb_operation::generate_key(cx, global, algorithm, extractable, usages)
|
|
.map(CryptoKeyOrCryptoKeyPair::CryptoKey)
|
|
},
|
|
GenerateKeyAlgorithm::ChaCha20Poly1305(_algorithm) => {
|
|
chacha20_poly1305_operation::generate_key(cx, global, extractable, usages)
|
|
.map(CryptoKeyOrCryptoKeyPair::CryptoKey)
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The value of the key "importKey" in the internal object supportedAlgorithms
|
|
struct ImportKeyOperation {}
|
|
|
|
impl Operation for ImportKeyOperation {
|
|
type RegisteredAlgorithm = ImportKeyAlgorithm;
|
|
}
|
|
|
|
/// Normalized algorithm for the "importKey" operation, used as output of
|
|
/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
|
|
enum ImportKeyAlgorithm {
|
|
RsassaPkcs1V1_5(SubtleRsaHashedImportParams),
|
|
RsaPss(SubtleRsaHashedImportParams),
|
|
RsaOaep(SubtleRsaHashedImportParams),
|
|
Ecdsa(SubtleEcKeyImportParams),
|
|
Ecdh(SubtleEcKeyImportParams),
|
|
Ed25519(SubtleAlgorithm),
|
|
X25519(SubtleAlgorithm),
|
|
AesCtr(SubtleAlgorithm),
|
|
AesCbc(SubtleAlgorithm),
|
|
AesGcm(SubtleAlgorithm),
|
|
AesKw(SubtleAlgorithm),
|
|
Hmac(SubtleHmacImportParams),
|
|
Hkdf(SubtleAlgorithm),
|
|
Pbkdf2(SubtleAlgorithm),
|
|
MlKem(SubtleAlgorithm),
|
|
MlDsa(SubtleAlgorithm),
|
|
AesOcb(SubtleAlgorithm),
|
|
ChaCha20Poly1305(SubtleAlgorithm),
|
|
Argon2(SubtleAlgorithm),
|
|
}
|
|
|
|
impl NormalizedAlgorithm for ImportKeyAlgorithm {
|
|
fn from_object_value(
|
|
cx: &mut js::context::JSContext,
|
|
algorithm_name: CryptoAlgorithm,
|
|
value: HandleValue,
|
|
) -> Fallible<Self> {
|
|
match algorithm_name {
|
|
CryptoAlgorithm::RsassaPkcs1V1_5 => Ok(ImportKeyAlgorithm::RsassaPkcs1V1_5(
|
|
value.try_into_with_cx(cx)?,
|
|
)),
|
|
CryptoAlgorithm::RsaPss => Ok(ImportKeyAlgorithm::RsaPss(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::RsaOaep => {
|
|
Ok(ImportKeyAlgorithm::RsaOaep(value.try_into_with_cx(cx)?))
|
|
},
|
|
CryptoAlgorithm::Ecdsa => Ok(ImportKeyAlgorithm::Ecdsa(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::Ecdh => Ok(ImportKeyAlgorithm::Ecdh(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::Ed25519 => {
|
|
Ok(ImportKeyAlgorithm::Ed25519(value.try_into_with_cx(cx)?))
|
|
},
|
|
CryptoAlgorithm::X25519 => Ok(ImportKeyAlgorithm::X25519(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::AesCtr => Ok(ImportKeyAlgorithm::AesCtr(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::AesCbc => Ok(ImportKeyAlgorithm::AesCbc(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::AesGcm => Ok(ImportKeyAlgorithm::AesGcm(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::AesKw => Ok(ImportKeyAlgorithm::AesKw(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::Hmac => Ok(ImportKeyAlgorithm::Hmac(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::Hkdf => Ok(ImportKeyAlgorithm::Hkdf(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::Pbkdf2 => Ok(ImportKeyAlgorithm::Pbkdf2(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::MlKem512 | CryptoAlgorithm::MlKem768 | CryptoAlgorithm::MlKem1024 => {
|
|
Ok(ImportKeyAlgorithm::MlKem(value.try_into_with_cx(cx)?))
|
|
},
|
|
CryptoAlgorithm::MlDsa44 | CryptoAlgorithm::MlDsa65 | CryptoAlgorithm::MlDsa87 => {
|
|
Ok(ImportKeyAlgorithm::MlDsa(value.try_into_with_cx(cx)?))
|
|
},
|
|
CryptoAlgorithm::AesOcb => Ok(ImportKeyAlgorithm::AesOcb(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::ChaCha20Poly1305 => Ok(ImportKeyAlgorithm::ChaCha20Poly1305(
|
|
value.try_into_with_cx(cx)?,
|
|
)),
|
|
CryptoAlgorithm::Argon2D | CryptoAlgorithm::Argon2I | CryptoAlgorithm::Argon2ID => {
|
|
Ok(ImportKeyAlgorithm::Argon2(value.try_into_with_cx(cx)?))
|
|
},
|
|
_ => Err(Error::NotSupported(Some(format!(
|
|
"{} does not support \"importKey\" operation",
|
|
algorithm_name.as_str()
|
|
)))),
|
|
}
|
|
}
|
|
|
|
fn name(&self) -> CryptoAlgorithm {
|
|
match self {
|
|
ImportKeyAlgorithm::RsassaPkcs1V1_5(algorithm) => algorithm.name,
|
|
ImportKeyAlgorithm::RsaPss(algorithm) => algorithm.name,
|
|
ImportKeyAlgorithm::RsaOaep(algorithm) => algorithm.name,
|
|
ImportKeyAlgorithm::Ecdsa(algorithm) => algorithm.name,
|
|
ImportKeyAlgorithm::Ecdh(algorithm) => algorithm.name,
|
|
ImportKeyAlgorithm::Ed25519(algorithm) => algorithm.name,
|
|
ImportKeyAlgorithm::X25519(algorithm) => algorithm.name,
|
|
ImportKeyAlgorithm::AesCtr(algorithm) => algorithm.name,
|
|
ImportKeyAlgorithm::AesCbc(algorithm) => algorithm.name,
|
|
ImportKeyAlgorithm::AesGcm(algorithm) => algorithm.name,
|
|
ImportKeyAlgorithm::AesKw(algorithm) => algorithm.name,
|
|
ImportKeyAlgorithm::Hmac(algorithm) => algorithm.name,
|
|
ImportKeyAlgorithm::Hkdf(algorithm) => algorithm.name,
|
|
ImportKeyAlgorithm::Pbkdf2(algorithm) => algorithm.name,
|
|
ImportKeyAlgorithm::MlKem(algorithm) => algorithm.name,
|
|
ImportKeyAlgorithm::MlDsa(algorithm) => algorithm.name,
|
|
ImportKeyAlgorithm::AesOcb(algorithm) => algorithm.name,
|
|
ImportKeyAlgorithm::ChaCha20Poly1305(algorithm) => algorithm.name,
|
|
ImportKeyAlgorithm::Argon2(algorithm) => algorithm.name,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ImportKeyAlgorithm {
|
|
fn import_key(
|
|
&self,
|
|
cx: &mut js::context::JSContext,
|
|
global: &GlobalScope,
|
|
format: KeyFormat,
|
|
key_data: &[u8],
|
|
extractable: bool,
|
|
usages: Vec<KeyUsage>,
|
|
) -> Result<DomRoot<CryptoKey>, Error> {
|
|
match self {
|
|
ImportKeyAlgorithm::RsassaPkcs1V1_5(algorithm) => {
|
|
rsassa_pkcs1_v1_5_operation::import_key(
|
|
cx,
|
|
global,
|
|
algorithm,
|
|
format,
|
|
key_data,
|
|
extractable,
|
|
usages,
|
|
)
|
|
},
|
|
ImportKeyAlgorithm::RsaPss(algorithm) => rsa_pss_operation::import_key(
|
|
cx,
|
|
global,
|
|
algorithm,
|
|
format,
|
|
key_data,
|
|
extractable,
|
|
usages,
|
|
),
|
|
ImportKeyAlgorithm::RsaOaep(algorithm) => rsa_oaep_operation::import_key(
|
|
cx,
|
|
global,
|
|
algorithm,
|
|
format,
|
|
key_data,
|
|
extractable,
|
|
usages,
|
|
),
|
|
ImportKeyAlgorithm::Ecdsa(algorithm) => ecdsa_operation::import_key(
|
|
cx,
|
|
global,
|
|
algorithm,
|
|
format,
|
|
key_data,
|
|
extractable,
|
|
usages,
|
|
),
|
|
ImportKeyAlgorithm::Ecdh(algorithm) => ecdh_operation::import_key(
|
|
cx,
|
|
global,
|
|
algorithm,
|
|
format,
|
|
key_data,
|
|
extractable,
|
|
usages,
|
|
),
|
|
ImportKeyAlgorithm::Ed25519(_algorithm) => {
|
|
ed25519_operation::import_key(cx, global, format, key_data, extractable, usages)
|
|
},
|
|
ImportKeyAlgorithm::X25519(_algorithm) => {
|
|
x25519_operation::import_key(cx, global, format, key_data, extractable, usages)
|
|
},
|
|
ImportKeyAlgorithm::AesCtr(_algorithm) => {
|
|
aes_ctr_operation::import_key(cx, global, format, key_data, extractable, usages)
|
|
},
|
|
ImportKeyAlgorithm::AesCbc(_algorithm) => {
|
|
aes_cbc_operation::import_key(cx, global, format, key_data, extractable, usages)
|
|
},
|
|
ImportKeyAlgorithm::AesGcm(_algorithm) => {
|
|
aes_gcm_operation::import_key(cx, global, format, key_data, extractable, usages)
|
|
},
|
|
ImportKeyAlgorithm::AesKw(_algorithm) => {
|
|
aes_kw_operation::import_key(cx, global, format, key_data, extractable, usages)
|
|
},
|
|
ImportKeyAlgorithm::Hmac(algorithm) => hmac_operation::import_key(
|
|
cx,
|
|
global,
|
|
algorithm,
|
|
format,
|
|
key_data,
|
|
extractable,
|
|
usages,
|
|
),
|
|
ImportKeyAlgorithm::Hkdf(_algorithm) => {
|
|
hkdf_operation::import_key(cx, global, format, key_data, extractable, usages)
|
|
},
|
|
ImportKeyAlgorithm::Pbkdf2(_algorithm) => {
|
|
pbkdf2_operation::import_key(cx, global, format, key_data, extractable, usages)
|
|
},
|
|
ImportKeyAlgorithm::MlKem(algorithm) => ml_kem_operation::import_key(
|
|
cx,
|
|
global,
|
|
algorithm,
|
|
format,
|
|
key_data,
|
|
extractable,
|
|
usages,
|
|
),
|
|
ImportKeyAlgorithm::MlDsa(algorithm) => ml_dsa_operation::import_key(
|
|
cx,
|
|
global,
|
|
algorithm,
|
|
format,
|
|
key_data,
|
|
extractable,
|
|
usages,
|
|
),
|
|
ImportKeyAlgorithm::AesOcb(_algorithm) => {
|
|
aes_ocb_operation::import_key(cx, global, format, key_data, extractable, usages)
|
|
},
|
|
ImportKeyAlgorithm::ChaCha20Poly1305(_algorithm) => {
|
|
chacha20_poly1305_operation::import_key(
|
|
cx,
|
|
global,
|
|
format,
|
|
key_data,
|
|
extractable,
|
|
usages,
|
|
)
|
|
},
|
|
ImportKeyAlgorithm::Argon2(algorithm) => argon2_operation::import_key(
|
|
cx,
|
|
global,
|
|
algorithm,
|
|
format,
|
|
key_data,
|
|
extractable,
|
|
usages,
|
|
),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The value of the key "exportKey" in the internal object supportedAlgorithms
|
|
struct ExportKeyOperation {}
|
|
|
|
impl Operation for ExportKeyOperation {
|
|
type RegisteredAlgorithm = ExportKeyAlgorithm;
|
|
}
|
|
|
|
/// Normalized algorithm for the "exportKey" operation, used as output of
|
|
/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
|
|
enum ExportKeyAlgorithm {
|
|
RsassaPkcs1V1_5(SubtleAlgorithm),
|
|
RsaPss(SubtleAlgorithm),
|
|
RsaOaep(SubtleAlgorithm),
|
|
Ecdsa(SubtleAlgorithm),
|
|
Ecdh(SubtleAlgorithm),
|
|
Ed25519(SubtleAlgorithm),
|
|
X25519(SubtleAlgorithm),
|
|
AesCtr(SubtleAlgorithm),
|
|
AesCbc(SubtleAlgorithm),
|
|
AesGcm(SubtleAlgorithm),
|
|
AesKw(SubtleAlgorithm),
|
|
Hmac(SubtleAlgorithm),
|
|
MlKem(SubtleAlgorithm),
|
|
MlDsa(SubtleAlgorithm),
|
|
AesOcb(SubtleAlgorithm),
|
|
ChaCha20Poly1305(SubtleAlgorithm),
|
|
}
|
|
|
|
impl NormalizedAlgorithm for ExportKeyAlgorithm {
|
|
fn from_object_value(
|
|
cx: &mut js::context::JSContext,
|
|
algorithm_name: CryptoAlgorithm,
|
|
value: HandleValue,
|
|
) -> Fallible<Self> {
|
|
match algorithm_name {
|
|
CryptoAlgorithm::RsassaPkcs1V1_5 => Ok(ExportKeyAlgorithm::RsassaPkcs1V1_5(
|
|
value.try_into_with_cx(cx)?,
|
|
)),
|
|
CryptoAlgorithm::RsaPss => Ok(ExportKeyAlgorithm::RsaPss(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::RsaOaep => {
|
|
Ok(ExportKeyAlgorithm::RsaOaep(value.try_into_with_cx(cx)?))
|
|
},
|
|
CryptoAlgorithm::Ecdsa => Ok(ExportKeyAlgorithm::Ecdsa(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::Ecdh => Ok(ExportKeyAlgorithm::Ecdh(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::Ed25519 => {
|
|
Ok(ExportKeyAlgorithm::Ed25519(value.try_into_with_cx(cx)?))
|
|
},
|
|
CryptoAlgorithm::X25519 => Ok(ExportKeyAlgorithm::X25519(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::AesCtr => Ok(ExportKeyAlgorithm::AesCtr(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::AesCbc => Ok(ExportKeyAlgorithm::AesCbc(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::AesGcm => Ok(ExportKeyAlgorithm::AesGcm(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::AesKw => Ok(ExportKeyAlgorithm::AesKw(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::Hmac => Ok(ExportKeyAlgorithm::Hmac(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::MlKem512 | CryptoAlgorithm::MlKem768 | CryptoAlgorithm::MlKem1024 => {
|
|
Ok(ExportKeyAlgorithm::MlKem(value.try_into_with_cx(cx)?))
|
|
},
|
|
CryptoAlgorithm::MlDsa44 | CryptoAlgorithm::MlDsa65 | CryptoAlgorithm::MlDsa87 => {
|
|
Ok(ExportKeyAlgorithm::MlDsa(value.try_into_with_cx(cx)?))
|
|
},
|
|
CryptoAlgorithm::AesOcb => Ok(ExportKeyAlgorithm::AesOcb(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::ChaCha20Poly1305 => Ok(ExportKeyAlgorithm::ChaCha20Poly1305(
|
|
value.try_into_with_cx(cx)?,
|
|
)),
|
|
_ => Err(Error::NotSupported(Some(format!(
|
|
"{} does not support \"exportKey\" operation",
|
|
algorithm_name.as_str()
|
|
)))),
|
|
}
|
|
}
|
|
|
|
fn name(&self) -> CryptoAlgorithm {
|
|
match self {
|
|
ExportKeyAlgorithm::RsassaPkcs1V1_5(algorithm) => algorithm.name,
|
|
ExportKeyAlgorithm::RsaPss(algorithm) => algorithm.name,
|
|
ExportKeyAlgorithm::RsaOaep(algorithm) => algorithm.name,
|
|
ExportKeyAlgorithm::Ecdsa(algorithm) => algorithm.name,
|
|
ExportKeyAlgorithm::Ecdh(algorithm) => algorithm.name,
|
|
ExportKeyAlgorithm::Ed25519(algorithm) => algorithm.name,
|
|
ExportKeyAlgorithm::X25519(algorithm) => algorithm.name,
|
|
ExportKeyAlgorithm::AesCtr(algorithm) => algorithm.name,
|
|
ExportKeyAlgorithm::AesCbc(algorithm) => algorithm.name,
|
|
ExportKeyAlgorithm::AesGcm(algorithm) => algorithm.name,
|
|
ExportKeyAlgorithm::AesKw(algorithm) => algorithm.name,
|
|
ExportKeyAlgorithm::Hmac(algorithm) => algorithm.name,
|
|
ExportKeyAlgorithm::MlKem(algorithm) => algorithm.name,
|
|
ExportKeyAlgorithm::MlDsa(algorithm) => algorithm.name,
|
|
ExportKeyAlgorithm::AesOcb(algorithm) => algorithm.name,
|
|
ExportKeyAlgorithm::ChaCha20Poly1305(algorithm) => algorithm.name,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ExportKeyAlgorithm {
|
|
fn export_key(&self, format: KeyFormat, key: &CryptoKey) -> Result<ExportedKey, Error> {
|
|
match self {
|
|
ExportKeyAlgorithm::RsassaPkcs1V1_5(_algorithm) => {
|
|
rsassa_pkcs1_v1_5_operation::export_key(format, key)
|
|
},
|
|
ExportKeyAlgorithm::RsaPss(_algorithm) => rsa_pss_operation::export_key(format, key),
|
|
ExportKeyAlgorithm::RsaOaep(_algorithm) => rsa_oaep_operation::export_key(format, key),
|
|
ExportKeyAlgorithm::Ecdsa(_algorithm) => ecdsa_operation::export_key(format, key),
|
|
ExportKeyAlgorithm::Ecdh(_algorithm) => ecdh_operation::export_key(format, key),
|
|
ExportKeyAlgorithm::Ed25519(_algorithm) => ed25519_operation::export_key(format, key),
|
|
ExportKeyAlgorithm::X25519(_algorithm) => x25519_operation::export_key(format, key),
|
|
ExportKeyAlgorithm::AesCtr(_algorithm) => aes_ctr_operation::export_key(format, key),
|
|
ExportKeyAlgorithm::AesCbc(_algorithm) => aes_cbc_operation::export_key(format, key),
|
|
ExportKeyAlgorithm::AesGcm(_algorithm) => aes_gcm_operation::export_key(format, key),
|
|
ExportKeyAlgorithm::AesKw(_algorithm) => aes_kw_operation::export_key(format, key),
|
|
ExportKeyAlgorithm::Hmac(_algorithm) => hmac_operation::export_key(format, key),
|
|
ExportKeyAlgorithm::MlKem(_algorithm) => ml_kem_operation::export_key(format, key),
|
|
ExportKeyAlgorithm::MlDsa(_algorithm) => ml_dsa_operation::export_key(format, key),
|
|
ExportKeyAlgorithm::AesOcb(_algorithm) => aes_ocb_operation::export_key(format, key),
|
|
ExportKeyAlgorithm::ChaCha20Poly1305(_algorithm) => {
|
|
chacha20_poly1305_operation::export_key(format, key)
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The value of the key "get key length" in the internal object supportedAlgorithms
|
|
struct GetKeyLengthOperation {}
|
|
|
|
impl Operation for GetKeyLengthOperation {
|
|
type RegisteredAlgorithm = GetKeyLengthAlgorithm;
|
|
}
|
|
|
|
/// Normalized algorithm for the "get key length" operation, used as output of
|
|
/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
|
|
enum GetKeyLengthAlgorithm {
|
|
AesCtr(SubtleAesDerivedKeyParams),
|
|
AesCbc(SubtleAesDerivedKeyParams),
|
|
AesGcm(SubtleAesDerivedKeyParams),
|
|
AesKw(SubtleAesDerivedKeyParams),
|
|
Hmac(SubtleHmacImportParams),
|
|
Hkdf(SubtleAlgorithm),
|
|
Pbkdf2(SubtleAlgorithm),
|
|
AesOcb(SubtleAesDerivedKeyParams),
|
|
ChaCha20Poly1305(SubtleAlgorithm),
|
|
Argon2(SubtleAlgorithm),
|
|
}
|
|
|
|
impl NormalizedAlgorithm for GetKeyLengthAlgorithm {
|
|
fn from_object_value(
|
|
cx: &mut js::context::JSContext,
|
|
algorithm_name: CryptoAlgorithm,
|
|
value: HandleValue,
|
|
) -> Fallible<Self> {
|
|
match algorithm_name {
|
|
CryptoAlgorithm::AesCtr => {
|
|
Ok(GetKeyLengthAlgorithm::AesCtr(value.try_into_with_cx(cx)?))
|
|
},
|
|
CryptoAlgorithm::AesCbc => {
|
|
Ok(GetKeyLengthAlgorithm::AesCbc(value.try_into_with_cx(cx)?))
|
|
},
|
|
CryptoAlgorithm::AesGcm => {
|
|
Ok(GetKeyLengthAlgorithm::AesGcm(value.try_into_with_cx(cx)?))
|
|
},
|
|
CryptoAlgorithm::AesKw => Ok(GetKeyLengthAlgorithm::AesKw(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::Hmac => Ok(GetKeyLengthAlgorithm::Hmac(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::Hkdf => Ok(GetKeyLengthAlgorithm::Hkdf(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::Pbkdf2 => {
|
|
Ok(GetKeyLengthAlgorithm::Pbkdf2(value.try_into_with_cx(cx)?))
|
|
},
|
|
CryptoAlgorithm::AesOcb => {
|
|
Ok(GetKeyLengthAlgorithm::AesOcb(value.try_into_with_cx(cx)?))
|
|
},
|
|
CryptoAlgorithm::ChaCha20Poly1305 => Ok(GetKeyLengthAlgorithm::ChaCha20Poly1305(
|
|
value.try_into_with_cx(cx)?,
|
|
)),
|
|
CryptoAlgorithm::Argon2D | CryptoAlgorithm::Argon2I | CryptoAlgorithm::Argon2ID => {
|
|
Ok(GetKeyLengthAlgorithm::Argon2(value.try_into_with_cx(cx)?))
|
|
},
|
|
_ => Err(Error::NotSupported(Some(format!(
|
|
"{} does not support \"get key length\" operation",
|
|
algorithm_name.as_str()
|
|
)))),
|
|
}
|
|
}
|
|
|
|
fn name(&self) -> CryptoAlgorithm {
|
|
match self {
|
|
GetKeyLengthAlgorithm::AesCtr(algorithm) => algorithm.name,
|
|
GetKeyLengthAlgorithm::AesCbc(algorithm) => algorithm.name,
|
|
GetKeyLengthAlgorithm::AesGcm(algorithm) => algorithm.name,
|
|
GetKeyLengthAlgorithm::AesKw(algorithm) => algorithm.name,
|
|
GetKeyLengthAlgorithm::Hmac(algorithm) => algorithm.name,
|
|
GetKeyLengthAlgorithm::Hkdf(algorithm) => algorithm.name,
|
|
GetKeyLengthAlgorithm::Pbkdf2(algorithm) => algorithm.name,
|
|
GetKeyLengthAlgorithm::AesOcb(algorithm) => algorithm.name,
|
|
GetKeyLengthAlgorithm::ChaCha20Poly1305(algorithm) => algorithm.name,
|
|
GetKeyLengthAlgorithm::Argon2(algorithm) => algorithm.name,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl GetKeyLengthAlgorithm {
|
|
fn get_key_length(&self) -> Result<Option<u32>, Error> {
|
|
match self {
|
|
GetKeyLengthAlgorithm::AesCtr(algorithm) => {
|
|
aes_ctr_operation::get_key_length(algorithm)
|
|
},
|
|
GetKeyLengthAlgorithm::AesCbc(algorithm) => {
|
|
aes_cbc_operation::get_key_length(algorithm)
|
|
},
|
|
GetKeyLengthAlgorithm::AesGcm(algorithm) => {
|
|
aes_gcm_operation::get_key_length(algorithm)
|
|
},
|
|
GetKeyLengthAlgorithm::AesKw(algorithm) => aes_kw_operation::get_key_length(algorithm),
|
|
GetKeyLengthAlgorithm::Hmac(algorithm) => hmac_operation::get_key_length(algorithm),
|
|
GetKeyLengthAlgorithm::Hkdf(_algorithm) => hkdf_operation::get_key_length(),
|
|
GetKeyLengthAlgorithm::Pbkdf2(_algorithm) => pbkdf2_operation::get_key_length(),
|
|
GetKeyLengthAlgorithm::AesOcb(algorithm) => {
|
|
aes_ocb_operation::get_key_length(algorithm)
|
|
},
|
|
GetKeyLengthAlgorithm::ChaCha20Poly1305(_algorithm) => {
|
|
chacha20_poly1305_operation::get_key_length()
|
|
},
|
|
GetKeyLengthAlgorithm::Argon2(_algorithm) => argon2_operation::get_key_length(),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The value of the key "encapsulate" in the internal object supportedAlgorithms
|
|
struct EncapsulateOperation {}
|
|
|
|
impl Operation for EncapsulateOperation {
|
|
type RegisteredAlgorithm = EncapsulateAlgorithm;
|
|
}
|
|
|
|
/// Normalized algorithm for the "encapsulate" operation, used as output of
|
|
/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
|
|
enum EncapsulateAlgorithm {
|
|
MlKem(SubtleAlgorithm),
|
|
}
|
|
|
|
impl NormalizedAlgorithm for EncapsulateAlgorithm {
|
|
fn from_object_value(
|
|
cx: &mut js::context::JSContext,
|
|
algorithm_name: CryptoAlgorithm,
|
|
value: HandleValue,
|
|
) -> Fallible<Self> {
|
|
match algorithm_name {
|
|
CryptoAlgorithm::MlKem512 | CryptoAlgorithm::MlKem768 | CryptoAlgorithm::MlKem1024 => {
|
|
Ok(EncapsulateAlgorithm::MlKem(value.try_into_with_cx(cx)?))
|
|
},
|
|
_ => Err(Error::NotSupported(Some(format!(
|
|
"{} does not support \"encapsulate\" operation",
|
|
algorithm_name.as_str()
|
|
)))),
|
|
}
|
|
}
|
|
|
|
fn name(&self) -> CryptoAlgorithm {
|
|
match self {
|
|
EncapsulateAlgorithm::MlKem(algorithm) => algorithm.name,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl EncapsulateAlgorithm {
|
|
fn encapsulate(&self, key: &CryptoKey) -> Result<SubtleEncapsulatedBits, Error> {
|
|
match self {
|
|
EncapsulateAlgorithm::MlKem(algorithm) => ml_kem_operation::encapsulate(algorithm, key),
|
|
}
|
|
}
|
|
}
|
|
|
|
// The value of the key "decapsulate" in the internal object supportedAlgorithms
|
|
struct DecapsulateOperation {}
|
|
|
|
impl Operation for DecapsulateOperation {
|
|
type RegisteredAlgorithm = DecapsulateAlgorithm;
|
|
}
|
|
|
|
/// Normalized algorithm for the "decapsulate" operation, used as output of
|
|
/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
|
|
enum DecapsulateAlgorithm {
|
|
MlKem(SubtleAlgorithm),
|
|
}
|
|
|
|
impl NormalizedAlgorithm for DecapsulateAlgorithm {
|
|
fn from_object_value(
|
|
cx: &mut js::context::JSContext,
|
|
algorithm_name: CryptoAlgorithm,
|
|
value: HandleValue,
|
|
) -> Fallible<Self> {
|
|
match algorithm_name {
|
|
CryptoAlgorithm::MlKem512 | CryptoAlgorithm::MlKem768 | CryptoAlgorithm::MlKem1024 => {
|
|
Ok(DecapsulateAlgorithm::MlKem(value.try_into_with_cx(cx)?))
|
|
},
|
|
_ => Err(Error::NotSupported(Some(format!(
|
|
"{} does not support \"decapsulate\" operation",
|
|
algorithm_name.as_str()
|
|
)))),
|
|
}
|
|
}
|
|
|
|
fn name(&self) -> CryptoAlgorithm {
|
|
match self {
|
|
DecapsulateAlgorithm::MlKem(algorithm) => algorithm.name,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl DecapsulateAlgorithm {
|
|
fn decapsulate(&self, key: &CryptoKey, ciphertext: &[u8]) -> Result<Vec<u8>, Error> {
|
|
match self {
|
|
DecapsulateAlgorithm::MlKem(algorithm) => {
|
|
ml_kem_operation::decapsulate(algorithm, key, ciphertext)
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
// The value of the key "getPublicKey" in the internal object supportedAlgorithms
|
|
struct GetPublicKeyOperation {}
|
|
|
|
impl Operation for GetPublicKeyOperation {
|
|
type RegisteredAlgorithm = GetPublicKeyAlgorithm;
|
|
}
|
|
|
|
/// Normalized algorithm for the "getPublicKey" operation, used as output of
|
|
/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
|
|
enum GetPublicKeyAlgorithm {
|
|
RsassaPkcs1v1_5(SubtleAlgorithm),
|
|
RsaPss(SubtleAlgorithm),
|
|
RsaOaep(SubtleAlgorithm),
|
|
Ecdsa(SubtleAlgorithm),
|
|
Ecdh(SubtleAlgorithm),
|
|
Ed25519(SubtleAlgorithm),
|
|
X25519(SubtleAlgorithm),
|
|
}
|
|
|
|
impl NormalizedAlgorithm for GetPublicKeyAlgorithm {
|
|
fn from_object_value(
|
|
cx: &mut js::context::JSContext,
|
|
algorithm_name: CryptoAlgorithm,
|
|
value: HandleValue,
|
|
) -> Fallible<Self> {
|
|
match algorithm_name {
|
|
CryptoAlgorithm::RsassaPkcs1V1_5 => Ok(GetPublicKeyAlgorithm::RsassaPkcs1v1_5(
|
|
value.try_into_with_cx(cx)?,
|
|
)),
|
|
CryptoAlgorithm::RsaPss => {
|
|
Ok(GetPublicKeyAlgorithm::RsaPss(value.try_into_with_cx(cx)?))
|
|
},
|
|
CryptoAlgorithm::RsaOaep => {
|
|
Ok(GetPublicKeyAlgorithm::RsaOaep(value.try_into_with_cx(cx)?))
|
|
},
|
|
CryptoAlgorithm::Ecdsa => Ok(GetPublicKeyAlgorithm::Ecdsa(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::Ecdh => Ok(GetPublicKeyAlgorithm::Ecdh(value.try_into_with_cx(cx)?)),
|
|
CryptoAlgorithm::Ed25519 => {
|
|
Ok(GetPublicKeyAlgorithm::Ed25519(value.try_into_with_cx(cx)?))
|
|
},
|
|
CryptoAlgorithm::X25519 => {
|
|
Ok(GetPublicKeyAlgorithm::X25519(value.try_into_with_cx(cx)?))
|
|
},
|
|
_ => Err(Error::NotSupported(Some(format!(
|
|
"{} does not support \"getPublicKey\" operation",
|
|
algorithm_name.as_str()
|
|
)))),
|
|
}
|
|
}
|
|
|
|
fn name(&self) -> CryptoAlgorithm {
|
|
match self {
|
|
GetPublicKeyAlgorithm::RsassaPkcs1v1_5(algorithm) => algorithm.name,
|
|
GetPublicKeyAlgorithm::RsaPss(algorithm) => algorithm.name,
|
|
GetPublicKeyAlgorithm::RsaOaep(algorithm) => algorithm.name,
|
|
GetPublicKeyAlgorithm::Ecdsa(algorithm) => algorithm.name,
|
|
GetPublicKeyAlgorithm::Ecdh(algorithm) => algorithm.name,
|
|
GetPublicKeyAlgorithm::Ed25519(algorithm) => algorithm.name,
|
|
GetPublicKeyAlgorithm::X25519(algorithm) => algorithm.name,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl GetPublicKeyAlgorithm {
|
|
fn get_public_key(
|
|
&self,
|
|
cx: &mut js::context::JSContext,
|
|
global: &GlobalScope,
|
|
key: &CryptoKey,
|
|
algorithm: &KeyAlgorithmAndDerivatives,
|
|
usages: Vec<KeyUsage>,
|
|
) -> Result<DomRoot<CryptoKey>, Error> {
|
|
match self {
|
|
GetPublicKeyAlgorithm::RsassaPkcs1v1_5(_algorithm) => {
|
|
rsassa_pkcs1_v1_5_operation::get_public_key(cx, global, key, algorithm, usages)
|
|
},
|
|
GetPublicKeyAlgorithm::RsaPss(_algorithm) => {
|
|
rsa_pss_operation::get_public_key(cx, global, key, algorithm, usages)
|
|
},
|
|
GetPublicKeyAlgorithm::RsaOaep(_algorithm) => {
|
|
rsa_oaep_operation::get_public_key(cx, global, key, algorithm, usages)
|
|
},
|
|
GetPublicKeyAlgorithm::Ecdsa(_algorithm) => {
|
|
ecdsa_operation::get_public_key(cx, global, key, algorithm, usages)
|
|
},
|
|
GetPublicKeyAlgorithm::Ecdh(_algorithm) => {
|
|
ecdh_operation::get_public_key(cx, global, key, algorithm, usages)
|
|
},
|
|
GetPublicKeyAlgorithm::Ed25519(_algorithm) => {
|
|
ed25519_operation::get_public_key(cx, global, key, algorithm, usages)
|
|
},
|
|
GetPublicKeyAlgorithm::X25519(_algorithm) => {
|
|
x25519_operation::get_public_key(cx, global, key, algorithm, usages)
|
|
},
|
|
}
|
|
}
|
|
}
|