ladybird/Tests/LibWeb/Text/input/Crypto/SubtleCrypto-rsa-bad-import-key.html
devgianlu 4e747f525a
Some checks are pending
CI / Linux, x86_64, Fuzzers_CI, Clang (push) Waiting to run
CI / macOS, arm64, Sanitizer_CI, Clang (push) Waiting to run
CI / Linux, x86_64, Sanitizer_CI, GNU (push) Waiting to run
CI / Linux, x86_64, Sanitizer_CI, Clang (push) Waiting to run
Package the js repl as a binary artifact / Linux, arm64 (push) Waiting to run
Package the js repl as a binary artifact / macOS, arm64 (push) Waiting to run
Package the js repl as a binary artifact / Linux, x86_64 (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
LibCrypto+LibWeb: Check RSA keys validity on SubtleCrypto import_key
Fix various TODO by checking the validity of RSA keys when they are
imported.

Also add some internal tests since WPT doesn't seem to provide them.
2025-06-25 12:21:28 +12:00

80 lines
2.8 KiB
HTML

<!DOCTYPE html>
<script src="../include.js"></script>
<script>
function b64ToBn(b64) {
const bin = atob(b64.replace(/-/g, '+').replace(/_/g, '/'));
const hex = bin.split('').map((ch) => ch.charCodeAt(0).toString(16).padStart(2, '0')).join('');
return [BigInt('0x' + hex), bin.length];
}
function bnToB64(bn, len) {
const hex = bn.toString(16);
const bin = hex.match(/.{1,2}/g).map((byte) => String.fromCharCode(parseInt(byte, 16))).join('');
return btoa(bin.padStart(len, '\x00')).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}
function corruptJwk(key) {
const [bn, len] = b64ToBn(key.d);
// Corrupt the private key
return {
...key,
d: bnToB64(bn ^ 1n, len),
};
}
function corruptPkcs8Pub(privateKey) {
// Corrupt the public key, which is encoded between 33 and 165 for the PKCS8
const corrupted = new Uint8Array(privateKey);
corrupted[128] ^= 0x01;
return corrupted.buffer;
}
function corruptPkcs8Priv(privateKey) {
// Corrupt a piece of the private key, which is encoded at the end of the PKCS8
const corrupted = new Uint8Array(privateKey);
corrupted[corrupted.length - 20] ^= 0x01;
return corrupted.buffer;
}
asyncTest(async done => {
for (const [name, genUsages, privUsages] of [
["RSASSA-PKCS1-v1_5", ["sign", "verify"], ["sign"]],
["RSA-PSS", ["sign", "verify"], ["sign"]],
["RSA-OAEP", ["encrypt", "decrypt"], ["decrypt"]],
]) {
for (const hash of ["SHA-1", "SHA-256", "SHA-384", "SHA-512"]) {
const keyPair = await window.crypto.subtle.generateKey({
name: name,
hash: hash,
modulusLength: 1024,
publicExponent: new Uint8Array([1, 0, 1]),
}, true, genUsages);
// NOTE: We don't check the public key for RSA since it's harder to corrupt.
for (const [format, corruptFn] of [["jwk", corruptJwk], ["pkcs8", corruptPkcs8Priv], ["pkcs8", corruptPkcs8Pub]]) {
const privateKey = await window.crypto.subtle.exportKey(format, keyPair.privateKey);
// Prove that the original key can be imported successfully
await window.crypto.subtle.importKey(format, privateKey, {name: name, hash: hash,}, false, privUsages);
// Corrupt the private key and try to import it
const corruptedPrivateKey = corruptFn(privateKey);
try {
await window.crypto.subtle.importKey(format, corruptedPrivateKey, {
name: name,
hash: hash,
}, false, privUsages);
println(`${name.padEnd(5, ' ')} ${hash} PRIV - ${format.padEnd(5, ' ')} FAILED`);
} catch (e) {
println(`${name.padEnd(5, ' ')} ${hash} PRIV - ${format.padEnd(5, ' ')} OK: ${e}`);
}
}
}
}
done();
});
</script>