mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
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>
This commit is contained in:
parent
fe58556c0b
commit
6b94b2c684
8 changed files with 159 additions and 13045 deletions
|
@ -428,8 +428,8 @@ DOMInterfaces = {
|
||||||
},
|
},
|
||||||
|
|
||||||
'SubtleCrypto': {
|
'SubtleCrypto': {
|
||||||
'inRealms': ['Encrypt', 'Decrypt', 'GenerateKey', 'DeriveBits', 'Digest', 'ImportKey', 'ExportKey'],
|
'inRealms': ['Encrypt', 'Decrypt', 'GenerateKey', 'DeriveKey', 'DeriveBits', 'Digest', 'ImportKey', 'ExportKey'],
|
||||||
'canGc': ['Encrypt', 'Decrypt', 'GenerateKey', 'DeriveBits', 'Digest', 'ImportKey', 'ExportKey'],
|
'canGc': ['Encrypt', 'Decrypt', 'GenerateKey', 'DeriveKey', 'DeriveBits', 'Digest', 'ImportKey', 'ExportKey'],
|
||||||
},
|
},
|
||||||
|
|
||||||
'SVGElement': {
|
'SVGElement': {
|
||||||
|
|
|
@ -389,6 +389,137 @@ impl SubtleCryptoMethods for SubtleCrypto {
|
||||||
promise
|
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>
|
/// <https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-deriveBits>
|
||||||
fn DeriveBits(
|
fn DeriveBits(
|
||||||
&self,
|
&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(
|
fn import_key(
|
||||||
&self,
|
&self,
|
||||||
subtle: &SubtleCrypto,
|
subtle: &SubtleCrypto,
|
||||||
|
@ -1275,3 +1415,15 @@ impl NormalizedAlgorithm {
|
||||||
Ok(digest::digest(algorithm, data))
|
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)
|
||||||
|
}
|
||||||
|
|
|
@ -39,11 +39,11 @@ interface SubtleCrypto {
|
||||||
Promise<any> generateKey(AlgorithmIdentifier algorithm,
|
Promise<any> generateKey(AlgorithmIdentifier algorithm,
|
||||||
boolean extractable,
|
boolean extractable,
|
||||||
sequence<KeyUsage> keyUsages );
|
sequence<KeyUsage> keyUsages );
|
||||||
// Promise<any> deriveKey(AlgorithmIdentifier algorithm,
|
Promise<any> deriveKey(AlgorithmIdentifier algorithm,
|
||||||
// CryptoKey baseKey,
|
CryptoKey baseKey,
|
||||||
// AlgorithmIdentifier derivedKeyType,
|
AlgorithmIdentifier derivedKeyType,
|
||||||
// boolean extractable,
|
boolean extractable,
|
||||||
// sequence<KeyUsage> keyUsages );
|
sequence<KeyUsage> keyUsages );
|
||||||
Promise<ArrayBuffer> deriveBits(AlgorithmIdentifier algorithm,
|
Promise<ArrayBuffer> deriveBits(AlgorithmIdentifier algorithm,
|
||||||
CryptoKey baseKey,
|
CryptoKey baseKey,
|
||||||
optional unsigned long? length = null);
|
optional unsigned long? length = null);
|
||||||
|
|
|
@ -26,12 +26,6 @@
|
||||||
[X25519 mixed case parameters]
|
[X25519 mixed case parameters]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[X25519 missing public property]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[X25519 public property of algorithm is not a CryptoKey]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[X25519 mismatched algorithms]
|
[X25519 mismatched algorithms]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -77,12 +71,6 @@
|
||||||
[X25519 mixed case parameters]
|
[X25519 mixed case parameters]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[X25519 missing public property]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[X25519 public property of algorithm is not a CryptoKey]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[X25519 mismatched algorithms]
|
[X25519 mismatched algorithms]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -23,12 +23,6 @@
|
||||||
[X448 mixed case parameters]
|
[X448 mixed case parameters]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[X448 missing public property]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[X448 public property of algorithm is not a CryptoKey]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[X448 mismatched algorithms]
|
[X448 mismatched algorithms]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -71,12 +65,6 @@
|
||||||
[X448 mixed case parameters]
|
[X448 mixed case parameters]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[X448 missing public property]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[X448 public property of algorithm is not a CryptoKey]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[X448 mismatched algorithms]
|
[X448 mismatched algorithms]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,6 @@
|
||||||
[P-521 mixed case parameters]
|
[P-521 mixed case parameters]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[P-521 missing public curve]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[P-521 public property of algorithm is not a CryptoKey]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[P-521 mismatched curves]
|
[P-521 mismatched curves]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -35,12 +29,6 @@
|
||||||
[P-256 mixed case parameters]
|
[P-256 mixed case parameters]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[P-256 missing public curve]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[P-256 public property of algorithm is not a CryptoKey]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[P-256 mismatched curves]
|
[P-256 mismatched curves]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -65,12 +53,6 @@
|
||||||
[P-384 mixed case parameters]
|
[P-384 mixed case parameters]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[P-384 missing public curve]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[P-384 public property of algorithm is not a CryptoKey]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[P-384 mismatched curves]
|
[P-384 mismatched curves]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -97,12 +79,6 @@
|
||||||
[P-521 mixed case parameters]
|
[P-521 mixed case parameters]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[P-521 missing public curve]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[P-521 public property of algorithm is not a CryptoKey]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[P-521 mismatched curves]
|
[P-521 mismatched curves]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -127,12 +103,6 @@
|
||||||
[P-256 mixed case parameters]
|
[P-256 mixed case parameters]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[P-256 missing public curve]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[P-256 public property of algorithm is not a CryptoKey]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[P-256 mismatched curves]
|
[P-256 mismatched curves]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -157,12 +127,6 @@
|
||||||
[P-384 mixed case parameters]
|
[P-384 mixed case parameters]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[P-384 missing public curve]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[P-384 public property of algorithm is not a CryptoKey]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[P-384 mismatched curves]
|
[P-384 mismatched curves]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -5,9 +5,6 @@
|
||||||
[SubtleCrypto interface: operation verify(AlgorithmIdentifier, CryptoKey, BufferSource, BufferSource)]
|
[SubtleCrypto interface: operation verify(AlgorithmIdentifier, CryptoKey, BufferSource, BufferSource)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[SubtleCrypto interface: operation deriveKey(AlgorithmIdentifier, CryptoKey, AlgorithmIdentifier, boolean, sequence<KeyUsage>)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[SubtleCrypto interface: operation deriveBits(AlgorithmIdentifier, CryptoKey, unsigned long)]
|
[SubtleCrypto interface: operation deriveBits(AlgorithmIdentifier, CryptoKey, unsigned long)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -29,12 +26,6 @@
|
||||||
[SubtleCrypto interface: calling verify(AlgorithmIdentifier, CryptoKey, BufferSource, BufferSource) on crypto.subtle with too few arguments must throw TypeError]
|
[SubtleCrypto interface: calling verify(AlgorithmIdentifier, CryptoKey, BufferSource, BufferSource) on crypto.subtle with too few arguments must throw TypeError]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[SubtleCrypto interface: crypto.subtle must inherit property "deriveKey(AlgorithmIdentifier, CryptoKey, AlgorithmIdentifier, boolean, sequence<KeyUsage>)" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[SubtleCrypto interface: calling deriveKey(AlgorithmIdentifier, CryptoKey, AlgorithmIdentifier, boolean, sequence<KeyUsage>) on crypto.subtle with too few arguments must throw TypeError]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[SubtleCrypto interface: crypto.subtle must inherit property "deriveBits(AlgorithmIdentifier, CryptoKey, unsigned long)" with the proper type]
|
[SubtleCrypto interface: crypto.subtle must inherit property "deriveBits(AlgorithmIdentifier, CryptoKey, unsigned long)" with the proper type]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -61,9 +52,6 @@
|
||||||
[SubtleCrypto interface: operation verify(AlgorithmIdentifier, CryptoKey, BufferSource, BufferSource)]
|
[SubtleCrypto interface: operation verify(AlgorithmIdentifier, CryptoKey, BufferSource, BufferSource)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[SubtleCrypto interface: operation deriveKey(AlgorithmIdentifier, CryptoKey, AlgorithmIdentifier, boolean, sequence<KeyUsage>)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[SubtleCrypto interface: operation deriveBits(AlgorithmIdentifier, CryptoKey, unsigned long)]
|
[SubtleCrypto interface: operation deriveBits(AlgorithmIdentifier, CryptoKey, unsigned long)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -85,12 +73,6 @@
|
||||||
[SubtleCrypto interface: calling verify(AlgorithmIdentifier, CryptoKey, BufferSource, BufferSource) on crypto.subtle with too few arguments must throw TypeError]
|
[SubtleCrypto interface: calling verify(AlgorithmIdentifier, CryptoKey, BufferSource, BufferSource) on crypto.subtle with too few arguments must throw TypeError]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[SubtleCrypto interface: crypto.subtle must inherit property "deriveKey(AlgorithmIdentifier, CryptoKey, AlgorithmIdentifier, boolean, sequence<KeyUsage>)" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[SubtleCrypto interface: calling deriveKey(AlgorithmIdentifier, CryptoKey, AlgorithmIdentifier, boolean, sequence<KeyUsage>) on crypto.subtle with too few arguments must throw TypeError]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[SubtleCrypto interface: crypto.subtle must inherit property "deriveBits(AlgorithmIdentifier, CryptoKey, unsigned long)" with the proper type]
|
[SubtleCrypto interface: crypto.subtle must inherit property "deriveBits(AlgorithmIdentifier, CryptoKey, unsigned long)" with the proper type]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue