Sitekey signature validation results from core are being misread in webext
In frame-state.js
, we call verifySignature
from core like this:
if (!verifySignature(key, signature, data))
return null;
However this is wrong, because verifySignature
returns a Promise.
Background
I discovered this while working on #221 (closed). The two bugs are not related, even though they both happen to touch sitekeys.
Unfortunately, if sitekey verification is async, then our webRequest callbacks need to be async, which is not supported by Chrome (see the notes for onHeadersReceived
on the MDN browser compatibility table), so this may require extra effort or rethinking sitekeys to fix (which is why I'm not just fixing it as part of #221 (closed)). This is especially a problem for CSP filters, which need to use the sitekey from an onHeadersReceived
event inside that same onHeadersReceived
event.
Environment
- EWE 0.4.0
Steps to reproduce
- Load the test extension
- Add a sitekey filter
- Open a page which returns that sitekey, but with an invalid signature
- Observe if the sitekey filter is applied
Actual behavior
The sitekey filter is applied.
Expected behavior
The sitekey filter is not applied because the website presented an invalid signature.
Extra information
The following middleware can be added to start-server.js
to make it return badly signed sitekeys when you add ?invalid-sitekey=1
to the url.
async function invalidSitekeyHeader(req, res, next) {
if (req.query["invalid-sitekey"]) {
let pem = await fs.promises.readFile(path.join(dirname, "sitekey.pem"));
let privateKey = crypto.createPrivateKey(pem);
let publicKey = crypto.createPublicKey(privateKey);
let spki = publicKey.export({type: "spki", format: "der"});
let data = "this data to sign isn't the right data to sign";
let signature = crypto.sign("rsa-sha1", Buffer.from(data), privateKey);
let value = `${spki.toString("base64")}_${signature.toString("base64")}`;
res.header("X-Adblock-Key", value);
}
next();
}
...
app.use(invalidSitekeyHeader);
And this sitekey test can be added to test/request-filter.js
it("blocks a request if sitekey signature is invalild", async function() {
await addFilter("/image.png^$image");
await addFilter(`@@$sitekey=${SITEKEY}`);
let page = new Page("image.html?invalid-sitekey=1");
await page.expectResource("image.png").toBeBlocked();
});