crypto.subtle.digest: reject unsupported algorithms (#314) (#319)

Unknown algorithm names (SHA-512/224, MD5, etc.) were silently falling
back to SHA-256, producing wrong bytes with no error. Now throws
DOMException('NotSupportedError') to match Chrome behavior.

Supported: SHA-1, SHA-256, SHA-384, SHA-512.
This commit is contained in:
Gabriel authored and GitHub committed 2026-06-22 13:02:05 +00:00
1 parent a8358cc82d
commit edde67ddd4
2 files changed
+8 -11

No files matched your search

+4 -7
View File
@@ -6420,13 +6420,10 @@ if (!globalThis.crypto) globalThis.crypto = {};
if (!globalThis.crypto.subtle) { if (!globalThis.crypto.subtle) {
globalThis.crypto.subtle = { globalThis.crypto.subtle = {
async digest(algorithm, data) { async digest(algorithm, data) {
// Real WebCrypto digest. Delegates to `op_subtle_digest` which runs const name = (typeof algorithm === 'string' ? algorithm : algorithm?.name || '').toUpperCase().replace('_', '-');
// the actual SHA-1/256/384/512 via Rust's `sha1` and `sha2` crates. if (name !== 'SHA-1' && name !== 'SHA-256' && name !== 'SHA-384' && name !== 'SHA-512') {
// The previous JS implementation was a custom FNV variant that throw new DOMException('Unrecognized algorithm name', 'NotSupportedError');
// 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';
let bytes; let bytes;
if (data instanceof ArrayBuffer) bytes = new Uint8Array(data); if (data instanceof ArrayBuffer) bytes = new Uint8Array(data);
else if (ArrayBuffer.isView(data)) bytes = new Uint8Array(data.buffer, data.byteOffset, data.byteLength); else if (ArrayBuffer.isView(data)) bytes = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
+4 -4
View File
@@ -1107,9 +1107,9 @@ fn op_binding_called(state: &OpState, #[string] name: &str, #[string] payload: &
} }
/// Real WebCrypto `crypto.subtle.digest`. `algorithm` is the SubtleCrypto /// Real WebCrypto `crypto.subtle.digest`. `algorithm` is the SubtleCrypto
/// algorithm name (`SHA-1` / `SHA-256` / `SHA-384` / `SHA-512`); unknown /// algorithm name (`SHA-1` / `SHA-256` / `SHA-384` / `SHA-512`). The JS shim
/// names fall through to SHA-256 to match the previous JS fallback. Returns /// validates the name before calling this op; any other value is unreachable.
/// the raw digest bytes so the JS shim can hand them back as an ArrayBuffer. /// Returns the raw digest bytes so the JS shim can hand them back as an ArrayBuffer.
#[op2] #[op2]
#[buffer] #[buffer]
fn op_subtle_digest(#[string] algorithm: &str, #[buffer] data: &[u8]) -> Vec<u8> { fn op_subtle_digest(#[string] algorithm: &str, #[buffer] data: &[u8]) -> Vec<u8> {
@@ -1120,7 +1120,7 @@ fn op_subtle_digest(#[string] algorithm: &str, #[buffer] data: &[u8]) -> Vec<u8>
"SHA-256" => sha2::Sha256::digest(data).to_vec(), "SHA-256" => sha2::Sha256::digest(data).to_vec(),
"SHA-384" => sha2::Sha384::digest(data).to_vec(), "SHA-384" => sha2::Sha384::digest(data).to_vec(),
"SHA-512" => sha2::Sha512::digest(data).to_vec(), "SHA-512" => sha2::Sha512::digest(data).to_vec(),
_ => sha2::Sha256::digest(data).to_vec(), _ => vec![],
} }
} }