Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* Any copyright is dedicated to the Public Domain.
2 http://creativecommons.org/publicdomain/zero/1.0/ */
4 function run_test() {
6 /**
7 * Signs a MAR file.
8 *
9 * @param inMAR The MAR file that should be signed
10 * @param outMAR The MAR file to create
11 */
12 function signMAR(inMAR, outMAR, certs, wantSuccess, useShortHandCmdLine) {
13 // Get a process to the signmar binary from the dist/bin directory.
14 let process = Cc["@mozilla.org/process/util;1"].
15 createInstance(Ci.nsIProcess);
16 let signmarBin = do_get_file("signmar" + BIN_SUFFIX);
18 // Make sure the signmar binary exists and is an executable.
19 do_check_true(signmarBin.exists());
20 do_check_true(signmarBin.isExecutable());
22 // Setup the command line arguments to sign the MAR.
23 let NSSConfigDir = do_get_file("data");
24 let args = ["-d", NSSConfigDir.path];
25 if (certs.length == 1 && useShortHandCmdLine) {
26 args.push("-n", certs[0]);
27 } else {
28 for (var i = 0; i < certs.length; i++) {
29 args.push("-n" + i, certs[i]);
30 }
31 }
32 args.push("-s", inMAR.path, outMAR.path);
34 process.init(signmarBin);
35 try {
36 process.run(true, args, args.length);
37 } catch(e) {
38 // On Windows negative return value throws an exception
39 process.exitValue = -1;
40 }
42 // Verify signmar returned 0 for success.
43 if (wantSuccess) {
44 do_check_eq(process.exitValue, 0);
45 } else {
46 do_check_neq(process.exitValue, 0);
47 }
48 }
51 /**
52 * Extract a MAR signature.
53 *
54 * @param inMAR The MAR file who's signature should be extracted
55 * @param sigIndex The index of the signature to extract
56 * @param extractedSig The file where the extracted signature will be stored
57 * @param wantSuccess True if a successful signmar return code is desired
58 */
59 function extractMARSignature(inMAR, sigIndex, extractedSig, wantSuccess) {
60 // Get a process to the signmar binary from the dist/bin directory.
61 let process = Cc["@mozilla.org/process/util;1"].
62 createInstance(Ci.nsIProcess);
63 let signmarBin = do_get_file("signmar" + BIN_SUFFIX);
65 // Make sure the signmar binary exists and is an executable.
66 do_check_true(signmarBin.exists());
67 do_check_true(signmarBin.isExecutable());
69 // Setup the command line arguments to extract the signature in the MAR.
70 let args = ["-n" + sigIndex, "-X", inMAR.path, extractedSig.path];
72 process.init(signmarBin);
73 try {
74 process.run(true, args, args.length);
75 } catch(e) {
76 // On Windows negative return value throws an exception
77 process.exitValue = -1;
78 }
80 // Verify signmar returned 0 for success.
81 if (wantSuccess) {
82 do_check_eq(process.exitValue, 0);
83 } else {
84 do_check_neq(process.exitValue, 0);
85 }
86 }
88 /**
89 * Import a MAR signature.
90 *
91 * @param inMAR The MAR file who's signature should be imported to
92 * @param sigIndex The index of the signature to import to
93 * @param sigFile The file where the base64 signature exists
94 * @param outMAR The same as inMAR but with the specified signature
95 * swapped at the specified index.
96 * @param wantSuccess True if a successful signmar return code is desired
97 */
98 function importMARSignature(inMAR, sigIndex, sigFile, outMAR, wantSuccess) {
99 // Get a process to the signmar binary from the dist/bin directory.
100 let process = Cc["@mozilla.org/process/util;1"].
101 createInstance(Ci.nsIProcess);
102 let signmarBin = do_get_file("signmar" + BIN_SUFFIX);
104 // Make sure the signmar binary exists and is an executable.
105 do_check_true(signmarBin.exists());
106 do_check_true(signmarBin.isExecutable());
108 // Setup the command line arguments to import the signature in the MAR.
109 let args = ["-n" + sigIndex, "-I", inMAR.path, sigFile.path, outMAR.path];
111 process.init(signmarBin);
112 try {
113 process.run(true, args, args.length);
114 } catch(e) {
115 // On Windows negative return value throws an exception
116 process.exitValue = -1;
117 }
119 // Verify signmar returned 0 for success.
120 if (wantSuccess) {
121 do_check_eq(process.exitValue, 0);
122 } else {
123 do_check_neq(process.exitValue, 0);
124 }
125 }
127 /**
128 * Verifies a MAR file.
129 *
130 * @param signedMAR Verifies a MAR file
131 */
132 function verifyMAR(signedMAR, wantSuccess, certs, useShortHandCmdLine) {
133 // Get a process to the signmar binary from the dist/bin directory.
134 let process = Cc["@mozilla.org/process/util;1"].
135 createInstance(Ci.nsIProcess);
136 let signmarBin = do_get_file("signmar" + BIN_SUFFIX);
138 // Make sure the signmar binary exists and is an executable.
139 do_check_true(signmarBin.exists());
140 do_check_true(signmarBin.isExecutable());
142 // Will reference the arguments to use for verification in signmar
143 let args = [];
145 // The XPCShell test wiki indicates this is the preferred way for
146 // Windows and OSX detection.
147 var isWindows = ("@mozilla.org/windows-registry-key;1" in Cc);
148 var isOSX = ("nsILocalFileMac" in Components.interfaces);
150 // Setup the command line arguments to create the MAR.
151 // Windows & Mac vs. Linux/... have different command line for verification
152 // since on Windows we verify with CryptoAPI, on Mac with Security
153 // Transforms or CDSA/CSSM and on all other platforms we verify with NSS. So
154 // on Windows and Mac we use an exported DER file and on other platforms we
155 // use the NSS config db.
156 if (isWindows || isOSX) {
157 if (certs.length == 1 && useShortHandCmdLine) {
158 args.push("-D", "data/" + certs[0] + ".der");
159 } else {
160 for (var i = 0; i < certs.length; i++) {
161 args.push("-D" + i, "data/" + certs[i] + ".der");
162 }
163 }
164 } else {
165 let NSSConfigDir = do_get_file("data");
166 args = ["-d", NSSConfigDir.path];
167 if (certs.length == 1 && useShortHandCmdLine) {
168 args.push("-n", certs[0]);
169 } else {
170 for (var i = 0; i < certs.length; i++) {
171 args.push("-n" + i, certs[i]);
172 }
173 }
174 }
175 args.push("-v", signedMAR.path);
177 process.init(signmarBin);
178 try {
179 // We put this in a try block because nsIProcess doesn't like -1 returns
180 process.run(true, args, args.length);
181 } catch (e) {
182 // On Windows negative return value throws an exception
183 process.exitValue = -1;
184 }
186 // Verify signmar returned 0 for success.
187 if (wantSuccess) {
188 do_check_eq(process.exitValue, 0);
189 } else {
190 do_check_neq(process.exitValue, 0);
191 }
192 }
194 /**
195 * Strips a MAR signature.
196 *
197 * @param signedMAR The MAR file that should be signed
198 * @param outMAR The MAR file to write to with signature stripped
199 */
200 function stripMARSignature(signedMAR, outMAR, wantSuccess) {
201 // Get a process to the signmar binary from the dist/bin directory.
202 let process = Cc["@mozilla.org/process/util;1"].
203 createInstance(Ci.nsIProcess);
204 let signmarBin = do_get_file("signmar" + BIN_SUFFIX);
206 // Make sure the signmar binary exists and is an executable.
207 do_check_true(signmarBin.exists());
208 do_check_true(signmarBin.isExecutable());
210 // Setup the command line arguments to create the MAR.
211 let args = ["-r", signedMAR.path, outMAR.path];
213 process.init(signmarBin);
214 try {
215 process.run(true, args, args.length);
216 } catch (e) {
217 // On Windows negative return value throws an exception
218 process.exitValue = -1;
219 }
221 // Verify signmar returned 0 for success.
222 if (wantSuccess) {
223 do_check_eq(process.exitValue, 0);
224 } else {
225 do_check_neq(process.exitValue, 0);
226 }
227 }
230 function cleanup() {
231 let outMAR = tempDir.clone();
232 outMAR.append("signed_out.mar");
233 if (outMAR.exists()) {
234 outMAR.remove(false);
235 }
236 outMAR = tempDir.clone();
237 outMAR.append("multiple_signed_out.mar");
238 if (outMAR.exists()) {
239 outMAR.remove(false);
240 }
241 outMAR = tempDir.clone();
242 outMAR.append("out.mar");
243 if (outMAR.exists()) {
244 outMAR.remove(false);
245 }
247 let outDir = tempDir.clone();
248 outDir.append("out");
249 if (outDir.exists()) {
250 outDir.remove(true);
251 }
252 }
254 const wantFailure = false;
255 const wantSuccess = true;
256 // Define the unit tests to run.
257 let tests = {
258 // Test signing a MAR file with a single signature
259 test_sign_single: function() {
260 let inMAR = do_get_file("data/" + refMARPrefix + "binary_data_mar.mar");
261 let outMAR = tempDir.clone();
262 outMAR.append("signed_out.mar");
263 if (outMAR.exists()) {
264 outMAR.remove(false);
265 }
266 signMAR(inMAR, outMAR, ["mycert"], wantSuccess, true);
267 do_check_true(outMAR.exists());
268 let outMARData = getBinaryFileData(outMAR);
269 let refMAR = do_get_file("data/" + refMARPrefix + "signed_pib_mar.mar");
270 let refMARData = getBinaryFileData(refMAR);
271 compareBinaryData(outMARData, refMARData);
272 },
273 // Test signing a MAR file with multiple signatures
274 test_sign_multiple: function() {
275 let inMAR = do_get_file("data/" + refMARPrefix + "binary_data_mar.mar");
276 let outMAR = tempDir.clone();
277 outMAR.append("multiple_signed_out.mar");
278 if (outMAR.exists()) {
279 outMAR.remove(false);
280 }
281 do_check_false(outMAR.exists());
282 signMAR(inMAR, outMAR, ["mycert", "mycert2", "mycert3"],
283 wantSuccess, true);
284 do_check_true(outMAR.exists());
285 let outMARData = getBinaryFileData(outMAR);
286 let refMAR = do_get_file("data/" + refMARPrefix + "multiple_signed_pib_mar.mar");
287 let refMARData = getBinaryFileData(refMAR);
288 compareBinaryData(outMARData, refMARData);
289 },
290 // Test verifying a signed MAR file
291 test_verify_single: function() {
292 let signedMAR = do_get_file("data/signed_pib_mar.mar");
293 verifyMAR(signedMAR, wantSuccess, ["mycert"], true);
294 verifyMAR(signedMAR, wantSuccess, ["mycert"], false);
295 },
296 // Test verifying a signed MAR file with too many certs fails.
297 // Or if you want to look at it another way, One mycert signature
298 // is missing.
299 test_verify_single_too_many_certs: function() {
300 let signedMAR = do_get_file("data/signed_pib_mar.mar");
301 verifyMAR(signedMAR, wantFailure, ["mycert", "mycert"], true);
302 verifyMAR(signedMAR, wantFailure, ["mycert", "mycert"], false);
303 },
304 // Test verifying a signed MAR file fails when using a wrong cert
305 test_verify_single_wrong_cert: function() {
306 let signedMAR = do_get_file("data/signed_pib_mar.mar");
307 verifyMAR(signedMAR, wantFailure, ["mycert2"], true);
308 verifyMAR(signedMAR, wantFailure, ["mycert2"], false);
309 },
310 // Test verifying a signed MAR file with multiple signatures
311 test_verify_multiple: function() {
312 let signedMAR = do_get_file("data/multiple_signed_pib_mar.mar");
313 verifyMAR(signedMAR, wantSuccess, ["mycert", "mycert2", "mycert3"]);
314 },
315 // Test verifying an unsigned MAR file fails
316 test_verify_unsigned_mar_file_fails: function() {
317 let unsignedMAR = do_get_file("data/binary_data_mar.mar");
318 verifyMAR(unsignedMAR, wantFailure, ["mycert", "mycert2", "mycert3"]);
319 },
320 // Test verifying a signed MAR file with the same signature multiple
321 // times fails. The input MAR has: mycert, mycert2, mycert3.
322 // we're checking to make sure the number of verified signatures
323 // is only 1 and not 3. Each signature should be verified once.
324 test_verify_multiple_same_cert: function() {
325 let signedMAR = do_get_file("data/multiple_signed_pib_mar.mar");
326 verifyMAR(signedMAR, wantFailure, ["mycert", "mycert", "mycert"]);
327 },
328 // Test verifying a signed MAR file with the correct signatures but in
329 // a different order fails
330 test_verify_multiple_wrong_order: function() {
331 let signedMAR = do_get_file("data/multiple_signed_pib_mar.mar");
332 verifyMAR(signedMAR, wantSuccess, ["mycert", "mycert2", "mycert3"]);
333 verifyMAR(signedMAR, wantFailure, ["mycert", "mycert3", "mycert2"]);
334 verifyMAR(signedMAR, wantFailure, ["mycert2", "mycert", "mycert3"]);
335 verifyMAR(signedMAR, wantFailure, ["mycert2", "mycert3", "mycert"]);
336 verifyMAR(signedMAR, wantFailure, ["mycert3", "mycert", "mycert2"]);
337 verifyMAR(signedMAR, wantFailure, ["mycert3", "mycert2", "mycert"]);
338 },
339 // Test verifying a signed MAR file without a PIB
340 test_verify_no_pib: function() {
341 let signedMAR = do_get_file("data/signed_no_pib_mar.mar");
342 verifyMAR(signedMAR, wantSuccess, ["mycert"], true);
343 verifyMAR(signedMAR, wantSuccess, ["mycert"], false);
344 },
345 // Test verifying a signed MAR file with multiple signatures without a PIB
346 test_verify_no_pib_multiple: function() {
347 let signedMAR = do_get_file("data/multiple_signed_no_pib_mar.mar");
348 verifyMAR(signedMAR, wantSuccess, ["mycert", "mycert2", "mycert3"]);
349 },
350 // Test verifying a crafted MAR file where the attacker tried to adjust
351 // the version number manually.
352 test_crafted_mar: function() {
353 let signedBadMAR = do_get_file("data/manipulated_signed_mar.mar");
354 verifyMAR(signedBadMAR, wantFailure, ["mycert"], true);
355 verifyMAR(signedBadMAR, wantFailure, ["mycert"], false);
356 },
357 // Test verifying a file that doesn't exist fails
358 test_bad_path_verify_fails: function() {
359 let noMAR = do_get_file("data/does_not_exist_.mar", true);
360 do_check_false(noMAR.exists());
361 verifyMAR(noMAR, wantFailure, ["mycert"], true);
362 },
363 // Test to make sure a stripped MAR is the same as the original MAR
364 test_strip_signature: function() {
365 let originalMAR = do_get_file("data/" +
366 refMARPrefix +
367 "binary_data_mar.mar");
368 let signedMAR = tempDir.clone();
369 signedMAR.append("signed_out.mar");
370 let outMAR = tempDir.clone();
371 outMAR.append("out.mar", true);
372 stripMARSignature(signedMAR, outMAR, wantSuccess);
374 // Verify that the stripped MAR matches the original data MAR exactly
375 let outMARData = getBinaryFileData(outMAR);
376 let originalMARData = getBinaryFileData(originalMAR);
377 compareBinaryData(outMARData, originalMARData);
378 },
379 // Test to make sure a stripped multi-signature-MAR is the same as the original MAR
380 test_strip_multiple_signatures: function() {
381 let originalMAR = do_get_file("data/" +
382 refMARPrefix +
383 "binary_data_mar.mar");
384 let signedMAR = tempDir.clone();
385 signedMAR.append("multiple_signed_out.mar");
386 let outMAR = tempDir.clone();
387 outMAR.append("out.mar");
388 stripMARSignature(signedMAR, outMAR, wantSuccess);
390 // Verify that the stripped MAR matches the original data MAR exactly
391 let outMARData = getBinaryFileData(outMAR);
392 let originalMARData = getBinaryFileData(originalMAR);
393 compareBinaryData(outMARData, originalMARData);
394 },
395 // Test extracting the first signature in a MAR that has only a single signature
396 test_extract_sig_single: function() {
397 let inMAR = do_get_file("data/signed_pib_mar.mar");
398 let extractedSig = do_get_file("extracted_signature", true);
399 if (extractedSig.exists()) {
400 extractedSig.remove(false);
401 }
402 extractMARSignature(inMAR, 0, extractedSig, wantSuccess);
403 do_check_true(extractedSig.exists());
405 let referenceSig = do_get_file("data/signed_pib_mar.signature.0"); +
406 compareBinaryData(extractedSig, referenceSig);
407 },
408 // Test extracting the all signatures in a multi signature MAR
409 // The input MAR has 3 signatures.
410 test_extract_sig_multi: function() {
411 for (let i = 0; i < 3; i++) {
412 let inMAR = do_get_file("data/multiple_signed_pib_mar.mar");
413 let extractedSig = do_get_file("extracted_signature", true);
414 if (extractedSig.exists()) {
415 extractedSig.remove(false);
416 }
417 extractMARSignature(inMAR, i, extractedSig, wantSuccess);
418 do_check_true(extractedSig.exists());
420 let referenceSig = do_get_file("data/multiple_signed_pib_mar.sig." + i); +
421 compareBinaryData(extractedSig, referenceSig);
422 }
423 },
424 // Test extracting a signature that is out of range fails
425 test_extract_sig_out_of_range: function() {
426 let inMAR = do_get_file("data/signed_pib_mar.mar");
427 let extractedSig = do_get_file("extracted_signature", true);
428 if (extractedSig.exists()) {
429 extractedSig.remove(false);
430 }
431 const outOfBoundsIndex = 5;
432 extractMARSignature(inMAR, outOfBoundsIndex, extractedSig, wantFailure);
433 do_check_false(extractedSig.exists());
434 },
435 // Test signing a file that doesn't exist fails
436 test_bad_path_sign_fails: function() {
437 let inMAR = do_get_file("data/does_not_exist_.mar", true);
438 let outMAR = tempDir.clone();
439 outMAR.append("signed_out.mar");
440 do_check_false(inMAR.exists());
441 signMAR(inMAR, outMAR, ["mycert"], wantFailure, true);
442 do_check_false(outMAR.exists());
443 },
444 // Test verifying only a subset of the signatures fails.
445 // The input MAR has: mycert, mycert2, mycert3.
446 // We're only verifying 2 of the 3 signatures and that should fail.
447 test_verify_multiple_subset: function() {
448 let signedMAR = do_get_file("data/multiple_signed_pib_mar.mar");
449 verifyMAR(signedMAR, wantFailure, ["mycert", "mycert2"]);
450 },
451 // Test importing the first signature in a MAR that has only
452 // a single signature
453 test_import_sig_single: function() {
454 // Make sure the input MAR was signed with mycert only
455 let inMAR = do_get_file("data/signed_pib_mar.mar");
456 verifyMAR(inMAR, wantSuccess, ["mycert"], false);
457 verifyMAR(inMAR, wantFailure, ["mycert2"], false);
458 verifyMAR(inMAR, wantFailure, ["mycert3"], false);
460 // Get the signature file for this MAR signed with the key from mycert2
461 let sigFile = do_get_file("data/signed_pib_mar.signature.mycert2");
462 do_check_true(sigFile.exists());
463 let outMAR = tempDir.clone();
464 outMAR.append("sigchanged_signed_pib_mar.mar");
465 if (outMAR.exists()) {
466 outMAR.remove(false);
467 }
469 //Run the import operation
470 importMARSignature(inMAR, 0, sigFile, outMAR, wantSuccess);
472 // Verify we have a new MAR file and that mycert no longer verifies
473 // and that mycert2 does verify
474 do_check_true(outMAR.exists());
475 verifyMAR(outMAR, wantFailure, ["mycert"], false);
476 verifyMAR(outMAR, wantSuccess, ["mycert2"], false);
477 verifyMAR(outMAR, wantFailure, ["mycert3"], false);
479 // Compare the binary data to something that was signed originally
480 // with the private key from mycert2
481 let refMAR = do_get_file("data/signed_pib_mar_with_mycert2.mar");
482 do_check_true(refMAR.exists());
483 let refMARData = getBinaryFileData(refMAR);
484 let outMARData = getBinaryFileData(outMAR);
485 compareBinaryData(outMARData, refMARData);
486 },
487 // Test importing a signature that doesn't belong to the file
488 // fails to verify.
489 test_import_wrong_sig: function() {
490 // Make sure the input MAR was signed with mycert only
491 let inMAR = do_get_file("data/signed_pib_mar.mar");
492 verifyMAR(inMAR, wantSuccess, ["mycert"], false);
493 verifyMAR(inMAR, wantFailure, ["mycert2"], false);
494 verifyMAR(inMAR, wantFailure, ["mycert3"], false);
496 // Get the signature file for this MAR signed with the key from mycert2
497 let sigFile = do_get_file("data/multiple_signed_pib_mar.sig.0");
498 do_check_true(sigFile.exists());
499 let outMAR = tempDir.clone();
500 outMAR.append("sigchanged_signed_pib_mar.mar");
501 if (outMAR.exists()) {
502 outMAR.remove(false);
503 }
505 //Run the import operation
506 importMARSignature(inMAR, 0, sigFile, outMAR, wantSuccess);
508 // Verify we have a new MAR file and that mycert no longer verifies
509 // and that mycert2 does verify
510 do_check_true(outMAR.exists());
511 verifyMAR(outMAR, wantFailure, ["mycert"], false);
512 verifyMAR(outMAR, wantFailure, ["mycert2"], false);
513 verifyMAR(outMAR, wantFailure, ["mycert3"], false);
514 },
515 // Test importing to the second signature in a MAR that has multiple
516 // signature
517 test_import_sig_multiple: function() {
518 // Make sure the input MAR was signed with mycert only
519 let inMAR = do_get_file("data/multiple_signed_pib_mar.mar");
520 verifyMAR(inMAR, wantSuccess, ["mycert", "mycert2", "mycert3"], false);
521 verifyMAR(inMAR, wantFailure, ["mycert", "mycert", "mycert3"], false);
523 // Get the signature file for this MAR signed with the key from mycert
524 let sigFile = do_get_file("data/multiple_signed_pib_mar.sig.0");
525 do_check_true(sigFile.exists());
526 let outMAR = tempDir.clone();
527 outMAR.append("sigchanged_signed_pib_mar.mar");
528 if (outMAR.exists()) {
529 outMAR.remove(false);
530 }
532 //Run the import operation
533 const secondSigPos = 1;
534 importMARSignature(inMAR, secondSigPos, sigFile, outMAR, wantSuccess);
536 // Verify we have a new MAR file and that mycert no longer verifies
537 // and that mycert2 does verify
538 do_check_true(outMAR.exists());
539 verifyMAR(outMAR, wantSuccess, ["mycert", "mycert", "mycert3"], false);
540 verifyMAR(outMAR, wantFailure, ["mycert", "mycert2", "mycert3"], false);
542 // Compare the binary data to something that was signed originally
543 // with the private keys from mycert, mycert, mycert3
544 let refMAR = do_get_file("data/multiple_signed_pib_mar_2.mar");
545 do_check_true(refMAR.exists());
546 let refMARData = getBinaryFileData(refMAR);
547 let outMARData = getBinaryFileData(outMAR);
548 compareBinaryData(outMARData, refMARData);
549 },
550 // Test stripping a MAR that doesn't exist fails
551 test_bad_path_strip_fails: function() {
552 let noMAR = do_get_file("data/does_not_exist_mar", true);
553 do_check_false(noMAR.exists());
554 let outMAR = tempDir.clone();
555 outMAR.append("out.mar");
556 stripMARSignature(noMAR, outMAR, wantFailure);
557 },
558 // Test extracting from a bad path fails
559 test_extract_bad_path: function() {
560 let noMAR = do_get_file("data/does_not_exist.mar", true);
561 let extractedSig = do_get_file("extracted_signature", true);
562 do_check_false(noMAR.exists());
563 if (extractedSig.exists()) {
564 extractedSig.remove(false);
565 }
566 extractMARSignature(noMAR, 0, extractedSig, wantFailure);
567 do_check_false(extractedSig.exists());
568 },
569 // Between each test make sure the out MAR does not exist.
570 cleanup_per_test: function() {
571 }
572 };
574 cleanup();
576 // Run all the tests
577 do_check_eq(run_tests(tests), Object.keys(tests).length - 1);
579 do_register_cleanup(cleanup);
580 }