summaryrefslogtreecommitdiffstats
path: root/security/manager/ssl/tests/unit/test_crlite_preexisting.js
blob: c788a11b5495cd88d2a9d55f743a5f8a41a6debd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
// 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
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// Tests that starting a profile with a preexisting CRLite filter and stash
// works correctly.

"use strict";

add_task(async function test_preexisting_crlite_data() {
  Services.prefs.setIntPref(
    "security.pki.crlite_mode",
    CRLiteModeEnforcePrefValue
  );

  let certStorage = Cc["@mozilla.org/security/certstorage;1"].getService(
    Ci.nsICertStorage
  );

  let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
    Ci.nsIX509CertDB
  );
  // These need to be available to be able to find them during path building
  // for certificate verification.
  let issuerCert = constructCertFromFile("test_crlite_filters/issuer.pem");
  ok(issuerCert, "issuer certificate should decode successfully");
  let noSCTCertIssuer = constructCertFromFile(
    "test_crlite_filters/no-sct-issuer.pem"
  );
  ok(
    noSCTCertIssuer,
    "issuer certificate for certificate without SCTs should decode successfully"
  );

  let validCert = constructCertFromFile("test_crlite_filters/valid.pem");
  let revokedCert = constructCertFromFile("test_crlite_filters/revoked.pem");

  // We didn't load a data.bin file, so the filter is not considered fresh and
  // we should get a "no filter" result. We later test that CRLite considers
  // this cert to be revoked. So success here shows that CRLite is not
  // consulted when the filter is stale.
  await checkCertErrorGenericAtTime(
    certdb,
    revokedCert,
    PRErrorCodeSuccess,
    certificateUsageSSLServer,
    new Date("2020-10-20T00:00:00Z").getTime() / 1000,
    false,
    "us-datarecovery.com",
    Ci.nsIX509CertDB.FLAG_LOCAL_ONLY
  );

  // Add an empty stash to ensure the filter is considered to be fresh.
  await new Promise(resolve => {
    certStorage.addCRLiteStash(new Uint8Array([]), (rv, _) => {
      Assert.equal(rv, Cr.NS_OK, "marked filter as fresh");
      resolve();
    });
  });

  // NB: by not specifying Ci.nsIX509CertDB.FLAG_LOCAL_ONLY, this tests that
  // the implementation does not fall back to OCSP fetching, because if it
  // did, the implementation would attempt to connect to a server outside the
  // test infrastructure, which would result in a crash in the test
  // environment, which would be treated as a test failure.
  await checkCertErrorGenericAtTime(
    certdb,
    validCert,
    PRErrorCodeSuccess,
    certificateUsageSSLServer,
    new Date("2020-10-20T00:00:00Z").getTime() / 1000,
    false,
    "vpn.worldofspeed.org",
    0
  );

  // NB: by not specifying Ci.nsIX509CertDB.FLAG_LOCAL_ONLY, this tests that
  // the implementation does not fall back to OCSP fetching, because if it
  // did, the implementation would attempt to connect to a server outside the
  // test infrastructure, which would result in a crash in the test
  // environment, which would be treated as a test failure.
  await checkCertErrorGenericAtTime(
    certdb,
    validCert,
    PRErrorCodeSuccess,
    certificateUsageSSLServer,
    new Date("2020-10-20T00:00:00Z").getTime() / 1000,
    false,
    "vpn.worldofspeed.org",
    0
  );

  await checkCertErrorGenericAtTime(
    certdb,
    revokedCert,
    SEC_ERROR_REVOKED_CERTIFICATE,
    certificateUsageSSLServer,
    new Date("2020-10-20T00:00:00Z").getTime() / 1000,
    false,
    "us-datarecovery.com",
    0
  );

  let revokedInStashCert = constructCertFromFile(
    "test_crlite_filters/revoked-in-stash.pem"
  );
  // The stash may not have loaded yet, so await a task that ensures the stash
  // loading task has completed.
  await new Promise(resolve => {
    certStorage.hasPriorData(
      Ci.nsICertStorage.DATA_TYPE_CRLITE_FILTER_INCREMENTAL,
      (rv, _) => {
        Assert.equal(rv, Cr.NS_OK, "hasPriorData should succeed");
        resolve();
      }
    );
  });
  await checkCertErrorGenericAtTime(
    certdb,
    revokedInStashCert,
    SEC_ERROR_REVOKED_CERTIFICATE,
    certificateUsageSSLServer,
    new Date("2020-10-20T00:00:00Z").getTime() / 1000,
    false,
    "stokedmoto.com",
    0
  );

  let revokedInStash2Cert = constructCertFromFile(
    "test_crlite_filters/revoked-in-stash-2.pem"
  );
  await checkCertErrorGenericAtTime(
    certdb,
    revokedInStash2Cert,
    SEC_ERROR_REVOKED_CERTIFICATE,
    certificateUsageSSLServer,
    new Date("2020-10-20T00:00:00Z").getTime() / 1000,
    false,
    "icsreps.com",
    0
  );

  // This certificate has no embedded SCTs, so it is not guaranteed to be in
  // CT, so CRLite can't be guaranteed to give the correct answer, so it is
  // not consulted, and the implementation falls back to OCSP. Since the real
  // OCSP responder can't be reached, this results in a
  // SEC_ERROR_OCSP_SERVER_ERROR.
  let noSCTCert = constructCertFromFile("test_crlite_filters/no-sct.pem");
  // NB: this will cause an OCSP request to be sent to localhost:80, but
  // since an OCSP responder shouldn't be running on that port, this should
  // fail safely.
  Services.prefs.setCharPref("network.dns.localDomains", "ocsp.digicert.com");
  Services.prefs.setBoolPref("security.OCSP.require", true);
  Services.prefs.setIntPref("security.OCSP.enabled", 1);
  await checkCertErrorGenericAtTime(
    certdb,
    noSCTCert,
    SEC_ERROR_OCSP_SERVER_ERROR,
    certificateUsageSSLServer,
    new Date("2020-10-20T00:00:00Z").getTime() / 1000,
    false,
    "mail233.messagelabs.com",
    0
  );
  Services.prefs.clearUserPref("network.dns.localDomains");
  Services.prefs.clearUserPref("security.OCSP.require");
  Services.prefs.clearUserPref("security.OCSP.enabled");

  let notCoveredCert = constructCertFromFile(
    "test_crlite_filters/notcovered.pem"
  );
  await checkCertErrorGenericAtTime(
    certdb,
    notCoveredCert,
    PRErrorCodeSuccess,
    certificateUsageSSLServer,
    new Date("2022-01-07T00:00:00Z").getTime() / 1000,
    false,
    "peekaboophonics.com",
    Ci.nsIX509CertDB.FLAG_LOCAL_ONLY
  );
});

function run_test() {
  let securityStateDirectory = do_get_profile();
  securityStateDirectory.append("security_state");
  // For simplicity, re-use the filter from test_crlite_filters.js.
  let crilteFile = do_get_file("test_crlite_filters/20201017-0-filter");
  crilteFile.copyTo(securityStateDirectory, "crlite.filter");
  // This stash file and the following cert storage file were obtained by
  // running just the task `test_crlite_filters_and_check_revocation` in
  // test_crlite_filters.js, causing it to hang (by adding something like
  // `add_test(() => {});`), and then copying the files from the temporary
  // profile directory.
  let stashFile = do_get_file("test_crlite_preexisting/crlite.stash");
  stashFile.copyTo(securityStateDirectory, "crlite.stash");
  let coverageFile = do_get_file("test_crlite_preexisting/crlite.coverage");
  coverageFile.copyTo(securityStateDirectory, "crlite.coverage");
  let enrollmentFile = do_get_file("test_crlite_preexisting/crlite.enrollment");
  enrollmentFile.copyTo(securityStateDirectory, "crlite.enrollment");
  let certStorageFile = do_get_file(
    "test_crlite_preexisting/crlite.enrollment"
  );
  certStorageFile.copyTo(securityStateDirectory, "crlite.enrollment");

  run_next_test();
}