no bug - Import translations from android-l10n r=release a=l10n CLOSED TREE
[gecko.git] / security / manager / ssl / tests / unit / test_cert_storage.js
blobe6bd4d944be05f88f1b03acacb76ec4096b9b2b1
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/. */
5 "use strict";
7 // This test checks a number of things:
8 // * it ensures that data loaded from revocations.txt on startup is present
9 // * it ensures that data served from OneCRL are persisted correctly
10 // * it ensures that items in the CertBlocklist are seen as revoked by the
11 //   cert verifier
12 // * it does a sanity check to ensure other cert verifier behavior is
13 //   unmodified
15 const { RemoteSecuritySettings } = ChromeUtils.importESModule(
16   "resource://gre/modules/psm/RemoteSecuritySettings.sys.mjs"
19 // First, we need to setup appInfo for the blocklist service to work
20 var id = "xpcshell@tests.mozilla.org";
21 var appName = "XPCShell";
22 var version = "1";
23 var platformVersion = "1.9.2";
24 const { updateAppInfo } = ChromeUtils.importESModule(
25   "resource://testing-common/AppInfo.sys.mjs"
27 updateAppInfo({
28   name: appName,
29   ID: id,
30   version,
31   platformVersion: platformVersion ? platformVersion : "1.0",
32   crashReporter: true,
33 });
35 // we need to ensure we setup revocation data before certDB, or we'll start with
36 // no revocation.txt in the profile
37 var gProfile = do_get_profile();
39 var gRevocations = gProfile.clone();
40 gRevocations.append("revocations.txt");
41 if (!gRevocations.exists()) {
42   let existing = do_get_file("test_onecrl/sample_revocations.txt", false);
43   existing.copyTo(gProfile, "revocations.txt");
46 var certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
47   Ci.nsIX509CertDB
50 const certBlocklist = [
51   // test with some bad data ...
52   {
53     issuerName: "Some nonsense in issuer",
54     serialNumber: "AkHVNA==",
55   },
56   {
57     issuerName: "MA0xCzAJBgNVBAMMAmNh",
58     serialNumber: "some nonsense in serial",
59   },
60   {
61     issuerName: "and serial",
62     serialNumber: "some nonsense in both issuer",
63   },
64   // some mixed
65   // In these case, the issuer name and the valid serialNumber correspond
66   // to test-int.pem in bad_certs/
67   {
68     issuerName: "MBIxEDAOBgNVBAMMB1Rlc3QgQ0E=",
69     serialNumber: "oops! more nonsense.",
70   },
71   {
72     issuerName: "MBIxEDAOBgNVBAMMB1Rlc3QgQ0E=",
73     serialNumber: "a0X7/7DlTaedpgrIJg25iBPOkIM=",
74   },
75   // ... and some good
76   // In this case, the issuer name and the valid serialNumber correspond
77   // to other-test-ca.pem in bad_certs/ (for testing root revocation)
78   {
79     issuerName: "MBgxFjAUBgNVBAMMDU90aGVyIHRlc3QgQ0E=",
80     serialNumber: "Rym6o+VN9xgZXT/QLrvN/nv1ZN4=",
81   },
82   // These items correspond to an entry in sample_revocations.txt where:
83   // isser name is the base-64 encoded subject DN for the shared Test
84   // Intermediate and the serialNumbers are base-64 encoded 78 and 31,
85   // respectively.
86   // We need this to ensure that existing items are retained if they're
87   // also in the blocklist
88   {
89     issuerName: "MBwxGjAYBgNVBAMMEVRlc3QgSW50ZXJtZWRpYXRl",
90     serialNumber: "Tg==",
91   },
92   {
93     issuerName: "MBwxGjAYBgNVBAMMEVRlc3QgSW50ZXJtZWRpYXRl",
94     serialNumber: "Hw==",
95   },
96   // This item revokes same-issuer-ee.pem by subject and pubKeyHash.
97   {
98     subject: "MCIxIDAeBgNVBAMMF0Fub3RoZXIgVGVzdCBFbmQtZW50aXR5",
99     pubKeyHash: "VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=",
100   },
103 function verify_cert(file, expectedError) {
104   let ee = constructCertFromFile(file);
105   return checkCertErrorGeneric(
106     certDB,
107     ee,
108     expectedError,
109     certificateUsageSSLServer
110   );
113 // The certificate blocklist currently only applies to TLS server certificates.
114 async function verify_non_tls_usage_succeeds(file) {
115   let ee = constructCertFromFile(file);
116   await checkCertErrorGeneric(
117     certDB,
118     ee,
119     PRErrorCodeSuccess,
120     certificateUsageSSLClient
121   );
122   await checkCertErrorGeneric(
123     certDB,
124     ee,
125     PRErrorCodeSuccess,
126     certificateUsageEmailSigner
127   );
128   await checkCertErrorGeneric(
129     certDB,
130     ee,
131     PRErrorCodeSuccess,
132     certificateUsageEmailRecipient
133   );
136 function load_cert(cert, trust) {
137   let file = "bad_certs/" + cert + ".pem";
138   addCertFromFile(certDB, file, trust);
141 async function update_blocklist() {
142   const { OneCRLBlocklistClient } = RemoteSecuritySettings.init();
144   const fakeEvent = {
145     current: certBlocklist, // with old .txt revocations.
146     deleted: [],
147     created: certBlocklist, // with new cert storage.
148     updated: [],
149   };
150   await OneCRLBlocklistClient.emit("sync", { data: fakeEvent });
151   // Save the last check timestamp, used by cert_storage to assert
152   // if the blocklist is «fresh».
153   Services.prefs.setIntPref(
154     OneCRLBlocklistClient.lastCheckTimePref,
155     Math.floor(Date.now() / 1000)
156   );
159 function run_test() {
160   // import the certificates we need
161   load_cert("test-ca", "CTu,CTu,CTu");
162   load_cert("test-int", ",,");
163   load_cert("other-test-ca", "CTu,CTu,CTu");
165   add_task(async function () {
166     // check some existing items in revocations.txt are blocked.
167     // This test corresponds to:
168     // issuer: MBIxEDAOBgNVBAMMB1Rlc3QgQ0E= (CN=Test CA)
169     // serial: Kg== (42)
170     let file = "test_onecrl/ee-revoked-by-revocations-txt.pem";
171     await verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE);
173     // This test corresponds to:
174     // issuer: MBwxGjAYBgNVBAMMEVRlc3QgSW50ZXJtZWRpYXRl (CN=Test Intermediate)
175     // serial: Tg== (78)
176     file = "test_onecrl/another-ee-revoked-by-revocations-txt.pem";
177     await verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE);
179     // And this test corresponds to:
180     // issuer: MBwxGjAYBgNVBAMMEVRlc3QgSW50ZXJtZWRpYXRl (CN=Test Intermediate)
181     // serial: Hw== (31)
182     // (we test this issuer twice to ensure we can read multiple serials)
183     file = "test_onecrl/another-ee-revoked-by-revocations-txt-serial-2.pem";
184     await verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE);
186     // Test that a certificate revoked by subject and public key hash in
187     // revocations.txt is revoked
188     // subject: MCsxKTAnBgNVBAMMIEVFIFJldm9rZWQgQnkgU3ViamVjdCBhbmQgUHViS2V5
189     // (CN=EE Revoked By Subject and PubKey)
190     // pubkeyhash: VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8= (this is the
191     // shared RSA SPKI)
192     file = "test_onecrl/ee-revoked-by-subject-and-pubkey.pem";
193     await verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE);
195     // Soon we'll load a blocklist which revokes test-int.pem, which issued
196     // test-int-ee.pem.
197     // Check the cert validates before we load the blocklist
198     file = "test_onecrl/test-int-ee.pem";
199     await verify_cert(file, PRErrorCodeSuccess);
201     // The blocklist also revokes other-test-ca.pem, which issued
202     // other-ca-ee.pem. Check the cert validates before we load the blocklist
203     file = "bad_certs/other-issuer-ee.pem";
204     await verify_cert(file, PRErrorCodeSuccess);
206     // The blocklist will revoke same-issuer-ee.pem via subject / pubKeyHash.
207     // Check the cert validates before we load the blocklist
208     file = "test_onecrl/same-issuer-ee.pem";
209     await verify_cert(file, PRErrorCodeSuccess);
210   });
212   // blocklist load is async so we must use add_test from here
213   add_task(update_blocklist);
215   add_task(async function () {
216     // The blocklist will be loaded now. Let's check the data is sane.
217     // In particular, we should still have the revoked issuer / serial pair
218     // that was in revocations.txt but not the blocklist.
219     let file = "test_onecrl/ee-revoked-by-revocations-txt.pem";
220     await verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE);
222     // We should also still have the revoked issuer / serial pairs that were in
223     // revocations.txt and are also in the blocklist.
224     file = "test_onecrl/another-ee-revoked-by-revocations-txt.pem";
225     await verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE);
226     file = "test_onecrl/another-ee-revoked-by-revocations-txt-serial-2.pem";
227     await verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE);
229     // The cert revoked by subject and pubkeyhash should still be revoked.
230     file = "test_onecrl/ee-revoked-by-subject-and-pubkey.pem";
231     await verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE);
233     // Check the blocklisted intermediate now causes a failure
234     file = "test_onecrl/test-int-ee.pem";
235     await verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE);
236     await verify_non_tls_usage_succeeds(file);
238     // Check the ee with the blocklisted root also causes a failure
239     file = "bad_certs/other-issuer-ee.pem";
240     await verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE);
241     await verify_non_tls_usage_succeeds(file);
243     // Check the ee blocked by subject / pubKey causes a failure
244     file = "test_onecrl/same-issuer-ee.pem";
245     await verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE);
246     await verify_non_tls_usage_succeeds(file);
248     // Check a non-blocklisted chain still validates OK
249     file = "bad_certs/default-ee.pem";
250     await verify_cert(file, PRErrorCodeSuccess);
252     // Check a bad cert is still bad (unknown issuer)
253     file = "bad_certs/unknownissuer.pem";
254     await verify_cert(file, SEC_ERROR_UNKNOWN_ISSUER);
255   });
257   run_next_test();