diff options
author | Simon Wülker <simon.wuelker@arcor.de> | 2024-11-08 13:59:01 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-11-08 12:59:01 +0000 |
commit | 6b94b2c6846b52a94aaee184c1e0d276b8f85887 (patch) | |
tree | 5be2f39b474fae39deffc5087a735fbfb3ab5403 /components/script/dom/subtlecrypto.rs | |
parent | fe58556c0bf37f9f13685c367341d598fcb52d33 (diff) | |
download | servo-6b94b2c6846b52a94aaee184c1e0d276b8f85887.tar.gz servo-6b94b2c6846b52a94aaee184c1e0d276b8f85887.zip |
Implement `subtlecrypto.deriveKey` (#34185)
* Implement NormalizedAlgorithm::get_key_length
This is a minimal implementation, which will make
the DeriveKey operation work for AES-CTR keys in
the future.
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Implement SubtleCrypto.deriveKey
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Update WPT expectations
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
---------
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
Diffstat (limited to 'components/script/dom/subtlecrypto.rs')
-rw-r--r-- | components/script/dom/subtlecrypto.rs | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/components/script/dom/subtlecrypto.rs b/components/script/dom/subtlecrypto.rs index f5e764ca986..64cdae30b8d 100644 --- a/components/script/dom/subtlecrypto.rs +++ b/components/script/dom/subtlecrypto.rs @@ -389,6 +389,137 @@ impl SubtleCryptoMethods for SubtleCrypto { promise } + /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-deriveKey> + fn DeriveKey( + &self, + cx: SafeJSContext, + algorithm: AlgorithmIdentifier, + base_key: &CryptoKey, + derived_key_type: AlgorithmIdentifier, + extractable: bool, + key_usages: Vec<KeyUsage>, + comp: InRealm, + can_gc: CanGc, + ) -> 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. + + // Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to algorithm + // and op set to "deriveBits". + let promise = Promise::new_in_current_realm(comp, can_gc); + let normalized_algorithm = match normalize_algorithm(cx, &algorithm, "deriveBits") { + Ok(algorithm) => algorithm, + Err(e) => { + // Step 3. If an error occurred, return a Promise rejected with normalizedAlgorithm. + promise.reject_error(e); + return promise; + }, + }; + + // Step 4. Let normalizedDerivedKeyAlgorithmImport be the result of normalizing an algorithm, + // with alg set to derivedKeyType and op set to "importKey". + let normalized_derived_key_algorithm_import = + match normalize_algorithm(cx, &derived_key_type, "importKey") { + Ok(algorithm) => algorithm, + Err(e) => { + // Step 5. If an error occurred, return a Promise rejected with normalizedDerivedKeyAlgorithmImport. + promise.reject_error(e); + 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". + let normalized_derived_key_algorithm_length = + match normalize_algorithm(cx, &derived_key_type, "get key length") { + Ok(algorithm) => algorithm, + Err(e) => { + // Step 7. If an error occurred, return a Promise rejected with normalizedDerivedKeyAlgorithmLength. + promise.reject_error(e); + return promise; + }, + }; + + // Step 8. Let promise be a new Promise. + // NOTE: We created the promise earlier, after Step 1. + + // Step 9. Return promise and perform the remaining steps in parallel. + let (task_source, canceller) = self.task_source_with_canceller(); + let trusted_promise = TrustedPromise::new(promise.clone()); + let trusted_base_key = Trusted::new(base_key); + let this = Trusted::new(self); + let _ = task_source.queue_with_canceller( + task!(derive_key: move || { + // Step 10. If the following steps or referenced procedures say to throw an error, reject promise + // with the returned error and then terminate the algorithm. + + // TODO Step 11. If the name member of normalizedAlgorithm is not equal to the name attribute of the # + // [[algorithm]] internal slot of baseKey then throw an InvalidAccessError. + let promise = trusted_promise.root(); + let base_key = trusted_base_key.root(); + let subtle = this.root(); + + // Step 12. 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) { + promise.reject_error(Error::InvalidAccess); + return; + } + + // Step 13. 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(e) => { + promise.reject_error(e); + return; + } + }; + + // Step 14. 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, Some(length as u32)){ + Ok(secret) => secret, + Err(e) => { + promise.reject_error(e); + return; + } + }; + + // Step 15. 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. + let result = normalized_derived_key_algorithm_import.import_key( + &subtle, + KeyFormat::Raw, + &secret, + extractable, + key_usages + ); + let result = match result { + Ok(key) => key, + Err(e) => { + promise.reject_error(e); + 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) && result.usages().is_empty() { + promise.reject_error(Error::Syntax); + return; + } + + // Step 17. Resolve promise with result. + promise.resolve_native(&*result); + }), + &canceller, + ); + + promise + } + /// <https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-deriveBits> fn DeriveBits( &self, @@ -1235,6 +1366,15 @@ impl NormalizedAlgorithm { } } + fn get_key_length(&self) -> Result<u16, Error> { + match self { + Self::AesCtrParams(aes_ctr_params) => { + get_key_length_for_aes(aes_ctr_params.length as u16) + }, + _ => Err(Error::NotSupported), + } + } + fn import_key( &self, subtle: &SubtleCrypto, @@ -1275,3 +1415,15 @@ impl NormalizedAlgorithm { Ok(digest::digest(algorithm, data)) } } + +/// <https://w3c.github.io/webcrypto/#aes-ctr-operations> +fn get_key_length_for_aes(length: u16) -> Result<u16, Error> { + // Step 1. If the length member of normalizedDerivedKeyAlgorithm is not 128, 192 or 256, + // then throw an OperationError. + if !matches!(length, 128 | 192 | 256) { + return Err(Error::Operation); + } + + // Step 2. Return the length member of normalizedDerivedKeyAlgorithm. + Ok(length) +} |