diff --git a/crates/obscura-js/js/bootstrap.js b/crates/obscura-js/js/bootstrap.js index 7db7e80..f364f54 100644 --- a/crates/obscura-js/js/bootstrap.js +++ b/crates/obscura-js/js/bootstrap.js @@ -6420,13 +6420,10 @@ if (!globalThis.crypto) globalThis.crypto = {}; if (!globalThis.crypto.subtle) { globalThis.crypto.subtle = { async digest(algorithm, data) { - // Real WebCrypto digest. Delegates to `op_subtle_digest` which runs - // the actual SHA-1/256/384/512 via Rust's `sha1` and `sha2` crates. - // The previous JS implementation was a custom FNV variant that - // produced bytes shaped like the hash but with wrong contents, so - // SRI checks, JWS signature verification, and OAuth PKCE silently - // accepted invalid input. - const name = (typeof algorithm === 'string' ? algorithm : algorithm?.name) || 'SHA-256'; + const name = (typeof algorithm === 'string' ? algorithm : algorithm?.name || '').toUpperCase().replace('_', '-'); + if (name !== 'SHA-1' && name !== 'SHA-256' && name !== 'SHA-384' && name !== 'SHA-512') { + throw new DOMException('Unrecognized algorithm name', 'NotSupportedError'); + } let bytes; if (data instanceof ArrayBuffer) bytes = new Uint8Array(data); else if (ArrayBuffer.isView(data)) bytes = new Uint8Array(data.buffer, data.byteOffset, data.byteLength); diff --git a/crates/obscura-js/src/ops.rs b/crates/obscura-js/src/ops.rs index bfbf1fd..6ae576b 100644 --- a/crates/obscura-js/src/ops.rs +++ b/crates/obscura-js/src/ops.rs @@ -1107,9 +1107,9 @@ fn op_binding_called(state: &OpState, #[string] name: &str, #[string] payload: & } /// Real WebCrypto `crypto.subtle.digest`. `algorithm` is the SubtleCrypto -/// algorithm name (`SHA-1` / `SHA-256` / `SHA-384` / `SHA-512`); unknown -/// names fall through to SHA-256 to match the previous JS fallback. Returns -/// the raw digest bytes so the JS shim can hand them back as an ArrayBuffer. +/// algorithm name (`SHA-1` / `SHA-256` / `SHA-384` / `SHA-512`). The JS shim +/// validates the name before calling this op; any other value is unreachable. +/// Returns the raw digest bytes so the JS shim can hand them back as an ArrayBuffer. #[op2] #[buffer] fn op_subtle_digest(#[string] algorithm: &str, #[buffer] data: &[u8]) -> Vec { @@ -1120,7 +1120,7 @@ fn op_subtle_digest(#[string] algorithm: &str, #[buffer] data: &[u8]) -> Vec "SHA-256" => sha2::Sha256::digest(data).to_vec(), "SHA-384" => sha2::Sha384::digest(data).to_vec(), "SHA-512" => sha2::Sha512::digest(data).to_vec(), - _ => sha2::Sha256::digest(data).to_vec(), + _ => vec![], } }