Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 70 additions & 1 deletion examples/componentize-demo/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@
// which the justfile recipe sets to the repository root — hence the
// root-relative library path below.

import { crypto, subtle, CryptoKey, DOMException } from "./js/componentize/webcrypto.js";
import {
crypto,
subtle,
CryptoKey,
DOMException,
setSha1CollisionPolicy,
} from "./js/componentize/webcrypto.js";

const encoder = new TextEncoder();

Expand All @@ -31,6 +37,24 @@ const GCM_CIPHERTEXT =
"8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662";
const GCM_TAG = "76fc6ece0f4e1768cddf8853bb2d551b";

// The first SHAttered message's five-block prefix: the shortest input on
// which sha1dc's collision detection fires (shared with the Rust
// conformance probe, which pins the same answers cross-target).
const SHATTERED_PREFIX =
"255044462d312e330a25e2e3cfd30a0a0a312030206f626a0a3c3c2f57696474" +
"682032203020522f4865696768742033203020522f547970652034203020522f" +
"537562747970652035203020522f46696c7465722036203020522f436f6c6f72" +
"53706163652037203020522f4c656e6774682038203020522f42697473506572" +
"436f6d706f6e656e7420383e3e0a73747265616d0affd8fffe00245348412d31" +
"20697320646561642121212121852fec092339759c39b1a1c63c4c97e1fffe01" +
"7346dc9166b67e118f029ab621b2560ff9ca67cca8c7f85ba84c79030c2b3de2" +
"18f86db3a90901d5df45c14f26fedfb3dc38e96ac22fe7bd728f0e45bce046d2" +
"3c570feb141398bb552ef5a0a82be331fea48037b8b5d71f0e332edf93ac3500" +
"eb4ddc0decc1a864790c782c76215660dd309791d06bd0af3f98cda4bc4629b1";
// Its deterministic sha1dc safe hash, and the FIPS 180-1 SHA-1 of "abc".
const SHATTERED_SAFE_HASH = "7117b3cb9225aaf0d8ef1a40e493957b0bf8693d";
const ABC_SHA1 = "a9993e364706816aba3e25717850c26c9cd0d89d";

// --- small helpers ------------------------------------------------------------

function hex(bytes) {
Expand Down Expand Up @@ -367,6 +391,50 @@ async function getRandomValuesCheck() {
);
}

/**
* `digest("SHA-1")` and the collision policy, end to end: honest input
* digests to standard SHA-1 in both postures; input carrying a collision
* attack yields the deterministic sha1dc safe hash under the default
* mitigating posture, and under `setSha1CollisionPolicy("reject")` throws
* `OperationError` — the shim's mapping of the package's
* `("lann:webcrypto", "collision-detected")` extension condition, whose
* pair rides in the `DOMException`'s `cause`.
*/
async function sha1CollisionPolicy() {
const attacked = unhex(SHATTERED_PREFIX);
try {
// The default posture: mitigate.
expectEq(hex(await subtle.digest("SHA-1", encoder.encode("abc"))), ABC_SHA1, "mitigate: abc");
expectEq(hex(await subtle.digest("SHA-1", attacked)), SHATTERED_SAFE_HASH, "mitigate: attacked input safe hash");

setSha1CollisionPolicy("reject");
expectEq(hex(await subtle.digest("SHA-1", encoder.encode("abc"))), ABC_SHA1, "reject: abc");
let thrown;
try {
await subtle.digest("SHA-1", attacked);
} catch (e) {
thrown = e;
}
if (!(thrown instanceof DOMException) || thrown.name !== "OperationError") {
throw new Error(`reject: attacked input: expected OperationError, got ${thrown ?? "success"}`);
}
const ext = thrown.cause?.val;
expectEq(ext?.origin, "lann:webcrypto", "reject: cause origin");
expectEq(ext?.name, "collision-detected", "reject: cause condition name");
} finally {
setSha1CollisionPolicy("mitigate");
}
let badPolicy;
try {
setSha1CollisionPolicy("plain");
} catch (e) {
badPolicy = e;
}
if (!(badPolicy instanceof TypeError)) {
throw new Error(`invalid policy: expected TypeError, got ${badPolicy ?? "success"}`);
}
}

const CHECKS = [
["hmac-known-answer", hmacKnownAnswer],
["hmac-verify", hmacVerify],
Expand All @@ -381,6 +449,7 @@ const CHECKS = [
["jwk-rejects-malformed", jwkRejectsMalformed],
["ed25519-sign-verify", ed25519SignVerify],
["get-random-values", getRandomValuesCheck],
["sha1-collision-policy", sha1CollisionPolicy],
];

// The `demo:webcrypto-demo/demo@0.1.0` export. `run` returns the ok summary
Expand Down
2 changes: 1 addition & 1 deletion js/componentize/componentize-js.rev
Original file line number Diff line number Diff line change
@@ -1 +1 @@
eed6d46b4741ad523592c4e3e044dab855386e91
bdd7c3d50e064d9c820218dbeb98be8bcae96875
4 changes: 2 additions & 2 deletions js/componentize/componentize-js.sha256
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@
# Regenerate with `just update-toolchain-digest` when the revision changes:
# it verifies the attestation before recording, so adding a line here is the
# deliberate, reviewable act of trusting a new binary.
linux-x86_64 9954f2a66d5165ca86c425c297d6b7b98f8760c5e97cf910b9e0fc3afd23121d bbf7be7397518def75f030821d759f15765bd13cdb20416e009c1e68bef64dc7
linux-aarch64 8ce76bd96feaf68fb2439f7b49d631adba7cdfc930442baf2eea77142d6d74c8 fe8b00ff3ca78ea99563bfdc1a7371fc7b839ede3070a7c9437d2b3858989ae1
linux-aarch64 043b3695a82fef4114454fa3e7195d8bfcaf704ac8e3880ba53e27526d2620ee e64592d1009bf7eed52d2d3efe33420c5c4c8d323bd9c3062db4fffe75cb713c
linux-x86_64 9a38c0a6b82f0bab9ac63cfc65d3a4218f65c96c68fe43998e0053762d1697cd 69b9b79f422abf26b0836a5ddd653ce751c433adf944d465b71f89cca31ff927
Loading