3 // Tests the API nsIX509CertDB.openSignedAppFileAsync, which backs add-on
4 // signature verification. Testcases include various ways of tampering with
5 // add-ons as well as different hash algorithms used in the various
6 // signature/metadata files.
10 const PR_CREATE_FILE = 0x08;
11 const PR_TRUNCATE = 0x20;
12 const PR_USEC_PER_MSEC = 1000;
14 do_get_profile(); // must be called before getting nsIX509CertDB
15 const certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
19 // Creates a new app package based in the inFilePath package, with a set of
20 // modifications (including possibly deletions) applied to the existing entries,
21 // and/or a set of new entries to be included.
22 function tamper(inFilePath, outFilePath, modifications, newEntries) {
23 let writer = Cc["@mozilla.org/zipwriter;1"].createInstance(Ci.nsIZipWriter);
24 writer.open(outFilePath, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE);
26 let reader = Cc["@mozilla.org/libjar/zip-reader;1"].createInstance(
29 reader.open(inFilePath);
31 for (let entryName of reader.findEntries("")) {
32 let inEntry = reader.getEntry(entryName);
33 let entryInput = reader.getInputStream(entryName);
35 let f = modifications[entryName];
36 let outEntry, outEntryInput;
38 [outEntry, outEntryInput] = f(inEntry, entryInput);
39 delete modifications[entryName];
41 [outEntry, outEntryInput] = [inEntry, entryInput];
43 // if f does not want the input entry to be copied to the output entry
44 // at all (i.e. it wants it to be deleted), it will return null.
47 writer.addEntryStream(
49 outEntry.lastModifiedTime,
55 if (entryInput != outEntryInput) {
56 outEntryInput.close();
68 // Any leftover modification means that we were expecting to modify an entry
69 // in the input file that wasn't there.
70 for (let name in modifications) {
71 if (modifications.hasOwnProperty(name)) {
72 throw new Error("input file was missing expected entries: " + name);
76 // Now, append any new entries to the end
77 newEntries.forEach(function (newEntry) {
78 let sis = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(
79 Ci.nsIStringInputStream
82 sis.setByteStringData(newEntry.content);
83 writer.addEntryStream(
85 new Date() * PR_USEC_PER_MSEC,
86 Ci.nsIZipWriter.COMPRESSION_BEST,
99 function removeEntry() {
103 function truncateEntry(entry, entryInput) {
104 if (entryInput.available() == 0) {
106 "Truncating already-zero length entry will result in " +
111 let content = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(
112 Ci.nsIStringInputStream
114 content.setByteStringData("");
116 return [entry, content];
119 function check_open_result(name, expectedRv, expectedSignatureAlgorithms) {
120 return function openSignedAppFileCallback(rv, aZipReader, aSignatureInfos) {
121 info("openSignedAppFileCallback called for " + name);
122 equal(rv, expectedRv, "Actual and expected return value should match");
125 Components.isSuccessCode(expectedRv),
126 "ZIP reader should be null only if the return value denotes failure"
129 aSignatureInfos.length,
130 expectedSignatureAlgorithms.length,
131 "Should have the same number of expected signature infos"
133 for (let i = 0; i < expectedSignatureAlgorithms.length; i++) {
135 aSignatureInfos[i].signatureAlgorithm,
136 expectedSignatureAlgorithms[i],
137 "Should have expected signature algorithm"
144 function original_app_path(test_name) {
145 return do_get_file("test_signed_apps/" + test_name + ".zip", false);
148 function tampered_app_path(test_name) {
149 return new FileUtils.File(
151 Services.dirsvc.get("TmpD", Ci.nsIFile).path,
152 `test_signed_app-${test_name}.zip`
157 var hashTestcases = [
158 // SHA-256 in PKCS#7 + SHA-256 present elsewhere => OK
160 name: "app_mf-1-256_sf-1-256_p7-1-256",
161 expectedResult: Cr.NS_OK,
162 expectedSignatureAlgorithms: [Ci.nsIAppSignatureInfo.PKCS7_WITH_SHA256],
165 name: "app_mf-1-256_sf-1-256_p7-256",
166 expectedResult: Cr.NS_OK,
167 expectedSignatureAlgorithms: [Ci.nsIAppSignatureInfo.PKCS7_WITH_SHA256],
170 name: "app_mf-1-256_sf-256_p7-1-256",
171 expectedResult: Cr.NS_OK,
172 expectedSignatureAlgorithms: [Ci.nsIAppSignatureInfo.PKCS7_WITH_SHA256],
175 name: "app_mf-1-256_sf-256_p7-256",
176 expectedResult: Cr.NS_OK,
177 expectedSignatureAlgorithms: [Ci.nsIAppSignatureInfo.PKCS7_WITH_SHA256],
180 name: "app_mf-256_sf-1-256_p7-1-256",
181 expectedResult: Cr.NS_OK,
182 expectedSignatureAlgorithms: [Ci.nsIAppSignatureInfo.PKCS7_WITH_SHA256],
185 name: "app_mf-256_sf-1-256_p7-256",
186 expectedResult: Cr.NS_OK,
187 expectedSignatureAlgorithms: [Ci.nsIAppSignatureInfo.PKCS7_WITH_SHA256],
190 name: "app_mf-256_sf-256_p7-1-256",
191 expectedResult: Cr.NS_OK,
192 expectedSignatureAlgorithms: [Ci.nsIAppSignatureInfo.PKCS7_WITH_SHA256],
195 name: "app_mf-256_sf-256_p7-256",
196 expectedResult: Cr.NS_OK,
197 expectedSignatureAlgorithms: [Ci.nsIAppSignatureInfo.PKCS7_WITH_SHA256],
200 // SHA-1 in PKCS#7 + SHA-1 present elsewhere => OK
202 name: "app_mf-1-256_sf-1-256_p7-1",
203 expectedResult: Cr.NS_OK,
204 expectedSignatureAlgorithms: [Ci.nsIAppSignatureInfo.PKCS7_WITH_SHA1],
207 name: "app_mf-1-256_sf-1_p7-1",
208 expectedResult: Cr.NS_OK,
209 expectedSignatureAlgorithms: [Ci.nsIAppSignatureInfo.PKCS7_WITH_SHA1],
212 name: "app_mf-1_sf-1-256_p7-1",
213 expectedResult: Cr.NS_OK,
214 expectedSignatureAlgorithms: [Ci.nsIAppSignatureInfo.PKCS7_WITH_SHA1],
217 name: "app_mf-1_sf-1_p7-1",
218 expectedResult: Cr.NS_OK,
219 expectedSignatureAlgorithms: [Ci.nsIAppSignatureInfo.PKCS7_WITH_SHA1],
222 // SHA-256 in PKCS#7 + SHA-256 not present elsewhere => INVALID
224 name: "app_mf-1-256_sf-1_p7-1-256",
225 expectedResult: Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
226 expectedSignatureAlgorithms: [],
229 name: "app_mf-1-256_sf-1_p7-256",
230 expectedResult: Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
231 expectedSignatureAlgorithms: [],
234 name: "app_mf-1_sf-1-256_p7-1-256",
235 expectedResult: Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
236 expectedSignatureAlgorithms: [],
239 name: "app_mf-1_sf-1-256_p7-256",
240 expectedResult: Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
241 expectedSignatureAlgorithms: [],
244 name: "app_mf-1_sf-1_p7-1-256",
245 expectedResult: Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
246 expectedSignatureAlgorithms: [],
249 name: "app_mf-1_sf-1_p7-256",
250 expectedResult: Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
251 expectedSignatureAlgorithms: [],
254 name: "app_mf-1_sf-256_p7-1-256",
255 expectedResult: Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
256 expectedSignatureAlgorithms: [],
259 name: "app_mf-1_sf-256_p7-256",
260 expectedResult: Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
261 expectedSignatureAlgorithms: [],
264 name: "app_mf-256_sf-1_p7-1-256",
265 expectedResult: Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
266 expectedSignatureAlgorithms: [],
269 name: "app_mf-256_sf-1_p7-256",
270 expectedResult: Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
271 expectedSignatureAlgorithms: [],
274 // SHA-1 in PKCS#7 + SHA-1 not present elsewhere => INVALID
276 name: "app_mf-1-256_sf-256_p7-1",
277 expectedResult: Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
278 expectedSignatureAlgorithms: [],
281 name: "app_mf-1_sf-256_p7-1",
282 expectedResult: Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
283 expectedSignatureAlgorithms: [],
286 name: "app_mf-256_sf-1-256_p7-1",
287 expectedResult: Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
288 expectedSignatureAlgorithms: [],
291 name: "app_mf-256_sf-1_p7-1",
292 expectedResult: Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
293 expectedSignatureAlgorithms: [],
296 name: "app_mf-256_sf-256_p7-1",
297 expectedResult: Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
298 expectedSignatureAlgorithms: [],
302 // Policy values for the preference "security.signed_app_signatures.policy"
303 const PKCS7WithSHA1OrSHA256 = 0b0;
304 const PKCS7_WITH_SHA256 = 0b1;
305 const COSEAndPKCS7WithSHA1OrSHA256 = 0b10;
306 const COSEAndPKCS7WithSHA256 = 0b11;
307 const COSERequiredAndPKCS7WithSHA1OrSHA256 = 0b100;
308 const COSERequiredAndPKCS7WithSHA256 = 0b101;
309 const COSEOnly = 0b110;
310 const COSEOnlyAgain = 0b111;
312 function add_signature_test(policy, test) {
313 // First queue up a test to set the desired policy:
314 add_test(function () {
315 Services.prefs.setIntPref("security.signed_app_signatures.policy", policy);
318 // Then queue up the test itself:
322 for (let testcase of hashTestcases) {
323 add_signature_test(PKCS7WithSHA1OrSHA256, function () {
324 certdb.openSignedAppFileAsync(
325 Ci.nsIX509CertDB.AppXPCShellRoot,
326 original_app_path(testcase.name),
329 testcase.expectedResult,
330 testcase.expectedSignatureAlgorithms
336 add_signature_test(PKCS7WithSHA1OrSHA256, function () {
337 certdb.openSignedAppFileAsync(
338 Ci.nsIX509CertDB.AppXPCShellRoot,
339 original_app_path("empty_signerInfos"),
341 "the signerInfos in the PKCS#7 signature is empty",
342 Cr.NS_ERROR_CMS_VERIFY_NOT_SIGNED,
348 add_signature_test(PKCS7WithSHA1OrSHA256, function () {
349 certdb.openSignedAppFileAsync(
350 Ci.nsIX509CertDB.AppXPCShellRoot,
351 original_app_path("unsigned_app"),
352 check_open_result("unsigned", Cr.NS_ERROR_SIGNED_JAR_NOT_SIGNED, [])
356 add_signature_test(PKCS7WithSHA1OrSHA256, function () {
357 certdb.openSignedAppFileAsync(
358 Ci.nsIX509CertDB.AppXPCShellRoot,
359 original_app_path("unknown_issuer_app"),
362 getXPCOMStatusFromNSS(SEC_ERROR_UNKNOWN_ISSUER),
368 add_signature_test(COSEAndPKCS7WithSHA1OrSHA256, function () {
369 certdb.openSignedAppFileAsync(
370 Ci.nsIX509CertDB.AppXPCShellRoot,
371 original_app_path("cose_signed_with_pkcs7"),
372 check_open_result("cose_signed_with_pkcs7", Cr.NS_OK, [
373 Ci.nsIAppSignatureInfo.COSE_WITH_SHA256,
374 Ci.nsIAppSignatureInfo.PKCS7_WITH_SHA256,
379 add_signature_test(COSEAndPKCS7WithSHA256, function () {
380 certdb.openSignedAppFileAsync(
381 Ci.nsIX509CertDB.AppXPCShellRoot,
382 original_app_path("app_mf-256_sf-256_p7-256"),
383 check_open_result("no COSE but correct PK#7", Cr.NS_OK, [
384 Ci.nsIAppSignatureInfo.PKCS7_WITH_SHA256,
389 add_signature_test(COSEAndPKCS7WithSHA256, function () {
390 certdb.openSignedAppFileAsync(
391 Ci.nsIX509CertDB.AppXPCShellRoot,
392 original_app_path("app_mf-1_sf-256_p7-256"),
394 "no COSE and wrong PK#7 hash",
395 Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
401 add_signature_test(COSERequiredAndPKCS7WithSHA1OrSHA256, function () {
402 certdb.openSignedAppFileAsync(
403 Ci.nsIX509CertDB.AppXPCShellRoot,
404 original_app_path("app_mf-256_sf-256_p7-256"),
406 "COSE signature missing (SHA1 or 256)",
407 Cr.NS_ERROR_SIGNED_JAR_WRONG_SIGNATURE,
413 add_signature_test(COSERequiredAndPKCS7WithSHA256, function () {
414 certdb.openSignedAppFileAsync(
415 Ci.nsIX509CertDB.AppXPCShellRoot,
416 original_app_path("app_mf-256_sf-256_p7-256"),
418 "COSE signature missing (SHA256)",
419 Cr.NS_ERROR_SIGNED_JAR_WRONG_SIGNATURE,
425 add_signature_test(COSERequiredAndPKCS7WithSHA256, function () {
426 certdb.openSignedAppFileAsync(
427 Ci.nsIX509CertDB.AppXPCShellRoot,
428 original_app_path("only_cose_signed"),
430 "COSE signature only (PK#7 allowed, not present)",
432 [Ci.nsIAppSignatureInfo.COSE_WITH_SHA256]
437 add_signature_test(COSERequiredAndPKCS7WithSHA1OrSHA256, function () {
438 certdb.openSignedAppFileAsync(
439 Ci.nsIX509CertDB.AppXPCShellRoot,
440 original_app_path("only_cose_signed"),
442 "COSE signature only (PK#7 allowed, not present)",
444 [Ci.nsIAppSignatureInfo.COSE_WITH_SHA256]
449 add_signature_test(COSEAndPKCS7WithSHA1OrSHA256, function () {
450 certdb.openSignedAppFileAsync(
451 Ci.nsIX509CertDB.AppXPCShellRoot,
452 original_app_path("cose_multiple_signed_with_pkcs7"),
453 check_open_result("cose_multiple_signed_with_pkcs7", Cr.NS_OK, [
454 Ci.nsIAppSignatureInfo.COSE_WITH_SHA256,
455 Ci.nsIAppSignatureInfo.PKCS7_WITH_SHA256,
460 add_signature_test(COSEAndPKCS7WithSHA1OrSHA256, function () {
461 certdb.openSignedAppFileAsync(
462 Ci.nsIX509CertDB.AppXPCShellRoot,
463 original_app_path("cose_int_signed_with_pkcs7"),
464 check_open_result("COSE signed with an intermediate", Cr.NS_OK, [
465 Ci.nsIAppSignatureInfo.COSE_WITH_SHA256,
466 Ci.nsIAppSignatureInfo.PKCS7_WITH_SHA256,
471 add_signature_test(COSEAndPKCS7WithSHA1OrSHA256, function () {
472 certdb.openSignedAppFileAsync(
473 Ci.nsIX509CertDB.AppXPCShellRoot,
474 original_app_path("only_cose_signed"),
476 "PK7 signature missing",
477 Cr.NS_ERROR_SIGNED_JAR_NOT_SIGNED,
483 add_signature_test(COSEOnly, function () {
484 certdb.openSignedAppFileAsync(
485 Ci.nsIX509CertDB.AppXPCShellRoot,
486 original_app_path("cose_multiple_signed_with_pkcs7"),
488 "Expected only COSE signature",
489 Cr.NS_ERROR_SIGNED_JAR_UNSIGNED_ENTRY,
495 add_signature_test(COSEOnly, function () {
496 certdb.openSignedAppFileAsync(
497 Ci.nsIX509CertDB.AppXPCShellRoot,
498 original_app_path("only_cose_multiple_signed"),
499 check_open_result("only Multiple COSE signatures", Cr.NS_OK, [
500 Ci.nsIAppSignatureInfo.COSE_WITH_SHA256,
505 add_signature_test(COSEOnly, function () {
506 certdb.openSignedAppFileAsync(
507 Ci.nsIX509CertDB.AppXPCShellRoot,
508 original_app_path("only_cose_signed"),
509 check_open_result("only_cose_signed", Cr.NS_OK, [
510 Ci.nsIAppSignatureInfo.COSE_WITH_SHA256,
515 add_signature_test(COSEOnlyAgain, function () {
516 certdb.openSignedAppFileAsync(
517 Ci.nsIX509CertDB.AppXPCShellRoot,
518 original_app_path("only_cose_signed"),
519 check_open_result("only_cose_signed (again)", Cr.NS_OK, [
520 Ci.nsIAppSignatureInfo.COSE_WITH_SHA256,
525 add_signature_test(COSEOnly, function () {
526 certdb.openSignedAppFileAsync(
527 Ci.nsIX509CertDB.AppXPCShellRoot,
528 original_app_path("cose_signed_with_pkcs7"),
530 "COSE only expected but also PK#7 signed",
531 Cr.NS_ERROR_SIGNED_JAR_UNSIGNED_ENTRY,
537 // Sanity check to ensure a no-op tampering gives a valid result
538 add_signature_test(PKCS7WithSHA1OrSHA256, function () {
539 let tampered = tampered_app_path("identity_tampering");
540 tamper(original_app_path("app_mf-1_sf-1_p7-1"), tampered, {}, []);
541 certdb.openSignedAppFileAsync(
542 Ci.nsIX509CertDB.AppXPCShellRoot,
543 original_app_path("app_mf-1_sf-1_p7-1"),
544 check_open_result("identity_tampering", Cr.NS_OK, [
545 Ci.nsIAppSignatureInfo.PKCS7_WITH_SHA1,
550 add_signature_test(PKCS7WithSHA1OrSHA256, function () {
551 let tampered = tampered_app_path("missing_rsa");
553 original_app_path("app_mf-1_sf-1_p7-1"),
555 { "META-INF/A.RSA": removeEntry },
558 certdb.openSignedAppFileAsync(
559 Ci.nsIX509CertDB.AppXPCShellRoot,
561 check_open_result("missing_rsa", Cr.NS_ERROR_SIGNED_JAR_NOT_SIGNED, [])
565 add_signature_test(PKCS7WithSHA1OrSHA256, function () {
566 let tampered = tampered_app_path("missing_sf");
568 original_app_path("app_mf-1_sf-1_p7-1"),
570 { "META-INF/A.SF": removeEntry },
573 certdb.openSignedAppFileAsync(
574 Ci.nsIX509CertDB.AppXPCShellRoot,
576 check_open_result("missing_sf", Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID, [])
580 add_signature_test(PKCS7WithSHA1OrSHA256, function () {
581 let tampered = tampered_app_path("missing_manifest_mf");
583 original_app_path("app_mf-1_sf-1_p7-1"),
585 { "META-INF/MANIFEST.MF": removeEntry },
588 certdb.openSignedAppFileAsync(
589 Ci.nsIX509CertDB.AppXPCShellRoot,
592 "missing_manifest_mf",
593 Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
599 add_signature_test(PKCS7WithSHA1OrSHA256, function () {
600 let tampered = tampered_app_path("missing_entry");
602 original_app_path("app_mf-1_sf-1_p7-1"),
604 { "manifest.json": removeEntry },
607 certdb.openSignedAppFileAsync(
608 Ci.nsIX509CertDB.AppXPCShellRoot,
610 check_open_result("missing_entry", Cr.NS_ERROR_SIGNED_JAR_ENTRY_MISSING, [])
614 add_signature_test(PKCS7WithSHA1OrSHA256, function () {
615 let tampered = tampered_app_path("truncated_entry");
617 original_app_path("app_mf-1_sf-1_p7-1"),
619 { "manifest.json": truncateEntry },
622 certdb.openSignedAppFileAsync(
623 Ci.nsIX509CertDB.AppXPCShellRoot,
627 Cr.NS_ERROR_SIGNED_JAR_MODIFIED_ENTRY,
633 add_signature_test(PKCS7WithSHA1OrSHA256, function () {
634 let tampered = tampered_app_path("truncated_manifestFile");
636 original_app_path("app_mf-1_sf-1_p7-1"),
638 { "META-INF/MANIFEST.MF": truncateEntry },
641 certdb.openSignedAppFileAsync(
642 Ci.nsIX509CertDB.AppXPCShellRoot,
645 "truncated_manifestFile",
646 Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
652 add_signature_test(PKCS7WithSHA1OrSHA256, function () {
653 let tampered = tampered_app_path("truncated_signatureFile");
655 original_app_path("app_mf-1_sf-1_p7-1"),
657 { "META-INF/A.SF": truncateEntry },
660 certdb.openSignedAppFileAsync(
661 Ci.nsIX509CertDB.AppXPCShellRoot,
664 "truncated_signatureFile",
665 getXPCOMStatusFromNSS(SEC_ERROR_PKCS7_BAD_SIGNATURE),
671 add_signature_test(PKCS7WithSHA1OrSHA256, function () {
672 let tampered = tampered_app_path("truncated_pkcs7File");
674 original_app_path("app_mf-1_sf-1_p7-1"),
676 { "META-INF/A.RSA": truncateEntry },
679 certdb.openSignedAppFileAsync(
680 Ci.nsIX509CertDB.AppXPCShellRoot,
683 "truncated_pkcs7File",
684 Cr.NS_ERROR_CMS_VERIFY_NOT_SIGNED,
690 add_signature_test(PKCS7WithSHA1OrSHA256, function () {
691 let tampered = tampered_app_path("unsigned_entry");
692 tamper(original_app_path("app_mf-1_sf-1_p7-1"), tampered, {}, [
693 { name: "unsigned.txt", content: "unsigned content!" },
695 certdb.openSignedAppFileAsync(
696 Ci.nsIX509CertDB.AppXPCShellRoot,
700 Cr.NS_ERROR_SIGNED_JAR_UNSIGNED_ENTRY,
706 add_signature_test(PKCS7WithSHA1OrSHA256, function () {
707 let tampered = tampered_app_path("unsigned_metainf_entry");
708 tamper(original_app_path("app_mf-1_sf-1_p7-1"), tampered, {}, [
709 { name: "META-INF/unsigned.txt", content: "unsigned content!" },
711 certdb.openSignedAppFileAsync(
712 Ci.nsIX509CertDB.AppXPCShellRoot,
715 "unsigned_metainf_entry",
716 Cr.NS_ERROR_SIGNED_JAR_UNSIGNED_ENTRY,
722 add_signature_test(PKCS7_WITH_SHA256, function testSHA1Disabled() {
723 certdb.openSignedAppFileAsync(
724 Ci.nsIX509CertDB.AppXPCShellRoot,
725 original_app_path("app_mf-1_sf-1_p7-1"),
727 "SHA-1 should not be accepted if disabled by policy",
728 Cr.NS_ERROR_SIGNED_JAR_WRONG_SIGNATURE,
736 function testSHA256WorksWithSHA1Disabled() {
737 certdb.openSignedAppFileAsync(
738 Ci.nsIX509CertDB.AppXPCShellRoot,
739 original_app_path("app_mf-256_sf-256_p7-256"),
741 "SHA-256 should work if SHA-1 is disabled by policy",
743 [Ci.nsIAppSignatureInfo.PKCS7_WITH_SHA256]
751 function testMultipleSignaturesWorkWithSHA1Disabled() {
752 certdb.openSignedAppFileAsync(
753 Ci.nsIX509CertDB.AppXPCShellRoot,
754 original_app_path("app_mf-1-256_sf-1-256_p7-1-256"),
756 "Multiple signatures should work if SHA-1 is " +
757 "disabled by policy (if SHA-256 signature verifies)",
759 [Ci.nsIAppSignatureInfo.PKCS7_WITH_SHA256]
766 COSEAndPKCS7WithSHA1OrSHA256,
767 COSERequiredAndPKCS7WithSHA1OrSHA256,
770 // NOTE: The zip files referenced in coseTestcasesStage and coseTestcasesProd
771 // were originally generated with
772 // https://github.com/mozilla-services/autograph/blob/c890e14de5b04dcff9be0d07fdea4ae6bbb58557/tools/autograph-client/build_test_xpis.sh
773 // Since then, the mechanism to sign these packages have changed, see
774 // https://bugzilla.mozilla.org/show_bug.cgi?id=1885457 for details.
776 var coseTestcasesStage = [
778 name: "addons-stage-tomato-clock-sha1-es256-es384",
779 expectedResult: Cr.NS_OK,
780 expectedSignatureAlgorithms: [
781 Ci.nsIAppSignatureInfo.COSE_WITH_SHA256,
782 Ci.nsIAppSignatureInfo.PKCS7_WITH_SHA1,
784 root: Ci.nsIX509CertDB.AddonsStageRoot,
787 name: "addons-stage-tomato-clock-sha1-es256-ps256",
788 // PS256 is not yet supported.
789 expectedResult: Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
790 expectedSignatureAlgorithms: [],
791 root: Ci.nsIX509CertDB.AddonsStageRoot,
794 name: "addons-stage-tomato-clock-sha1-es256",
795 expectedResult: Cr.NS_OK,
796 expectedSignatureAlgorithms: [
797 Ci.nsIAppSignatureInfo.COSE_WITH_SHA256,
798 Ci.nsIAppSignatureInfo.PKCS7_WITH_SHA1,
800 root: Ci.nsIX509CertDB.AddonsStageRoot,
803 name: "addons-stage-tomato-clock-sha1-ps256",
804 // PS256 is not yet supported.
805 expectedResult: Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
806 expectedSignatureAlgorithms: [],
807 root: Ci.nsIX509CertDB.AddonsStageRoot,
811 var coseTestcasesProd = [
813 name: "autograph-714ba248-prod-tomato-clock-PKCS7-SHA1-ES256-ES384",
814 expectedResult: Cr.NS_OK,
815 expectedSignatureAlgorithms: [
816 Ci.nsIAppSignatureInfo.COSE_WITH_SHA256,
817 Ci.nsIAppSignatureInfo.PKCS7_WITH_SHA1,
819 root: Ci.nsIX509CertDB.AddonsPublicRoot,
822 name: "autograph-714ba248-prod-tomato-clock-PKCS7-SHA1-ES256-PS256",
823 // PS256 is not yet supported.
824 expectedResult: Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
825 expectedSignatureAlgorithms: [],
826 root: Ci.nsIX509CertDB.AddonsPublicRoot,
829 name: "autograph-714ba248-prod-tomato-clock-PKCS7-SHA1-ES256",
830 expectedResult: Cr.NS_OK,
831 expectedSignatureAlgorithms: [
832 Ci.nsIAppSignatureInfo.COSE_WITH_SHA256,
833 Ci.nsIAppSignatureInfo.PKCS7_WITH_SHA1,
835 root: Ci.nsIX509CertDB.AddonsPublicRoot,
838 name: "autograph-714ba248-prod-tomato-clock-PKCS7-SHA1-PS256",
839 // PS256 is not yet supported.
840 expectedResult: Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
841 expectedSignatureAlgorithms: [],
842 root: Ci.nsIX509CertDB.AddonsPublicRoot,
846 for (let policy of cosePolicies) {
847 for (let testcase of [...coseTestcasesStage, ...coseTestcasesProd]) {
848 add_signature_test(policy, function () {
849 certdb.openSignedAppFileAsync(
851 original_app_path(testcase.name),
854 testcase.expectedResult,
855 testcase.expectedSignatureAlgorithms
862 add_signature_test(COSEAndPKCS7WithSHA256, function testCOSESigTampered() {
863 let tampered = tampered_app_path("cose_sig_tampered");
865 original_app_path("cose_signed_with_pkcs7"),
867 { "META-INF/cose.sig": truncateEntry },
870 certdb.openSignedAppFileAsync(
871 Ci.nsIX509CertDB.AppXPCShellRoot,
875 Cr.NS_ERROR_SIGNED_JAR_MODIFIED_ENTRY,
881 // PKCS7 is processed before COSE, so if a COSE signature file is removed or
882 // tampered with, this appears as a PKCS7 signature verification failure.
883 add_signature_test(COSEAndPKCS7WithSHA256, function testCOSESigRemoved() {
884 let tampered = tampered_app_path("cose_sig_removed");
886 original_app_path("cose_signed_with_pkcs7"),
888 { "META-INF/cose.sig": removeEntry },
891 certdb.openSignedAppFileAsync(
892 Ci.nsIX509CertDB.AppXPCShellRoot,
896 Cr.NS_ERROR_SIGNED_JAR_ENTRY_MISSING,
902 add_signature_test(COSEAndPKCS7WithSHA256, function testCOSEManifestTampered() {
903 let tampered = tampered_app_path("cose_manifest_tampered");
905 original_app_path("cose_signed_with_pkcs7"),
907 { "META-INF/cose.manifest": truncateEntry },
910 certdb.openSignedAppFileAsync(
911 Ci.nsIX509CertDB.AppXPCShellRoot,
914 "cose_manifest_tampered",
915 Cr.NS_ERROR_SIGNED_JAR_MODIFIED_ENTRY,
921 add_signature_test(COSEAndPKCS7WithSHA256, function testCOSEManifestRemoved() {
922 let tampered = tampered_app_path("cose_manifest_removed");
924 original_app_path("cose_signed_with_pkcs7"),
926 { "META-INF/cose.manifest": removeEntry },
929 certdb.openSignedAppFileAsync(
930 Ci.nsIX509CertDB.AppXPCShellRoot,
933 "cose_manifest_removed",
934 Cr.NS_ERROR_SIGNED_JAR_ENTRY_MISSING,
940 add_signature_test(COSEAndPKCS7WithSHA256, function testCOSEFileAdded() {
941 let tampered = tampered_app_path("cose_file_added");
942 tamper(original_app_path("cose_signed_with_pkcs7"), tampered, {}, [
943 { name: "unsigned.txt", content: "unsigned content!" },
945 certdb.openSignedAppFileAsync(
946 Ci.nsIX509CertDB.AppXPCShellRoot,
950 Cr.NS_ERROR_SIGNED_JAR_UNSIGNED_ENTRY,
956 add_signature_test(COSEAndPKCS7WithSHA256, function testCOSEFileRemoved() {
957 let tampered = tampered_app_path("cose_file_removed");
959 original_app_path("cose_signed_with_pkcs7"),
961 { "manifest.json": removeEntry },
964 certdb.openSignedAppFileAsync(
965 Ci.nsIX509CertDB.AppXPCShellRoot,
969 Cr.NS_ERROR_SIGNED_JAR_ENTRY_MISSING,
975 add_signature_test(COSEAndPKCS7WithSHA256, function testCOSEFileTampered() {
976 let tampered = tampered_app_path("cose_file_tampered");
978 original_app_path("cose_signed_with_pkcs7"),
980 { "manifest.json": truncateEntry },
983 certdb.openSignedAppFileAsync(
984 Ci.nsIX509CertDB.AppXPCShellRoot,
987 "cose_file_tampered",
988 Cr.NS_ERROR_SIGNED_JAR_MODIFIED_ENTRY,
994 add_signature_test(COSEOnly, function testOnlyCOSESigTampered() {
995 let tampered = tampered_app_path("only_cose_sig_tampered");
997 original_app_path("only_cose_signed"),
999 { "META-INF/cose.sig": truncateEntry },
1002 certdb.openSignedAppFileAsync(
1003 Ci.nsIX509CertDB.AppXPCShellRoot,
1006 "only_cose_sig_tampered",
1007 Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
1013 add_signature_test(COSEOnly, function testOnlyCOSESigRemoved() {
1014 let tampered = tampered_app_path("only_cose_sig_removed");
1016 original_app_path("only_cose_signed"),
1018 { "META-INF/cose.sig": removeEntry },
1021 certdb.openSignedAppFileAsync(
1022 Ci.nsIX509CertDB.AppXPCShellRoot,
1025 "only_cose_sig_removed",
1026 Cr.NS_ERROR_SIGNED_JAR_WRONG_SIGNATURE,
1032 add_signature_test(COSEOnly, function testOnlyCOSEManifestTampered() {
1033 let tampered = tampered_app_path("only_cose_manifest_tampered");
1035 original_app_path("only_cose_signed"),
1037 { "META-INF/cose.manifest": truncateEntry },
1040 certdb.openSignedAppFileAsync(
1041 Ci.nsIX509CertDB.AppXPCShellRoot,
1044 "only_cose_manifest_tampered",
1045 Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
1051 add_signature_test(COSEOnly, function testOnlyCOSEManifestRemoved() {
1052 let tampered = tampered_app_path("only_cose_manifest_removed");
1054 original_app_path("only_cose_signed"),
1056 { "META-INF/cose.manifest": removeEntry },
1059 certdb.openSignedAppFileAsync(
1060 Ci.nsIX509CertDB.AppXPCShellRoot,
1063 "only_cose_manifest_removed",
1064 Cr.NS_ERROR_SIGNED_JAR_WRONG_SIGNATURE,
1070 add_signature_test(COSEOnly, function testOnlyCOSEFileAdded() {
1071 let tampered = tampered_app_path("only_cose_file_added");
1072 tamper(original_app_path("only_cose_signed"), tampered, {}, [
1073 { name: "unsigned.txt", content: "unsigned content!" },
1075 certdb.openSignedAppFileAsync(
1076 Ci.nsIX509CertDB.AppXPCShellRoot,
1079 "only_cose_file_added",
1080 Cr.NS_ERROR_SIGNED_JAR_UNSIGNED_ENTRY,
1086 add_signature_test(COSEOnly, function testOnlyCOSEFileRemoved() {
1087 let tampered = tampered_app_path("only_cose_file_removed");
1089 original_app_path("only_cose_signed"),
1091 { "manifest.json": removeEntry },
1094 certdb.openSignedAppFileAsync(
1095 Ci.nsIX509CertDB.AppXPCShellRoot,
1098 "only_cose_file_removed",
1099 Cr.NS_ERROR_SIGNED_JAR_ENTRY_MISSING,
1105 add_signature_test(COSEOnly, function testOnlyCOSEFileTampered() {
1106 let tampered = tampered_app_path("only_cose_file_tampered");
1108 original_app_path("only_cose_signed"),
1110 { "manifest.json": truncateEntry },
1113 certdb.openSignedAppFileAsync(
1114 Ci.nsIX509CertDB.AppXPCShellRoot,
1117 "only_cose_file_tampered",
1118 Cr.NS_ERROR_SIGNED_JAR_MODIFIED_ENTRY,
1124 // This was signed with only COSE first, and then the contents were tampered
1125 // with (making the signature invalid). Then, the file was signed with
1126 // PKCS7/SHA1. We need to ensure that if we're configured to process COSE, this
1127 // verification fails.
1128 add_signature_test(COSEAndPKCS7WithSHA1OrSHA256, function () {
1129 certdb.openSignedAppFileAsync(
1130 Ci.nsIX509CertDB.AppXPCShellRoot,
1131 original_app_path("cose_tampered_good_pkcs7"),
1133 "tampered COSE with good PKCS7 signature should fail " +
1134 "when COSE and PKCS7 is processed",
1135 Cr.NS_ERROR_SIGNED_JAR_MODIFIED_ENTRY,
1141 add_signature_test(COSEOnly, function () {
1142 certdb.openSignedAppFileAsync(
1143 Ci.nsIX509CertDB.AppXPCShellRoot,
1144 original_app_path("cose_tampered_good_pkcs7"),
1146 "tampered COSE with good PKCS7 signature should fail " +
1147 "when only COSE is processed",
1148 Cr.NS_ERROR_SIGNED_JAR_MODIFIED_ENTRY,
1154 // If we're not processing COSE, this should verify successfully.
1155 add_signature_test(PKCS7WithSHA1OrSHA256, function () {
1156 certdb.openSignedAppFileAsync(
1157 Ci.nsIX509CertDB.AppXPCShellRoot,
1158 original_app_path("cose_tampered_good_pkcs7"),
1160 "tampered COSE with good PKCS7 signature should succeed " +
1161 "when COSE is not processed",
1163 [Ci.nsIAppSignatureInfo.PKCS7_WITH_SHA1]
1168 add_test(function () {
1169 certdb.openSignedAppFileAsync(
1170 Ci.nsIX509CertDB.AppXPCShellRoot,
1171 original_app_path("bug_1411458"),
1172 check_open_result("bug 1411458", Cr.NS_ERROR_CMS_VERIFY_NO_CONTENT_INFO, [])
1176 // This has a big manifest file (~2MB). It should verify correctly.
1177 add_test(function () {
1178 certdb.openSignedAppFileAsync(
1179 Ci.nsIX509CertDB.AppXPCShellRoot,
1180 original_app_path("big_manifest"),
1181 check_open_result("add-on with big manifest file", Cr.NS_OK, [
1182 Ci.nsIAppSignatureInfo.PKCS7_WITH_SHA256,
1187 // This has a huge manifest file (~10MB). Manifest files this large are not
1188 // supported (8MB is the limit). It should not verify correctly.
1189 add_test(function () {
1190 certdb.openSignedAppFileAsync(
1191 Ci.nsIX509CertDB.AppXPCShellRoot,
1192 original_app_path("huge_manifest"),
1194 "add-on with huge manifest file",
1195 Cr.NS_ERROR_SIGNED_JAR_ENTRY_INVALID,
1201 // Verification should pass despite a not-yet-valid EE certificate.
1202 // Regression test for bug 1713628
1203 add_test(function () {
1204 certdb.openSignedAppFileAsync(
1205 Ci.nsIX509CertDB.AppXPCShellRoot,
1206 original_app_path("validity_not_yet_valid"),
1207 check_open_result("validity_not_yet_valid", Cr.NS_OK, [
1208 Ci.nsIAppSignatureInfo.PKCS7_WITH_SHA256,
1213 // Verification should pass despite an expired EE certificate.
1214 // Regression test for bug 1267318 and bug 1548973
1215 add_test(function () {
1216 certdb.openSignedAppFileAsync(
1217 Ci.nsIX509CertDB.AppXPCShellRoot,
1218 original_app_path("validity_expired"),
1219 check_open_result("validity_expired", Cr.NS_OK, [
1220 Ci.nsIAppSignatureInfo.PKCS7_WITH_SHA256,
1225 add_signature_test(COSEAndPKCS7WithSHA1OrSHA256, function () {
1226 certdb.openSignedAppFileAsync(
1227 Ci.nsIX509CertDB.AppXPCShellRoot,
1228 original_app_path("alternate-root"),
1229 check_open_result("alternate-root", Cr.NS_OK, [
1230 Ci.nsIAppSignatureInfo.COSE_WITH_SHA256,
1231 Ci.nsIAppSignatureInfo.PKCS7_WITH_SHA256,
1236 // TODO: tampered MF, tampered SF
1237 // TODO: too-large MF, too-large RSA, too-large SF
1238 // TODO: MF and SF that end immediately after the last main header
1240 // TODO: broken headers to exercise the parser