no bug - Import translations from android-l10n r=release a=l10n CLOSED TREE
[gecko.git] / security / manager / ssl / tests / unit / test_cert_signatures.js
blob73858afe37a4c411d0d6af8266597a0a0cae766f
1 // -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
2 // This Source Code Form is subject to the terms of the Mozilla Public
3 // License, v. 2.0. If a copy of the MPL was not distributed with this
4 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 "use strict";
8 // Tests that certificates cannot be tampered with without being detected.
9 // Tests a combination of cases: RSA signatures, ECDSA signatures, certificate
10 // chains where the intermediate has been tampered with, chains where the
11 // end-entity has been tampered, tampering of the signature, and tampering in
12 // the rest of the certificate.
14 do_get_profile(); // must be called before getting nsIX509CertDB
15 var certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
16   Ci.nsIX509CertDB
19 // Reads a PEM-encoded certificate, modifies the nth byte (0-indexed), and
20 // returns the base64-encoded bytes of the certificate. Negative indices may be
21 // specified to modify a byte from the end of the certificate.
22 function readAndTamperWithNthByte(certificatePath, n) {
23   let pem = readFile(do_get_file(certificatePath, false));
24   let der = atob(pemToBase64(pem));
25   if (n < 0) {
26     // remember, n is negative at this point
27     n = der.length + n;
28   }
29   let replacement = "\x22";
30   if (der.charCodeAt(n) == replacement) {
31     replacement = "\x23";
32   }
33   der = der.substring(0, n) + replacement + der.substring(n + 1);
34   return btoa(der);
37 // The signature on certificates appears last. This should modify the contents
38 // of the signature such that it no longer validates correctly while still
39 // resulting in a structurally valid certificate.
40 const BYTE_IN_SIGNATURE = -8;
41 function addSignatureTamperedCertificate(certificatePath) {
42   let base64 = readAndTamperWithNthByte(certificatePath, BYTE_IN_SIGNATURE);
43   certdb.addCertFromBase64(base64, ",,");
46 function ensureSignatureVerificationFailure(certificatePath) {
47   let cert = constructCertFromFile(certificatePath);
48   return checkCertErrorGeneric(
49     certdb,
50     cert,
51     SEC_ERROR_BAD_SIGNATURE,
52     certificateUsageSSLServer
53   );
56 function tamperWithSignatureAndEnsureVerificationFailure(certificatePath) {
57   let base64 = readAndTamperWithNthByte(certificatePath, BYTE_IN_SIGNATURE);
58   let cert = certdb.constructX509FromBase64(base64);
59   return checkCertErrorGeneric(
60     certdb,
61     cert,
62     SEC_ERROR_BAD_SIGNATURE,
63     certificateUsageSSLServer
64   );
67 // The beginning of a certificate looks like this (in hex, using DER):
68 // 30 XX XX XX [the XX encode length - there are probably 3 bytes here]
69 //    30 XX XX XX [length again]
70 //       A0 03
71 //          02 01
72 //             02
73 //       02 XX [length again - 1 byte as long as we're using pycert]
74 //          XX XX ... [serial number - 20 bytes as long as we're using pycert]
75 // Since we want to modify the serial number, we need to change something from
76 // byte 15 to byte 34 (0-indexed). If it turns out that the two length sections
77 // we assumed were 3 bytes are shorter (they can't be longer), modifying
78 // something from byte 15 to byte 30 will still get us what we want. Since the
79 // serial number is a DER INTEGER and because it must be positive, it's best to
80 // skip the first two bytes of the serial number so as to not run into any
81 // issues there. Thus byte 17 is a good byte to modify.
82 const BYTE_IN_SERIAL_NUMBER = 17;
83 function addSerialNumberTamperedCertificate(certificatePath) {
84   let base64 = readAndTamperWithNthByte(certificatePath, BYTE_IN_SERIAL_NUMBER);
85   certdb.addCertFromBase64(base64, ",,");
88 function tamperWithSerialNumberAndEnsureVerificationFailure(certificatePath) {
89   let base64 = readAndTamperWithNthByte(certificatePath, BYTE_IN_SERIAL_NUMBER);
90   let cert = certdb.constructX509FromBase64(base64);
91   return checkCertErrorGeneric(
92     certdb,
93     cert,
94     SEC_ERROR_BAD_SIGNATURE,
95     certificateUsageSSLServer
96   );
99 add_task(async function () {
100   addCertFromFile(certdb, "test_cert_signatures/ca-rsa.pem", "CTu,,");
101   addCertFromFile(certdb, "test_cert_signatures/ca-secp384r1.pem", "CTu,,");
103   // Tamper with the signatures on intermediate certificates and ensure that
104   // end-entity certificates issued by those intermediates do not validate
105   // successfully.
106   addSignatureTamperedCertificate("test_cert_signatures/int-rsa.pem");
107   addSignatureTamperedCertificate("test_cert_signatures/int-secp384r1.pem");
108   await ensureSignatureVerificationFailure("test_cert_signatures/ee-rsa.pem");
109   await ensureSignatureVerificationFailure(
110     "test_cert_signatures/ee-secp384r1.pem"
111   );
113   // Tamper with the signatures on end-entity certificates and ensure that they
114   // do not validate successfully.
115   await tamperWithSignatureAndEnsureVerificationFailure(
116     "test_cert_signatures/ee-rsa-direct.pem"
117   );
118   await tamperWithSignatureAndEnsureVerificationFailure(
119     "test_cert_signatures/ee-secp384r1-direct.pem"
120   );
122   // Tamper with the serial numbers of intermediate certificates and ensure
123   // that end-entity certificates issued by those intermediates do not validate
124   // successfully.
125   addSerialNumberTamperedCertificate("test_cert_signatures/int-rsa.pem");
126   addSerialNumberTamperedCertificate("test_cert_signatures/int-secp384r1.pem");
127   await ensureSignatureVerificationFailure("test_cert_signatures/ee-rsa.pem");
128   await ensureSignatureVerificationFailure(
129     "test_cert_signatures/ee-secp384r1.pem"
130   );
132   // Tamper with the serial numbers of end-entity certificates and ensure that
133   // they do not validate successfully.
134   await tamperWithSerialNumberAndEnsureVerificationFailure(
135     "test_cert_signatures/ee-rsa-direct.pem"
136   );
137   await tamperWithSerialNumberAndEnsureVerificationFailure(
138     "test_cert_signatures/ee-secp384r1-direct.pem"
139   );