diff options
author | Simon Wülker <simon.wuelker@arcor.de> | 2024-11-18 18:28:24 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-11-18 17:28:24 +0000 |
commit | 2485bd9a63addf6f1523f591801e26716e80b627 (patch) | |
tree | 92f77c23f38cd1a53f82b87cdd92b689bf080146 /components/script/dom | |
parent | 11dfbd6f90bc7bc8b8d7485695548b5ad685d0e1 (diff) | |
download | servo-2485bd9a63addf6f1523f591801e26716e80b627.tar.gz servo-2485bd9a63addf6f1523f591801e26716e80b627.zip |
Implement HMAC key generation (#34278)
* Implement HMAC key generation
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')
-rw-r--r-- | components/script/dom/subtlecrypto.rs | 115 | ||||
-rw-r--r-- | components/script/dom/webidls/SubtleCrypto.webidl | 6 |
2 files changed, 119 insertions, 2 deletions
diff --git a/components/script/dom/subtlecrypto.rs b/components/script/dom/subtlecrypto.rs index 26c415b04c7..dead9657c34 100644 --- a/components/script/dom/subtlecrypto.rs +++ b/components/script/dom/subtlecrypto.rs @@ -27,8 +27,8 @@ use crate::dom::bindings::codegen::Bindings::CryptoKeyBinding::{ }; use crate::dom::bindings::codegen::Bindings::SubtleCryptoBinding::{ AesCbcParams, AesCtrParams, AesDerivedKeyParams, AesKeyAlgorithm, AesKeyGenParams, Algorithm, - AlgorithmIdentifier, HkdfParams, HmacImportParams, HmacKeyAlgorithm, JsonWebKey, KeyAlgorithm, - KeyFormat, Pbkdf2Params, SubtleCryptoMethods, + AlgorithmIdentifier, HkdfParams, HmacImportParams, HmacKeyAlgorithm, HmacKeyGenParams, + JsonWebKey, KeyAlgorithm, KeyFormat, Pbkdf2Params, SubtleCryptoMethods, }; use crate::dom::bindings::codegen::UnionTypes::{ ArrayBufferViewOrArrayBuffer, ArrayBufferViewOrArrayBufferOrJsonWebKey, @@ -986,6 +986,24 @@ impl SubtleHmacImportParams { } } +struct SubtleHmacKeyGenParams { + /// <https://w3c.github.io/webcrypto/#dfn-HmacKeyGenParams-hash> + hash: DigestAlgorithm, + + /// <https://w3c.github.io/webcrypto/#dfn-HmacKeyGenParams-length> + length: Option<u32>, +} + +impl SubtleHmacKeyGenParams { + fn new(cx: JSContext, params: RootedTraceableBox<HmacKeyGenParams>) -> Fallible<Self> { + let hash = normalize_algorithm_for_digest(cx, ¶ms.hash)?; + let params = Self { + hash, + length: params.length, + }; + Ok(params) + } +} /// <https://w3c.github.io/webcrypto/#hkdf-params> #[derive(Clone, Debug)] pub struct SubtleHkdfParams { @@ -1106,6 +1124,7 @@ enum SignatureAlgorithm { /// [`normalize_algorithm`]: https://w3c.github.io/webcrypto/#algorithm-normalization-normalize-an-algorithm enum KeyGenerationAlgorithm { Aes(SubtleAesKeyGenParams), + Hmac(SubtleHmacKeyGenParams), } macro_rules! value_from_js_object { @@ -1307,6 +1326,10 @@ fn normalize_algorithm_for_generate_key( if name.eq_ignore_ascii_case(ALG_AES_CBC) || name.eq_ignore_ascii_case(ALG_AES_CTR) { let params = value_from_js_object!(AesKeyGenParams, cx, value); KeyGenerationAlgorithm::Aes(params.into()) + } else if name.eq_ignore_ascii_case(ALG_HMAC) { + let params = value_from_js_object!(HmacKeyGenParams, cx, value); + let subtle_params = SubtleHmacKeyGenParams::new(cx, params)?; + KeyGenerationAlgorithm::Hmac(subtle_params) } else { return Err(Error::NotSupported); }; @@ -1493,6 +1516,84 @@ impl SubtleCrypto { Ok(crypto_key) } + /// <https://w3c.github.io/webcrypto/#hmac-operations> + #[allow(unsafe_code)] + fn generate_key_hmac( + &self, + usages: Vec<KeyUsage>, + params: &SubtleHmacKeyGenParams, + extractable: bool, + ) -> Result<DomRoot<CryptoKey>, Error> { + // Step 1. If usages contains any entry which is not "sign" or "verify", then throw a SyntaxError. + if usages + .iter() + .any(|usage| !matches!(usage, KeyUsage::Sign | KeyUsage::Verify)) + { + return Err(Error::Syntax); + } + + // Step 2. + let length = match params.length { + // If the length member of normalizedAlgorithm is not present: + None => { + // Let length be the block size in bits of the hash function identified by the + // hash member of normalizedAlgorithm. + params.hash.block_size_in_bits() as u32 + }, + // Otherwise, if the length member of normalizedAlgorithm is non-zero: + Some(length) if length != 0 => { + // Let length be equal to the length member of normalizedAlgorithm. + length + }, + // Otherwise: + _ => { + // throw an OperationError. + return Err(Error::Operation); + }, + }; + + // Step 3. Generate a key of length length bits. + let mut key_data = vec![0; length as usize]; + self.rng.borrow_mut().fill_bytes(&mut key_data); + + // Step 4. If the key generation step fails, then throw an OperationError. + // NOTE: Our key generation is infallible. + + // Step 5. Let key be a new CryptoKey object representing the generated key. + // Step 6. Let algorithm be a new HmacKeyAlgorithm. + // Step 7. Set the name attribute of algorithm to "HMAC". + // Step 8. Let hash be a new KeyAlgorithm. + // Step 9. Set the name attribute of hash to equal the name member of the hash member of normalizedAlgorithm. + // Step 10. Set the hash attribute of algorithm to hash. + // Step 11. Set the [[type]] internal slot of key to "secret". + // Step 12. Set the [[algorithm]] internal slot of key to algorithm. + // Step 13. Set the [[extractable]] internal slot of key to be extractable. + // Step 14. Set the [[usages]] internal slot of key to be usages. + let name = DOMString::from(ALG_HMAC); + let cx = GlobalScope::get_cx(); + rooted!(in(*cx) let mut algorithm_object = unsafe {JS_NewObject(*cx, ptr::null()) }); + assert!(!algorithm_object.is_null()); + HmacKeyAlgorithm::from_length_and_hash( + length, + params.hash, + algorithm_object.handle_mut(), + cx, + ); + + let key = CryptoKey::new( + &self.global(), + KeyType::Secret, + extractable, + name, + algorithm_object.handle(), + usages, + Handle::Hmac(key_data), + ); + + // Step 15. Return key. + Ok(key) + } + /// <https://w3c.github.io/webcrypto/#aes-cbc-operations> /// <https://w3c.github.io/webcrypto/#aes-ctr-operations> #[allow(unsafe_code)] @@ -2005,6 +2106,15 @@ impl DigestAlgorithm { }; Ok(digest::digest(algorithm, data)) } + + fn block_size_in_bits(&self) -> usize { + match self { + Self::Sha1 => 160, + Self::Sha256 => 256, + Self::Sha384 => 384, + Self::Sha512 => 512, + } + } } impl ImportKeyAlgorithm { @@ -2125,6 +2235,7 @@ impl KeyGenerationAlgorithm { ) -> Result<DomRoot<CryptoKey>, Error> { match self { Self::Aes(params) => subtle.generate_key_aes(usages, params, extractable), + Self::Hmac(params) => subtle.generate_key_hmac(usages, params, extractable), } } } diff --git a/components/script/dom/webidls/SubtleCrypto.webidl b/components/script/dom/webidls/SubtleCrypto.webidl index e9a0546ec66..6bd19254885 100644 --- a/components/script/dom/webidls/SubtleCrypto.webidl +++ b/components/script/dom/webidls/SubtleCrypto.webidl @@ -104,6 +104,12 @@ dictionary HmacKeyAlgorithm : KeyAlgorithm { required unsigned long length; }; +// https://w3c.github.io/webcrypto/#dfn-HmacKeyGenParams +dictionary HmacKeyGenParams : Algorithm { + required HashAlgorithmIdentifier hash; + [EnforceRange] unsigned long length; +}; + // https://w3c.github.io/webcrypto/#hkdf-params dictionary HkdfParams : Algorithm { required HashAlgorithmIdentifier hash; |