Source code
Revision control
Copy as Markdown
Other Tools
Test Info: Errors
- This test gets skipped with pattern: os == 'android'
- This test failed 13 times in the preceding 30 days. quicksearch this test
- Manifest: toolkit/components/pdfjs/test/unit/xpcshell.toml
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
"use strict";
const { validateVerifyPdfSignatureArgs, filterCertsForView } =
ChromeUtils.importESModule("resource://pdf.js/PdfjsParent.sys.mjs");
// ---------------------------------------------------------------------
// validateVerifyPdfSignatureArgs — guards `_verifyPdfSignature` before
// forwarding bytes to NSS. Must reject every malformed shape and accept
// only the documented `{pkcs7, data, signatureType}` triple.
// ---------------------------------------------------------------------
add_task(function test_verifyArgs_rejects_missing_payload() {
Assert.equal(validateVerifyPdfSignatureArgs(null), false);
Assert.equal(validateVerifyPdfSignatureArgs(undefined), false);
Assert.equal(validateVerifyPdfSignatureArgs({}), false);
});
add_task(function test_verifyArgs_rejects_bad_pkcs7() {
const detached = [new Uint8Array(1)];
// Missing / wrong type pkcs7.
Assert.equal(
validateVerifyPdfSignatureArgs({ data: detached, signatureType: 0 }),
false,
"missing pkcs7"
);
Assert.equal(
validateVerifyPdfSignatureArgs({
pkcs7: "string-not-bytes",
data: detached,
signatureType: 0,
}),
false,
"pkcs7 must be Uint8Array, not string"
);
Assert.equal(
validateVerifyPdfSignatureArgs({
pkcs7: new ArrayBuffer(4),
data: detached,
signatureType: 0,
}),
false,
"pkcs7 must be Uint8Array, not ArrayBuffer"
);
});
add_task(function test_verifyArgs_rejects_bad_detached() {
const pkcs7 = new Uint8Array(4);
Assert.equal(
validateVerifyPdfSignatureArgs({ pkcs7, signatureType: 0 }),
false,
"missing data array"
);
Assert.equal(
validateVerifyPdfSignatureArgs({ pkcs7, data: "abc", signatureType: 0 }),
false,
"data must be an Array"
);
Assert.equal(
validateVerifyPdfSignatureArgs({ pkcs7, data: [], signatureType: 0 }),
false,
"data must be non-empty (`[].every` returns true)"
);
Assert.equal(
validateVerifyPdfSignatureArgs({
pkcs7,
data: [new Uint8Array(1), "not-bytes"],
signatureType: 0,
}),
false,
"every entry of data must be Uint8Array"
);
});
add_task(function test_verifyArgs_rejects_bad_signatureType() {
const pkcs7 = new Uint8Array(4);
const data = [new Uint8Array(1)];
for (const signatureType of [-1, 2, 1.5, NaN, "0", true, null, undefined]) {
Assert.equal(
validateVerifyPdfSignatureArgs({ pkcs7, data, signatureType }),
false,
`signatureType ${JSON.stringify(signatureType)} must be rejected`
);
}
});
add_task(function test_verifyArgs_accepts_well_formed() {
Assert.equal(
validateVerifyPdfSignatureArgs({
pkcs7: new Uint8Array([0x30, 0x82]),
data: [new Uint8Array([1, 2]), new Uint8Array([3, 4])],
signatureType: 0,
}),
true,
"adbe.pkcs7.detached payload (signatureType 0)"
);
Assert.equal(
validateVerifyPdfSignatureArgs({
pkcs7: new Uint8Array([0x30, 0x82]),
data: [new Uint8Array(0)], // a single empty span is still well-formed
signatureType: 1,
}),
true,
"adbe.pkcs7.sha1 payload (signatureType 1)"
);
});
// ---------------------------------------------------------------------
// filterCertsForView — guards `_viewPdfCertificate` so that what gets
// embedded into the `about:certificate` URL is bounded base64.
// ---------------------------------------------------------------------
// 16 ASCII chars, valid base64.
const VALID_CERT = "MIIBIjANBgkqhk==";
add_task(function test_filterCerts_rejects_bad_input_shape() {
Assert.equal(filterCertsForView(null), null, "null payload");
Assert.equal(filterCertsForView({}), null, "no certs key");
Assert.equal(
filterCertsForView({ certs: VALID_CERT }),
null,
"certs must be array"
);
Assert.equal(filterCertsForView({ certs: [] }), null, "empty cert list");
});
add_task(function test_filterCerts_rejects_too_many() {
// 16 is the documented cap; 17 must be rejected wholesale (no partial
// truncation) so a malicious caller can't slip in past the cap.
const justUnderCap = Array.from({ length: 16 }, () => VALID_CERT);
Assert.deepEqual(
filterCertsForView({ certs: justUnderCap }),
justUnderCap,
"exactly 16 certs are allowed through"
);
const overCap = Array.from({ length: 17 }, () => VALID_CERT);
Assert.equal(
filterCertsForView({ certs: overCap }),
null,
"17 certs must be rejected"
);
});
add_task(function test_filterCerts_drops_non_base64_entries() {
Assert.equal(
filterCertsForView({ certs: ["!@#$%^"] }),
null,
"non-base64 only -> null"
);
Assert.equal(
filterCertsForView({ certs: [""] }),
null,
"empty string -> null"
);
Assert.deepEqual(
filterCertsForView({
certs: [VALID_CERT, "!@#$%^", VALID_CERT, 42, null],
}),
[VALID_CERT, VALID_CERT],
"valid entries kept, non-base64 / non-string entries dropped"
);
});
add_task(function test_filterCerts_rejects_oversized_entry() {
const tooLong = "A".repeat(64 * 1024 + 1);
Assert.equal(
filterCertsForView({ certs: [tooLong] }),
null,
"entry over 64 KiB cap is rejected and result is null"
);
Assert.deepEqual(
filterCertsForView({ certs: [tooLong, VALID_CERT] }),
[VALID_CERT],
"oversized entry filtered out, valid one survives"
);
});
add_task(function test_filterCerts_accepts_well_formed() {
Assert.deepEqual(
filterCertsForView({ certs: [VALID_CERT] }),
[VALID_CERT],
"single valid cert"
);
Assert.deepEqual(
filterCertsForView({ certs: [VALID_CERT, VALID_CERT] }),
[VALID_CERT, VALID_CERT],
"two valid certs preserve order"
);
});